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