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