test_helper.rb

  1# frozen_string_literal: true
  2
  3require "simplecov"
  4SimpleCov.start do
  5	add_filter "/test/"
  6	enable_coverage :branch
  7	command_name ENV.fetch("COVERAGE_NAME", "tests")
  8end
  9
 10require "minitest/autorun"
 11require "webmock/minitest"
 12
 13MMS_PROXY = "https://proxy.test.example.com/"
 14
 15_saved_argv = ARGV.dup
 16
 17ARGV[0] = "component"
 18ARGV[6] = MMS_PROXY
 19
 20require_relative "../sgx-bwmsgsv2"
 21ARGV.replace(_saved_argv)
 22
 23def SGXbwmsgsv2.write_to_stream(s)
 24	@written ||= []
 25	@written << s
 26end
 27
 28def reset_stanzas!
 29	SGXbwmsgsv2.instance_variable_set(:@written, [])
 30end
 31
 32def reset_redis!
 33	REDIS.reset!
 34	REDIS.set("catapult_jid-", "HERE")
 35	REDIS.set("catapult_jid-+15550000000", "test@example.com")
 36	REDIS.set("catapult_cred-test@example.com", [
 37		'account', 'user', 'password', '+15550000000'
 38	])
 39end
 40
 41def written
 42	SGXbwmsgsv2.instance_variable_get(:@written)
 43end
 44
 45def invoke_webhook(payload, extra_env: {})
 46	with_stubs([
 47		[
 48			SGXbwmsgsv2,
 49			:write,
 50			->(data) { SGXbwmsgsv2.write_to_stream(data) }
 51		 ]
 52	]) do
 53		handler = WebhookHandler.new
 54		env = {
 55			"REQUEST_URI" => "/",
 56			"REQUEST_METHOD" => "POST",
 57			"params" => { "_json" => [payload] }
 58		}.merge(extra_env)
 59		handler.instance_variable_set(:@env, env)
 60		def handler.params
 61			@env["params"]
 62		end
 63		EMPromise.resolve(nil).then {
 64			handler.response(env)
 65		}.sync
 66	end
 67end
 68
 69def xmpp_error_name(error)
 70	error.find_first(
 71		"child::*[name()!='text']",
 72		Blather::StanzaError::STANZA_ERR_NS
 73	).element_name
 74end
 75
 76def xmpp_error_text(error)
 77	error.find_first("ns:text", ns: Blather::StanzaError::STANZA_ERR_NS)&.text
 78end
 79
 80
 81begin
 82	require "pry-byebug"
 83
 84	module Minitest
 85		class Test
 86			alias old_capture_exceptions capture_exceptions
 87			def capture_exceptions
 88				old_capture_exceptions do
 89					yield
 90				rescue Minitest::Skip => e
 91					failures << e
 92				end
 93			end
 94		end
 95	end
 96rescue LoadError, NameError
 97	# Just helpers for dev, no big deal if missing
 98	nil
 99end
100
101
102$VERBOSE = nil
103
104class FakeRedis
105	def initialize(values={})
106		@values = values
107	end
108
109	def reset!(values={})
110		@values = values
111	end
112
113	def set(key, value, *)
114		@values[key] = value
115		EMPromise.resolve("OK")
116	end
117
118	def setex(key, _expiry, value)
119		set(key, value)
120	end
121
122	def del(*keys)
123		keys.each { |key| @values.delete(key) }
124	end
125
126	def mget(*keys)
127		EMPromise.all(keys.map(&method(:get)))
128	end
129
130	def get(key)
131		EMPromise.resolve(@values[key])
132	end
133
134	def getbit(key, bit)
135		get(key).then { |v| v.to_i.to_s(2)[bit].to_i }
136	end
137
138	def bitfield(key, *ops)
139		get(key).then do |v|
140			bits = v.to_i.to_s(2)
141			ops.each_slice(3).map do |(op, encoding, offset)|
142				raise "unsupported bitfield op" unless op == "GET"
143				raise "unsupported bitfield op" unless encoding == "u1"
144
145				bits[offset].to_i
146			end
147		end
148	end
149
150	def hget(key, field)
151		@values.dig(key, field)
152	end
153
154	def hincrby(key, field, incrby)
155		@values[key] ||= {}
156		@values[key][field] ||= 0
157		@values[key][field] += incrby
158	end
159
160	def sadd(key, member)
161		@values[key] ||= Set.new
162		@values[key] << member
163	end
164
165	def srem(key, member)
166		@values[key].delete(member)
167	end
168
169	def scard(key)
170		@values[key]&.size || 0
171	end
172
173	def expire(_, _); end
174
175	def exists(*keys)
176		EMPromise.resolve(
177			@values.select { |k, _| keys.include? k }.size.to_s
178		)
179	end
180
181	def lindex(key, index)
182		get(key).then { |v| v&.fetch(index) }
183	end
184
185	def lrange(key, sindex, eindex)
186		get(key).then { |v| v ? v[sindex..eindex] : [] }
187	end
188
189	def rpush(key, *values)
190		@values[key] ||= []
191		values.each { |v| @values[key].push(v) }
192	end
193
194	def multi
195	end
196
197	def exec
198	end
199
200	def discard
201	end
202
203	def xadd(stream, id, *args)
204		@values[stream] ||= []
205		entry_id = id == "*" ? "#{Time.now.to_i}-0" : id
206		fields = Hash[*args]
207		@values[stream] << { id: entry_id, fields: fields }
208		EMPromise.resolve(entry_id)
209	end
210
211	def stream_entries(stream)
212		EMPromise.resolve(@values[stream] || [])
213	end
214end
215
216REDIS = FakeRedis.new
217
218module Minitest
219	class Test
220		def with_stubs(stubs, &block)
221			if stubs.empty?
222				block.call
223			else
224				obj, method, value = stubs.first
225				obj.stub(method, value) do
226					with_stubs(stubs[1..], &block)
227				end
228			end
229		end
230
231		def self.em(m)
232			alias_method "raw_#{m}", m
233			define_method(m) do
234				$panic = nil
235				e = nil
236				EM.run do
237					Fiber.new {
238						ARGV[0] = "component"
239						ARGV[6] = MMS_PROXY
240						begin
241							send("raw_#{m}")
242						rescue
243							e = $!
244						ensure
245							EM.stop
246						end
247					}.resume
248				end
249				raise e if e
250			end
251		end
252	end
253end