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 process_stanza(s)
 70	SGXbwmsgsv2.send(:client).receive_data(s)
 71	raise $panic if $panic
 72end
 73
 74def xmpp_error_name(error)
 75	error.find_first(
 76		"child::*[name()!='text']",
 77		Blather::StanzaError::STANZA_ERR_NS
 78	).element_name
 79end
 80
 81def xmpp_error_text(error)
 82	error.find_first("ns:text", ns: Blather::StanzaError::STANZA_ERR_NS)&.text
 83end
 84
 85
 86begin
 87	require "pry-byebug"
 88
 89	module Minitest
 90		class Test
 91			alias old_capture_exceptions capture_exceptions
 92			def capture_exceptions
 93				old_capture_exceptions do
 94					yield
 95				rescue Minitest::Skip => e
 96					failures << e
 97				end
 98			end
 99		end
100	end
101rescue LoadError, NameError
102	# Just helpers for dev, no big deal if missing
103	nil
104end
105
106
107$VERBOSE = nil
108
109class FakeRedis
110	def initialize(values={})
111		@values = values
112	end
113
114	def reset!(values={})
115		@values = values
116	end
117
118	def set(key, value, *)
119		@values[key] = value
120		EMPromise.resolve("OK")
121	end
122
123	def setex(key, _expiry, value)
124		set(key, value)
125	end
126
127	def del(*keys)
128		keys.each { |key| @values.delete(key) }
129	end
130
131	def mget(*keys)
132		EMPromise.all(keys.map(&method(:get)))
133	end
134
135	def get(key)
136		EMPromise.resolve(@values[key])
137	end
138
139	def getbit(key, bit)
140		get(key).then { |v| v.to_i.to_s(2)[bit].to_i }
141	end
142
143	def bitfield(key, *ops)
144		get(key).then do |v|
145			bits = v.to_i.to_s(2)
146			ops.each_slice(3).map do |(op, encoding, offset)|
147				raise "unsupported bitfield op" unless op == "GET"
148				raise "unsupported bitfield op" unless encoding == "u1"
149
150				bits[offset].to_i
151			end
152		end
153	end
154
155	def hget(key, field)
156		@values.dig(key, field)
157	end
158
159	def hincrby(key, field, incrby)
160		@values[key] ||= {}
161		@values[key][field] ||= 0
162		@values[key][field] += incrby
163	end
164
165	def sadd(key, member)
166		@values[key] ||= Set.new
167		@values[key] << member
168	end
169
170	def srem(key, member)
171		@values[key].delete(member)
172	end
173
174	def scard(key)
175		@values[key]&.size || 0
176	end
177
178	def expire(_, _); end
179
180	def exists(*keys)
181		EMPromise.resolve(
182			@values.select { |k, _| keys.include? k }.size.to_s
183		)
184	end
185
186	def lindex(key, index)
187		get(key).then { |v| v&.fetch(index) }
188	end
189
190	def lrange(key, sindex, eindex)
191		get(key).then { |v| v ? v[sindex..eindex] : [] }
192	end
193
194	def rpush(key, *values)
195		@values[key] ||= []
196		values.each { |v| @values[key].push(v) }
197	end
198
199	def multi
200	end
201
202	def exec
203	end
204
205	def discard
206	end
207
208	def xadd(stream, id, *args)
209		@values[stream] ||= []
210		entry_id = id == "*" ? "#{Time.now.to_i}-0" : id
211		fields = Hash[*args]
212		@values[stream] << { id: entry_id, fields: fields }
213		EMPromise.resolve(entry_id)
214	end
215
216	def stream_entries(stream)
217		EMPromise.resolve(@values[stream] || [])
218	end
219end
220
221REDIS = FakeRedis.new
222
223module Minitest
224	class Test
225		def with_stubs(stubs, &block)
226			if stubs.empty?
227				block.call
228			else
229				obj, method, value = stubs.first
230				obj.stub(method, value) do
231					with_stubs(stubs[1..], &block)
232				end
233			end
234		end
235
236		def self.em(m)
237			alias_method "raw_#{m}", m
238			define_method(m) do
239				$panic = nil
240				e = nil
241				EM.run do
242					Fiber.new {
243						ARGV[0] = "component"
244						ARGV[6] = MMS_PROXY
245						begin
246							send("raw_#{m}")
247						rescue
248							e = $!
249						ensure
250							EM.stop
251						end
252					}.resume
253				end
254				raise e if e
255			end
256		end
257	end
258end