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