1# frozen_string_literal: true
2
3require "rack/test"
4require "test_helper"
5require_relative "../web"
6
7Customer::BLATHER = Minitest::Mock.new
8CustomerFwd::BANDWIDTH_VOICE = Minitest::Mock.new
9Web::BANDWIDTH_VOICE = Minitest::Mock.new
10
11class WebTest < Minitest::Test
12 include Rack::Test::Methods
13
14 def app
15 Web.opts[:customer_repo] = CustomerRepo.new(
16 redis: FakeRedis.new(
17 "jmp_customer_jid-customerid" => "customer@example.com",
18 "catapult_jid-+15551234567" => "customer_customerid@component",
19 "jmp_customer_jid-customerid_low" => "customer@example.com",
20 "catapult_jid-+15551234560" => "customer_customerid_low@component",
21 "jmp_customer_jid-customerid_limit" => "customer@example.com",
22 "catapult_jid-+15551234561" => "customer_customerid_limit@component"
23 ),
24 db: FakeDB.new(
25 ["customerid"] => [{
26 "balance" => BigDecimal(10),
27 "plan_name" => "test_usd",
28 "expires_at" => Time.now + 100
29 }],
30 ["customerid_low"] => [{
31 "balance" => BigDecimal("0.01"),
32 "plan_name" => "test_usd",
33 "expires_at" => Time.now + 100
34 }],
35 ["customerid_limit"] => [{
36 "balance" => BigDecimal(10),
37 "plan_name" => "test_usd",
38 "expires_at" => Time.now + 100
39 }]
40 ),
41 sgx_repo: Bwmsgsv2Repo.new(
42 redis: FakeRedis.new(
43 "catapult_fwd-+15551234567" => "xmpp:customer@example.com",
44 "catapult_fwd_timeout-customer_customerid@component" => "30",
45 "catapult_fwd-+15551234560" => "xmpp:customer@example.com",
46 "catapult_fwd_timeout-customer_customerid_low@component" => "30",
47 "catapult_fwd-+15551234561" => "xmpp:customer@example.com",
48 "catapult_fwd_timeout-customer_customerid_limit@component" => "30"
49 ),
50 ibr_repo: FakeIBRRepo.new(
51 "sgx" => {
52 "customer_customerid@component" => IBR.new.tap do |ibr|
53 ibr.phone = "+15551234567"
54 end,
55 "customer_customerid_limit@component" => IBR.new.tap do |ibr|
56 ibr.phone = "+15551234567"
57 end
58 }
59 )
60 )
61 )
62 Web.opts[:call_attempt_repo] = CallAttemptRepo.new(
63 db: FakeDB.new(
64 ["test_usd", "+15557654321", :outbound] => [{ "rate" => 0.01 }],
65 ["test_usd", "+15557654321", :inbound] => [{ "rate" => 0.01 }],
66 ["customerid_limit"] => [{ "a" => -1000 }],
67 ["customerid_low"] => [{ "a" => -1000 }]
68 )
69 )
70 Web.opts[:common_logger] = FakeLog.new
71 Web.instance_variable_set(:@outbound_transfers, { "bcall" => "oocall" })
72 Web.app
73 end
74
75 def test_outbound_forwards
76 post(
77 "/outbound/calls",
78 {
79 from: "customerid",
80 to: "+15557654321",
81 callId: "acall"
82 }.to_json,
83 { "CONTENT_TYPE" => "application/json" }
84 )
85
86 assert last_response.ok?
87 assert_equal(
88 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
89 "<Forward from=\"+15551234567\" to=\"+15557654321\" />" \
90 "</Response>",
91 last_response.body
92 )
93 end
94 em :test_outbound_forwards
95
96 def test_outbound_low_balance
97 post(
98 "/outbound/calls",
99 {
100 from: "customerid_low",
101 to: "+15557654321",
102 callId: "acall"
103 }.to_json,
104 { "CONTENT_TYPE" => "application/json" }
105 )
106
107 assert last_response.ok?
108 assert_equal(
109 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
110 "<SpeakSentence>Your balance of $0.01 is not enough to " \
111 "complete this call.</SpeakSentence></Response>",
112 last_response.body
113 )
114 end
115 em :test_outbound_low_balance
116
117 def test_outbound_unsupported
118 post(
119 "/outbound/calls",
120 {
121 from: "customerid_limit",
122 to: "+95557654321",
123 callId: "acall"
124 }.to_json,
125 { "CONTENT_TYPE" => "application/json" }
126 )
127
128 assert last_response.ok?
129 assert_equal(
130 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
131 "<SpeakSentence>The number you have dialled is not " \
132 "supported on your account.</SpeakSentence></Response>",
133 last_response.body
134 )
135 end
136 em :test_outbound_unsupported
137
138 def test_outbound_atlimit
139 post(
140 "/outbound/calls",
141 {
142 from: "customerid_limit",
143 to: "+15557654321",
144 callId: "acall"
145 }.to_json,
146 { "CONTENT_TYPE" => "application/json" }
147 )
148
149 assert last_response.ok?
150 assert_equal(
151 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
152 "<Gather gatherUrl=\"\/outbound/calls\" maxDigits=\"1\" " \
153 "repeatCount=\"3\"><SpeakSentence>This call will take you over " \
154 "your configured monthly overage limit.</SpeakSentence><SpeakSentence>" \
155 "Change your limit in your account settings or press 1 to accept the " \
156 "charges. You can hang up to cancel.</SpeakSentence></Gather></Response>",
157 last_response.body
158 )
159 end
160 em :test_outbound_atlimit
161
162 def test_outbound_atlimit_digits
163 post(
164 "/outbound/calls",
165 {
166 from: "customerid_limit",
167 to: "+15557654321",
168 callId: "acall",
169 digits: "1"
170 }.to_json,
171 { "CONTENT_TYPE" => "application/json" }
172 )
173
174 assert last_response.ok?
175 assert_equal(
176 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
177 "<Forward from=\"+15551234567\" to=\"+15557654321\" />" \
178 "</Response>",
179 last_response.body
180 )
181 end
182 em :test_outbound_atlimit_digits
183
184 def test_inbound
185 CustomerFwd::BANDWIDTH_VOICE.expect(
186 :create_call,
187 OpenStruct.new(data: OpenStruct.new(call_id: "ocall")),
188 [
189 "test_bw_account",
190 Matching.new { |arg| assert_equal [:body], arg.keys }
191 ]
192 )
193
194 post(
195 "/inbound/calls",
196 {
197 from: "+15557654321",
198 to: "+15551234567",
199 callId: "acall"
200 }.to_json,
201 { "CONTENT_TYPE" => "application/json" }
202 )
203
204 assert last_response.ok?
205 assert_equal(
206 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
207 "<Ring answerCall=\"false\" duration=\"300\" />" \
208 "</Response>",
209 last_response.body
210 )
211 assert_mock CustomerFwd::BANDWIDTH_VOICE
212 end
213 em :test_inbound
214
215 def test_inbound_low
216 post(
217 "/inbound/calls",
218 {
219 from: "+15557654321",
220 to: "+15551234560",
221 callId: "acall"
222 }.to_json,
223 { "CONTENT_TYPE" => "application/json" }
224 )
225
226 assert last_response.ok?
227 assert_equal(
228 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
229 "<Redirect redirectUrl=\"/inbound/calls/acall/voicemail\" />" \
230 "</Response>",
231 last_response.body
232 )
233 assert_mock CustomerFwd::BANDWIDTH_VOICE
234 end
235 em :test_inbound_low
236
237 def test_inbound_leg2
238 post(
239 "/inbound/calls/acall",
240 {
241 from: "+15557654321",
242 to: "+15551234567",
243 callId: "ocall"
244 }.to_json,
245 { "CONTENT_TYPE" => "application/json" }
246 )
247
248 assert last_response.ok?
249 assert_equal(
250 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
251 "<Tag>connected</Tag><Bridge>acall</Bridge>" \
252 "</Response>",
253 last_response.body
254 )
255 end
256 em :test_inbound_leg2
257
258 def test_inbound_limit_leg2
259 post(
260 "/inbound/calls/acall",
261 {
262 from: "+15557654321",
263 to: "+15551234561",
264 callId: "ocall"
265 }.to_json,
266 { "CONTENT_TYPE" => "application/json" }
267 )
268
269 assert last_response.ok?
270 assert_equal(
271 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
272 "<Gather gatherUrl=\"\/inbound/calls/acall\" maxDigits=\"1\" " \
273 "repeatCount=\"3\"><SpeakSentence>This call will take you over " \
274 "your configured monthly overage limit.</SpeakSentence><SpeakSentence>" \
275 "Change your limit in your account settings or press 1 to accept the " \
276 "charges. You can hang up to send the caller to voicemail." \
277 "</SpeakSentence></Gather></Response>",
278 last_response.body
279 )
280 end
281 em :test_inbound_limit_leg2
282
283 def test_inbound_limit_digits_leg2
284 post(
285 "/inbound/calls/acall",
286 {
287 from: "+15557654321",
288 to: "+15551234561",
289 callId: "ocall",
290 digits: "1"
291 }.to_json,
292 { "CONTENT_TYPE" => "application/json" }
293 )
294
295 assert last_response.ok?
296 assert_equal(
297 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
298 "<Tag>connected</Tag><Bridge>acall</Bridge>" \
299 "</Response>",
300 last_response.body
301 )
302 end
303 em :test_inbound_limit_digits_leg2
304
305 def test_inbound_limit_hangup
306 Web::BANDWIDTH_VOICE.expect(
307 :modify_call,
308 nil,
309 [
310 "test_bw_account",
311 "bcall",
312 Matching.new do |arg|
313 assert_equal [:body], arg.keys
314 assert_equal(
315 "http://example.org/inbound/calls/oocall/voicemail",
316 arg[:body].redirect_url
317 )
318 end
319 ]
320 )
321
322 post(
323 "/inbound/calls/bcall/transfer_complete",
324 {
325 from: "+15557654321",
326 to: "+15551234561",
327 callId: "oocall",
328 cause: "hangup"
329 }.to_json,
330 { "CONTENT_TYPE" => "application/json" }
331 )
332
333 assert last_response.ok?
334 assert_mock Web::BANDWIDTH_VOICE
335 end
336 em :test_inbound_limit_hangup
337
338 def test_voicemail
339 Customer::BLATHER.expect(
340 :<<,
341 nil,
342 [Matching.new do |stanza|
343 assert_equal "+15557654321@component", stanza.from.to_s
344 assert_equal "customer@example.com", stanza.to.to_s
345 assert_equal "https://jmp.chat/media", OOB.find_or_create(stanza).url
346 end]
347 )
348
349 post(
350 "/inbound/calls/CALLID/voicemail/audio",
351 {
352 "startTime" => "2021-01-01T00:00:00Z",
353 "endTime" => "2021-01-01T00:00:06Z",
354 "mediaUrl" => "https://voice.bandwidth.com/api/v2/accounts/1/media",
355 "to" => "+15551234567",
356 "from" => "+15557654321"
357 }.to_json,
358 { "CONTENT_TYPE" => "application/json" }
359 )
360
361 assert last_response.ok?
362 assert_mock Customer::BLATHER
363 end
364 em :test_voicemail
365
366 def test_anonymous_voicemail
367 Customer::BLATHER.expect(
368 :<<,
369 nil,
370 [Matching.new do |stanza|
371 assert_equal(
372 "16;phone-context=anonymous.phone-context.soprani.ca@component",
373 stanza.from.to_s
374 )
375 assert_equal "customer@example.com", stanza.to.to_s
376 assert_equal "https://jmp.chat/media", OOB.find_or_create(stanza).url
377 end]
378 )
379
380 post(
381 "/inbound/calls/CALLID/voicemail/audio",
382 {
383 "startTime" => "2021-01-01T00:00:00Z",
384 "endTime" => "2021-01-01T00:00:06Z",
385 "mediaUrl" => "https://voice.bandwidth.com/api/v2/accounts/1/media",
386 "to" => "+15551234567",
387 "from" => "Anonymous"
388 }.to_json,
389 { "CONTENT_TYPE" => "application/json" }
390 )
391
392 assert last_response.ok?
393 assert_mock Customer::BLATHER
394 end
395 em :test_anonymous_voicemail
396
397 def test_voicemail_short
398 post(
399 "/inbound/calls/CALLID/voicemail/audio",
400 {
401 "startTime" => "2021-01-01T00:00:00Z",
402 "endTime" => "2021-01-01T00:00:05Z"
403 }.to_json,
404 { "CONTENT_TYPE" => "application/json" }
405 )
406
407 assert last_response.ok?
408 assert_mock Customer::BLATHER
409 end
410 em :test_voicemail_short
411end