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