1# frozen_string_literal: true
2
3require "rack/test"
4require "test_helper"
5require "bwmsgsv2_repo"
6require "customer_repo"
7require_relative "../web"
8
9ExpiringLock::REDIS = Minitest::Mock.new
10Customer::BLATHER = Minitest::Mock.new
11CustomerFwd::BANDWIDTH_VOICE = Minitest::Mock.new
12Web::BANDWIDTH_VOICE = Minitest::Mock.new
13LowBalance::AutoTopUp::CreditCardSale = Minitest::Mock.new
14
15ReachableRedis = Minitest::Mock.new
16
17class WebTest < Minitest::Test
18 include Rack::Test::Methods
19
20 def setup
21 @cdr_repo = CDRRepo.new(db: FakeDB.new)
22 end
23
24 def app
25 Web.opts[:customer_repo] = CustomerRepo.new(
26 redis: FakeRedis.new(
27 "jmp_customer_jid-customerid" => "customer@example.com",
28 "catapult_jid-+15551234567" => "customer_customerid@component",
29 "jmp_customer_jid-customerid_low" => "customer@example.com",
30 "catapult_jid-+15551234560" => "customer_customerid_low@component",
31 "jmp_customer_jid-customerid_topup" => "customer@example.com",
32 "jmp_customer_auto_top_up_amount-customerid_topup" => "15",
33 "jmp_customer_monthly_overage_limit-customerid_topup" => "99999",
34 "catapult_jid-+15551234562" => "customer_customerid_topup@component",
35 "jmp_customer_jid-customerid_limit" => "customer@example.com",
36 "catapult_jid-+15551234561" => "customer_customerid_limit@component",
37 "jmp_customer_jid-customerid_reach" => "customerid_reach@example.com",
38 "catapult_jid-+15551234563" => "customer_customerid_reach@component",
39 "jmp_customer_jid-customerid2" => "customer2@example.com",
40 "catapult_jid-+15551230000" => "customer_customerid2@component",
41 "jmp_customer_jid-customerid_tombed" => "customer_tombed@example.com"
42 ),
43 db: FakeDB.new(
44 ["customerid"] => [{
45 "balance" => BigDecimal(10),
46 "plan_name" => "test_usd",
47 "expires_at" => Time.now + 100
48 }],
49 ["customerid2"] => [{
50 "balance" => BigDecimal(10),
51 "plan_name" => "test_usd",
52 "expires_at" => Time.now + 100
53 }],
54 ["customerid_low"] => [{
55 "balance" => BigDecimal("0.01"),
56 "plan_name" => "test_usd",
57 "expires_at" => Time.now + 100
58 }],
59 ["customerid_topup"] => [{
60 "balance" => BigDecimal("0.01"),
61 "plan_name" => "test_usd",
62 "expires_at" => Time.now + 100
63 }],
64 ["customerid_reach"] => [{
65 "balance" => BigDecimal(10),
66 "plan_name" => "test_usd",
67 "expires_at" => Time.now + 100
68 }],
69 ["customerid_limit"] => [{
70 "balance" => BigDecimal(10),
71 "plan_name" => "test_usd",
72 "expires_at" => Time.now + 100
73 }],
74 ["customerid_tombed"] => [{
75 "balance" => BigDecimal(10),
76 "plan_name" => "test_usd",
77 "expires_at" => Time.now + 100
78 }]
79 ),
80 sgx_repo: Bwmsgsv2Repo.new(
81 redis: FakeRedis.new(
82 "catapult_fwd-+15551234567" => "xmpp:customer@example.com",
83 "catapult_fwd_timeout-customer_customerid@component" => "30",
84 "catapult_fwd-+15551234560" => "xmpp:customer@example.com",
85 "catapult_fwd_timeout-customer_customerid_low@component" => "30",
86 "catapult_fwd-+15551234561" => "xmpp:customer@example.com",
87 "catapult_fwd_timeout-customer_customerid_limit@component" => "30",
88 "catapult_fwd-+15551234563" => "xmpp:customer@example.com",
89 "catapult_fwd_timeout-customer_customerid_reach@component" => "30",
90 "catapult_fwd-+15551230000" => "xmpp:customer2@example.com",
91 "catapult_fwd_timeout-customer_customerid2@component" => "30"
92 ),
93 ibr_repo: FakeIBRRepo.new(
94 "sgx" => {
95 "customer_customerid@component" =>
96 Blather::Stanza::Iq::IBR.new.tap do |ibr|
97 ibr.phone = "+15551234567"
98 end,
99 "customer_customerid_low@component" =>
100 Blather::Stanza::Iq::IBR.new.tap do |ibr|
101 ibr.phone = "+15551234567"
102 end,
103 "customer_customerid_topup@component" =>
104 Blather::Stanza::Iq::IBR.new.tap do |ibr|
105 ibr.phone = "+15551234567"
106 end,
107 "customer_customerid_reach@component" =>
108 Blather::Stanza::Iq::IBR.new.tap do |ibr|
109 ibr.phone = "+15551234563"
110 end,
111 "customer_customerid_limit@component" =>
112 Blather::Stanza::Iq::IBR.new.tap do |ibr|
113 ibr.phone = "+15551234567"
114 end
115 }
116 )
117 )
118 )
119 Web.opts[:call_attempt_repo] = CallAttemptRepo.new(
120 redis: FakeRedis.new,
121 db: FakeDB.new(
122 ["test_usd", "+15557654321", :outbound] => [{ "rate" => 0.01 }],
123 ["test_usd", "+1911", :outbound] => [{ "rate" => 0.01 }],
124 ["test_usd", "+19116", :outbound] => [{ "rate" => 0.01 }],
125 ["test_usd", "+15557654321", :inbound] => [{ "rate" => 0.01 }],
126 ["test_usd", "+14445556666", :inbound] => [{ "rate" => 0.01 }],
127 ["test_usd", "+18001234567", :outbound] => [{ "rate" => 0.00 }],
128 ["customerid_limit"] => FakeDB::MultiResult.new(
129 [{ "a" => 1000 }],
130 [{ "settled_amount" => 15 }]
131 ),
132 ["customerid_low"] => FakeDB::MultiResult.new(
133 [{ "a" => 1000 }],
134 [{ "settled_amount" => 15 }]
135 ),
136 ["customerid_topup"] => FakeDB::MultiResult.new(
137 [{ "a" => 1000 }],
138 [{ "settled_amount" => 15 }]
139 )
140 )
141 )
142 Web.opts[:cdr_repo] = @cdr_repo
143 Web.opts[:trust_level_repo] = TrustLevelRepo.new(
144 db: FakeDB.new,
145 redis: FakeRedis.new(
146 "jmp_customer_trust_level-customerid_tombed" => "Tomb"
147 )
148 )
149 Web.opts[:common_logger] = FakeLog.new
150 Web.opts[:reachability_repo] = ReachabilityRepo::Voice.new(
151 redis: ReachableRedis,
152 senders: ["+14445556666"]
153 )
154 Web.instance_variable_set(:@outbound_transfers, { "bcall" => "oocall" })
155 Web.app
156 end
157
158 def test_outbound_forwards
159 post(
160 "/outbound/calls",
161 {
162 from: "ccustomerid",
163 to: "+15557654321",
164 callId: "acall"
165 }.to_json,
166 { "CONTENT_TYPE" => "application/json" }
167 )
168
169 assert last_response.ok?
170 assert_equal(
171 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
172 "<Transfer transferCallerId=\"+15551234567\">" \
173 "<PhoneNumber>+15557654321</PhoneNumber></Transfer></Response>",
174 last_response.body
175 )
176 end
177 em :test_outbound_forwards
178
179 def test_outbound_low_balance
180 ExpiringLock::REDIS.expect(
181 :set,
182 EMPromise.resolve(nil),
183 ["jmp_customer_low_balance-customerid_low", Time, "EX", 604800, "NX"]
184 )
185
186 post(
187 "/outbound/calls",
188 {
189 from: "ccustomerid_low",
190 to: "+15557654321",
191 callId: "acall"
192 }.to_json,
193 { "CONTENT_TYPE" => "application/json" }
194 )
195
196 assert last_response.ok?
197 assert_equal(
198 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
199 "<SpeakSentence>Your balance of $0.01 is not enough to " \
200 "complete this call.</SpeakSentence></Response>",
201 last_response.body
202 )
203 assert_mock ExpiringLock::REDIS
204 end
205 em :test_outbound_low_balance
206
207 def test_outbound_low_balance_top_up
208 LowBalance::AutoTopUp::CreditCardSale.expect(
209 :create,
210 EMPromise.resolve(
211 OpenStruct.new(total: 15)
212 ),
213 [Customer], amount: 15
214 )
215
216 ExpiringLock::REDIS.expect(
217 :set,
218 EMPromise.resolve("OK"),
219 ["jmp_customer_low_balance-customerid_topup", Time, "EX", 604800, "NX"]
220 )
221
222 CustomerFinancials::REDIS.expect(
223 :smembers,
224 EMPromise.resolve([]),
225 ["block_credit_cards"]
226 )
227 LowBalance::AutoTopUp::REDIS.expect(
228 :exists,
229 0,
230 ["jmp_auto_top_up_block-abcd"]
231 )
232 braintree_customer = Minitest::Mock.new
233 CustomerFinancials::BRAINTREE.expect(:customer, braintree_customer)
234 payment_methods = OpenStruct.new(payment_methods: [
235 OpenStruct.new(default?: true, unique_number_identifier: "abcd")
236 ])
237 braintree_customer.expect(
238 :find,
239 EMPromise.resolve(payment_methods),
240 ["customerid_topup"]
241 )
242
243 Customer::BLATHER.expect(
244 :<<,
245 nil,
246 [Blather::Stanza]
247 )
248
249 post(
250 "/outbound/calls",
251 {
252 from: "ccustomerid_topup",
253 to: "+15557654321",
254 callId: "acall"
255 }.to_json,
256 { "CONTENT_TYPE" => "application/json" }
257 )
258
259 assert last_response.ok?
260 assert_equal(
261 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
262 "<Transfer transferCallerId=\"+15551234567\">" \
263 "<PhoneNumber>+15557654321</PhoneNumber></Transfer></Response>",
264 last_response.body
265 )
266 assert_mock ExpiringLock::REDIS
267 assert_mock Customer::BLATHER
268 assert_mock LowBalance::AutoTopUp::CreditCardSale
269 end
270 em :test_outbound_low_balance_top_up
271
272 def test_outbound_unsupported
273 post(
274 "/outbound/calls",
275 {
276 from: "ccustomerid",
277 to: "+95557654321",
278 callId: "acall"
279 }.to_json,
280 { "CONTENT_TYPE" => "application/json" }
281 )
282
283 assert last_response.ok?
284 assert_equal(
285 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
286 "<SpeakSentence>The number you have dialled is not " \
287 "supported on your account.</SpeakSentence></Response>",
288 last_response.body
289 )
290 end
291 em :test_outbound_unsupported
292
293 def test_outbound_unsupported_short_numbers_911
294 post(
295 "/outbound/calls",
296 {
297 from: "ccustomerid",
298 to: "+1911",
299 callId: "acall"
300 }.to_json,
301 { "CONTENT_TYPE" => "application/json" }
302 )
303
304 assert last_response.ok?
305 assert_equal(
306 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
307 "<SpeakSentence>The number you have dialled is not " \
308 "supported on your account.</SpeakSentence></Response>",
309 last_response.body
310 )
311 end
312 em :test_outbound_unsupported_short_numbers_911
313
314 def test_outbound_supported_9116
315 post(
316 "/outbound/calls",
317 {
318 from: "ccustomerid",
319 to: "+19116",
320 callId: "acall"
321 }.to_json,
322 { "CONTENT_TYPE" => "application/json" }
323 )
324
325 assert last_response.ok?
326 assert_equal(
327 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
328 "<Transfer transferCallerId=\"+15551234567\">" \
329 "<PhoneNumber>+19116</PhoneNumber></Transfer></Response>",
330 last_response.body
331 )
332 end
333 em :test_outbound_supported_9116
334
335 def test_outbound_atlimit
336 post(
337 "/outbound/calls",
338 {
339 from: "ccustomerid_limit",
340 to: "+15557654321",
341 callId: "acall"
342 }.to_json,
343 { "CONTENT_TYPE" => "application/json" }
344 )
345
346 assert last_response.ok?
347 assert_equal(
348 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
349 "<Gather gatherUrl=\"\/outbound/calls\" maxDigits=\"1\" " \
350 "repeatCount=\"3\"><SpeakSentence>This call will take you over " \
351 "your configured monthly overage limit.</SpeakSentence><SpeakSentence>" \
352 "Change your limit in your account settings or press 1 to accept the " \
353 "charges. You can hang up to cancel.</SpeakSentence></Gather></Response>",
354 last_response.body
355 )
356 end
357 em :test_outbound_atlimit
358
359 def test_outbound_no_customer
360 post(
361 "/outbound/calls",
362 {
363 from: "no_such_customer",
364 to: "+15557654321",
365 callId: "acall"
366 }.to_json,
367 { "CONTENT_TYPE" => "application/json" }
368 )
369
370 assert last_response.ok?
371 assert_equal(
372 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
373 "<SpeakSentence>Your credentials are invalid, please contact support." \
374 "</SpeakSentence></Response>",
375 last_response.body
376 )
377 end
378 em :test_outbound_no_customer
379
380 def test_outbound_atlimit_digits
381 post(
382 "/outbound/calls",
383 {
384 from: "ccustomerid_limit",
385 to: "+15557654321",
386 callId: "acall",
387 digits: "1"
388 }.to_json,
389 { "CONTENT_TYPE" => "application/json" }
390 )
391
392 assert last_response.ok?
393 assert_equal(
394 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
395 "<Transfer transferCallerId=\"+15551234567\">" \
396 "<PhoneNumber>+15557654321</PhoneNumber></Transfer></Response>",
397 last_response.body
398 )
399 end
400 em :test_outbound_atlimit_digits
401
402 def test_outbound_toll_free
403 post(
404 "/outbound/calls",
405 {
406 from: "ccustomerid",
407 to: "+18001234567",
408 callId: "acall"
409 }.to_json,
410 { "CONTENT_TYPE" => "application/json" }
411 )
412
413 assert last_response.ok?
414 assert_equal(
415 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
416 "<Transfer transferCallerId=\"+15551234567\">" \
417 "<PhoneNumber>+18001234567</PhoneNumber></Transfer></Response>",
418 last_response.body
419 )
420 end
421 em :test_outbound_toll_free
422
423 def test_outbound_disconnect
424 post(
425 "/outbound/calls/status",
426 {
427 eventType: "disconnect",
428 from: "ccustomerid",
429 to: "+15557654321",
430 callId: "acall",
431 startTime: Time.now.to_s,
432 endTime: Time.now.to_s,
433 cause: "hangup"
434 }.to_json,
435 { "CONTENT_TYPE" => "application/json" }
436 )
437
438 assert last_response.ok?
439 assert_equal("OK", last_response.body)
440 end
441 em :test_outbound_disconnect
442
443 def test_outbound_disconnect_tombed
444 @cdr_repo.stub(:put, ->(*) { raise "put called" }) do
445 post(
446 "/outbound/calls/status",
447 {
448 eventType: "disconnect",
449 from: "ccustomerid_tombed",
450 to: "+15557654321",
451 callId: "acall",
452 startTime: Time.now.to_s,
453 endTime: Time.now.to_s,
454 cause: "hangup"
455 }.to_json,
456 { "CONTENT_TYPE" => "application/json" }
457 )
458 end
459
460 assert last_response.ok?
461 assert_equal("OK", last_response.body)
462 end
463 em :test_outbound_disconnect_tombed
464
465 def test_inbound
466 CustomerFwd::BANDWIDTH_VOICE.expect(
467 :create_call,
468 OpenStruct.new(data: OpenStruct.new(call_id: "ocall")),
469 ["test_bw_account"],
470 body: Matching.new do |arg|
471 assert_equal(
472 "http://example.org/inbound/calls/acall?customer_id=customerid",
473 arg.answer_url
474 )
475 end
476 )
477
478 post(
479 "/inbound/calls",
480 {
481 from: "+15557654321",
482 to: "+15551234567",
483 callId: "acall"
484 }.to_json,
485 { "CONTENT_TYPE" => "application/json" }
486 )
487
488 assert last_response.ok?
489 assert_equal(
490 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
491 "<Ring answerCall=\"false\" duration=\"300\" />" \
492 "</Response>",
493 last_response.body
494 )
495 assert_mock CustomerFwd::BANDWIDTH_VOICE
496 end
497 em :test_inbound
498
499 def test_inbound_from_reachability
500 CustomerFwd::BANDWIDTH_VOICE.expect(
501 :create_call,
502 OpenStruct.new(data: OpenStruct.new(call_id: "ocall")),
503 ["test_bw_account"],
504 body: Matching.new do |arg|
505 assert_equal(
506 "http://example.org/inbound/calls/acall?customer_id=customerid",
507 arg.answer_url
508 )
509 end
510 )
511
512 ReachableRedis.expect(
513 :exists,
514 EMPromise.resolve(0),
515 ["jmp_customer_reachability_voice-customerid"]
516 )
517
518 post(
519 "/inbound/calls",
520 {
521 from: "+14445556666",
522 to: "+15551234567",
523 callId: "acall"
524 }.to_json,
525 { "CONTENT_TYPE" => "application/json" }
526 )
527
528 assert last_response.ok?
529 assert_equal(
530 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
531 "<Ring answerCall=\"false\" duration=\"300\" />" \
532 "</Response>",
533 last_response.body
534 )
535 assert_mock CustomerFwd::BANDWIDTH_VOICE
536 assert_mock ReachableRedis
537 end
538 em :test_inbound_from_reachability
539
540 def test_inbound_no_bwmsgsv2
541 CustomerFwd::BANDWIDTH_VOICE.expect(
542 :create_call,
543 OpenStruct.new(data: OpenStruct.new(call_id: "ocall")),
544 ["test_bw_account"],
545 body: Matching.new do |arg|
546 assert_equal(
547 "http://example.org/inbound/calls/acall?customer_id=customerid2",
548 arg.answer_url
549 )
550 end
551 )
552
553 post(
554 "/inbound/calls",
555 {
556 from: "+15557654321",
557 to: "+15551230000",
558 callId: "acall"
559 }.to_json,
560 { "CONTENT_TYPE" => "application/json" }
561 )
562
563 assert last_response.ok?
564 assert_equal(
565 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
566 "<Ring answerCall=\"false\" duration=\"300\" />" \
567 "</Response>",
568 last_response.body
569 )
570 assert_mock CustomerFwd::BANDWIDTH_VOICE
571 end
572 em :test_inbound_no_bwmsgsv2
573
574 def test_inbound_low
575 ExpiringLock::REDIS.expect(
576 :set,
577 EMPromise.resolve(nil),
578 ["jmp_customer_low_balance-customerid_low", Time, "EX", 604800, "NX"]
579 )
580
581 post(
582 "/inbound/calls",
583 {
584 from: "+15557654321",
585 to: "+15551234560",
586 callId: "acall"
587 }.to_json,
588 { "CONTENT_TYPE" => "application/json" }
589 )
590
591 assert last_response.ok?
592 assert_equal(
593 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
594 "<Redirect redirectUrl=\"/inbound/calls/acall/voicemail\" />" \
595 "</Response>",
596 last_response.body
597 )
598 assert_mock CustomerFwd::BANDWIDTH_VOICE
599 assert_mock ExpiringLock::REDIS
600 end
601 em :test_inbound_low
602
603 def test_inbound_leg2
604 post(
605 "/inbound/calls/acall?customer_id=customerid",
606 {
607 from: "+15557654321",
608 to: "sip:boop@example.com",
609 callId: "ocall"
610 }.to_json,
611 { "CONTENT_TYPE" => "application/json" }
612 )
613
614 assert last_response.ok?
615 assert_equal(
616 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
617 "<Tag>connected</Tag><Bridge>acall</Bridge>" \
618 "</Response>",
619 last_response.body
620 )
621 end
622 em :test_inbound_leg2
623
624 def test_inbound_limit_leg2
625 path = "/inbound/calls/acall?customer_id=customerid_limit"
626
627 post(
628 path,
629 {
630 from: "+15557654321",
631 to: "sip:boop@example.com",
632 callId: "ocall"
633 }.to_json,
634 { "CONTENT_TYPE" => "application/json" }
635 )
636
637 assert last_response.ok?
638 assert_equal(
639 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
640 "<Gather gatherUrl=\"#{path}\" maxDigits=\"1\" " \
641 "repeatCount=\"3\"><SpeakSentence>This call will take you over " \
642 "your configured monthly overage limit.</SpeakSentence><SpeakSentence>" \
643 "Change your limit in your account settings or press 1 to accept the " \
644 "charges. You can hang up to send the caller to voicemail." \
645 "</SpeakSentence></Gather></Response>",
646 last_response.body
647 )
648 end
649 em :test_inbound_limit_leg2
650
651 def test_inbound_limit_digits_leg2
652 post(
653 "/inbound/calls/acall?customer_id=customerid_limit",
654 {
655 from: "+15557654321",
656 to: "sip:boop@example.com",
657 callId: "ocall",
658 digits: "1"
659 }.to_json,
660 { "CONTENT_TYPE" => "application/json" }
661 )
662
663 assert last_response.ok?
664 assert_equal(
665 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
666 "<Tag>connected</Tag><Bridge>acall</Bridge>" \
667 "</Response>",
668 last_response.body
669 )
670 end
671 em :test_inbound_limit_digits_leg2
672
673 def test_inbound_limit_hangup
674 Web::BANDWIDTH_VOICE.expect(
675 :modify_call,
676 nil,
677 [
678 "test_bw_account",
679 "bcall"
680 ],
681 body: Matching.new do |arg|
682 assert_equal(
683 "http://example.org/inbound/calls/oocall/voicemail",
684 arg.redirect_url
685 )
686 end
687 )
688
689 post(
690 "/inbound/calls/bcall/transfer_complete",
691 {
692 from: "+15557654321",
693 to: "+15551234561",
694 callId: "oocall",
695 cause: "hangup"
696 }.to_json,
697 { "CONTENT_TYPE" => "application/json" }
698 )
699
700 assert last_response.ok?
701 assert_mock Web::BANDWIDTH_VOICE
702 end
703 em :test_inbound_limit_hangup
704
705 def test_voicemail
706 language_id = stub_request(:post, "https://api.rev.ai/languageid/v1/jobs")
707 .with(body: {
708 metadata: {
709 media_url: "https://jmp.chat/media",
710 from_jid: "+15557654321@component",
711 customer_id: "customerid"
712 }.to_json,
713 source_config: {
714 url: "https://jmp.chat/media"
715 },
716 notification_config: {
717 url: "http://example.org/inbound/calls/CALLID/voicemail/language_id"
718 }
719 }.to_json)
720
721 Customer::BLATHER.expect(
722 :<<,
723 nil,
724 [Matching.new do |stanza|
725 assert_equal "+15557654321@component", stanza.from.to_s
726 assert_equal "customer@example.com", stanza.to.to_s
727 assert_equal "https://jmp.chat/media", OOB.find_or_create(stanza).url
728 end]
729 )
730
731 post(
732 "/inbound/calls/CALLID/voicemail/audio",
733 {
734 "startTime" => "2021-01-01T00:00:00Z",
735 "endTime" => "2021-01-01T00:00:06Z",
736 "mediaUrl" => "https://voice.bandwidth.com/api/v2/accounts/1/media",
737 "to" => "+15551234567",
738 "from" => "+15557654321"
739 }.to_json,
740 { "CONTENT_TYPE" => "application/json" }
741 )
742
743 assert last_response.ok?
744 assert_mock Customer::BLATHER
745 assert_requested language_id
746 end
747 em :test_voicemail
748
749 def test_anonymous_voicemail
750 language_id = stub_request(:post, "https://api.rev.ai/languageid/v1/jobs")
751 .with(body: {
752 metadata: {
753 media_url: "https://jmp.chat/media",
754 from_jid:
755 "16;phone-context=anonymous.phone-context.soprani.ca@component",
756 customer_id: "customerid"
757 }.to_json,
758 source_config: {
759 url: "https://jmp.chat/media"
760 },
761 notification_config: {
762 url: "http://example.org/inbound/calls/CALLID/voicemail/language_id"
763 }
764 }.to_json)
765
766 Customer::BLATHER.expect(
767 :<<,
768 nil,
769 [Matching.new do |stanza|
770 assert_equal(
771 "16;phone-context=anonymous.phone-context.soprani.ca@component",
772 stanza.from.to_s
773 )
774 assert_equal "customer@example.com", stanza.to.to_s
775 assert_equal "https://jmp.chat/media", OOB.find_or_create(stanza).url
776 end]
777 )
778
779 post(
780 "/inbound/calls/CALLID/voicemail/audio",
781 {
782 "startTime" => "2021-01-01T00:00:00Z",
783 "endTime" => "2021-01-01T00:00:06Z",
784 "mediaUrl" => "https://voice.bandwidth.com/api/v2/accounts/1/media",
785 "to" => "+15551234567",
786 "from" => "Anonymous"
787 }.to_json,
788 { "CONTENT_TYPE" => "application/json" }
789 )
790
791 assert last_response.ok?
792 assert_mock Customer::BLATHER
793 assert_requested language_id
794 end
795 em :test_anonymous_voicemail
796
797 def test_voicemail_short
798 post(
799 "/inbound/calls/CALLID/voicemail/audio",
800 {
801 "startTime" => "2021-01-01T00:00:00Z",
802 "endTime" => "2021-01-01T00:00:05Z"
803 }.to_json,
804 { "CONTENT_TYPE" => "application/json" }
805 )
806
807 assert last_response.ok?
808 assert_mock Customer::BLATHER
809 end
810 em :test_voicemail_short
811
812 def test_voicemail_no_customer
813 post(
814 "/inbound/calls/CALLID/voicemail",
815 {
816 "startTime" => "2021-01-01T00:00:00Z",
817 "endTime" => "2021-01-01T00:00:06Z",
818 "mediaUrl" => "https://voice.bandwidth.com/api/v2/accounts/1/media",
819 "to" => "+15551200000",
820 "from" => "+15557654321"
821 }.to_json,
822 { "CONTENT_TYPE" => "application/json" }
823 )
824
825 assert last_response.ok?
826 assert_equal(
827 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
828 "<SpeakSentence>The number you have dialled is not in service." \
829 "</SpeakSentence></Response>",
830 last_response.body
831 )
832 end
833 em :test_voicemail_no_customer
834
835 def test_inbound_from_reachability_during_reachability
836 ReachableRedis.expect(
837 :exists,
838 EMPromise.resolve(1),
839 ["jmp_customer_reachability_voice-customerid_reach"]
840 )
841 ReachableRedis.expect(
842 :incr,
843 EMPromise.resolve(1),
844 ["jmp_customer_reachability_voice-customerid_reach"]
845 )
846
847 post(
848 "/inbound/calls",
849 {
850 from: "+14445556666",
851 to: "+15551234563",
852 callId: "acall"
853 }.to_json,
854 { "CONTENT_TYPE" => "application/json" }
855 )
856
857 assert last_response.ok?
858 assert_equal(
859 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
860 "<Hangup />" \
861 "</Response>",
862 last_response.body
863 )
864 assert_mock CustomerFwd::BANDWIDTH_VOICE
865 assert_mock ReachableRedis
866 end
867 em :test_inbound_from_reachability_during_reachability
868end