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
14Transaction::DB = Minitest::Mock.new
15
16ReachableRedis = Minitest::Mock.new
17
18class WebTest < Minitest::Test
19 include Rack::Test::Methods
20
21 def setup
22 @cdr_repo = CDRRepo.new(db: FakeDB.new)
23 end
24
25 def app
26 Web.opts[:customer_repo] = CustomerRepo.new(
27 redis: FakeRedis.new(
28 "jmp_customer_jid-customerid" => "customer@example.com",
29 "catapult_jid-+15551234567" => "customer_customerid@component",
30 "jmp_customer_jid-customerid_low" => "customer@example.com",
31 "catapult_jid-+15551234560" => "customer_customerid_low@component",
32 "jmp_customer_jid-customerid_topup" => "customer@example.com",
33 "jmp_customer_auto_top_up_amount-customerid_topup" => "15",
34 "jmp_customer_monthly_overage_limit-customerid_topup" => "99999",
35 "catapult_jid-+15551234562" => "customer_customerid_topup@component",
36 "jmp_customer_jid-customerid_limit" => "customer@example.com",
37 "catapult_jid-+15551234561" => "customer_customerid_limit@component",
38 "jmp_customer_jid-customerid_reach" => "customerid_reach@example.com",
39 "catapult_jid-+15551234563" => "customer_customerid_reach@component",
40 "jmp_customer_jid-customerid2" => "customer2@example.com",
41 "catapult_jid-+15551230000" => "customer_customerid2@component",
42 "jmp_customer_jid-customerid_tombed" => "customer_tombed@example.com",
43 "jmp_customer_jid-bulkcustomer" => "bulk@example.com"
44 ),
45 db: FakeDB.new(
46 ["customerid"] => [{
47 "balance" => BigDecimal(10),
48 "plan_name" => "test_usd",
49 "expires_at" => Time.now + 100
50 }],
51 ["customerid2"] => [{
52 "balance" => BigDecimal(10),
53 "plan_name" => "test_usd",
54 "expires_at" => Time.now + 100
55 }],
56 ["customerid_low"] => [{
57 "balance" => BigDecimal("0.01"),
58 "plan_name" => "test_usd",
59 "expires_at" => Time.now + 100
60 }],
61 ["customerid_topup"] => [{
62 "balance" => BigDecimal("0.01"),
63 "plan_name" => "test_usd",
64 "expires_at" => Time.now + 100
65 }],
66 ["customerid_reach"] => [{
67 "balance" => BigDecimal(10),
68 "plan_name" => "test_usd",
69 "expires_at" => Time.now + 100
70 }],
71 ["customerid_limit"] => [{
72 "balance" => BigDecimal(10),
73 "plan_name" => "test_usd",
74 "expires_at" => Time.now + 100
75 }],
76 ["customerid_tombed"] => [{
77 "balance" => BigDecimal(10),
78 "plan_name" => "test_usd",
79 "expires_at" => Time.now + 100
80 }],
81 ["bulkcustomer"] => [{
82 "balance" => BigDecimal(1000),
83 "plan_name" => "test_usd",
84 "expires_at" => Time.now + 100
85 }]
86 ),
87 sgx_repo: Bwmsgsv2Repo.new(
88 redis: FakeRedis.new(
89 "catapult_fwd-+15551234567" => "xmpp:customer@example.com",
90 "catapult_fwd_timeout-customer_customerid@component" => "30",
91 "catapult_fwd-+15551234560" => "xmpp:customer@example.com",
92 "catapult_fwd_timeout-customer_customerid_low@component" => "30",
93 "catapult_fwd-+15551234561" => "xmpp:customer@example.com",
94 "catapult_fwd_timeout-customer_customerid_limit@component" => "30",
95 "catapult_fwd-+15551234563" => "xmpp:customer@example.com",
96 "catapult_fwd_timeout-customer_customerid_reach@component" => "30",
97 "catapult_fwd-+15551230000" => "xmpp:customer2@example.com",
98 "catapult_fwd_timeout-customer_customerid2@component" => "30"
99 ),
100 ibr_repo: FakeIBRRepo.new(
101 "sgx" => {
102 "customer_customerid@component" =>
103 Blather::Stanza::Iq::IBR.new.tap do |ibr|
104 ibr.phone = "+15551234567"
105 end,
106 "customer_customerid_low@component" =>
107 Blather::Stanza::Iq::IBR.new.tap do |ibr|
108 ibr.phone = "+15551234567"
109 end,
110 "customer_customerid_topup@component" =>
111 Blather::Stanza::Iq::IBR.new.tap do |ibr|
112 ibr.phone = "+15551234567"
113 end,
114 "customer_customerid_reach@component" =>
115 Blather::Stanza::Iq::IBR.new.tap do |ibr|
116 ibr.phone = "+15551234563"
117 end,
118 "customer_customerid_limit@component" =>
119 Blather::Stanza::Iq::IBR.new.tap do |ibr|
120 ibr.phone = "+15551234567"
121 end
122 }
123 )
124 )
125 )
126 Web.opts[:call_attempt_repo] = CallAttemptRepo.new(
127 redis: FakeRedis.new(
128 "jmp_customer_activater-customerid" => "+15551234567",
129 "jmp_customer_activater-customerid2" => "+15551234567",
130 "jmp_customer_activater-customerid_limit" => "+15551234567",
131 "jmp_customer_activater-customerid_low" => "+15551234567",
132 "jmp_customer_activater-customerid_topup" => "+15551234567"
133 ),
134 db: FakeDB.new(
135 ["test_usd", "+15557654321", :outbound] => [{ "rate" => 0.01 }],
136 ["test_usd", "+1911", :outbound] => [{ "rate" => 0.01 }],
137 ["test_usd", "+19116", :outbound] => [{ "rate" => 0.01 }],
138 ["test_usd", "+15557654321", :inbound] => [{ "rate" => 0.01 }],
139 ["test_usd", "+14445556666", :inbound] => [{ "rate" => 0.01 }],
140 ["test_usd", "+18001234567", :outbound] => [{ "rate" => 0.00 }],
141 ["customerid_limit"] => FakeDB::MultiResult.new(
142 [{ "a" => 1000 }],
143 [],
144 [{ "settled_amount" => 15 }]
145 ),
146 ["customerid_low"] => FakeDB::MultiResult.new(
147 [{ "a" => 1000 }],
148 [],
149 [{ "settled_amount" => 15 }]
150 ),
151 ["customerid_topup"] => FakeDB::MultiResult.new(
152 [{ "a" => 1000 }],
153 [],
154 [{ "settled_amount" => 15 }]
155 )
156 )
157 )
158 Web.opts[:cdr_repo] = @cdr_repo
159 Web.opts[:trust_level_repo] = TrustLevelRepo.new(
160 db: FakeDB.new,
161 redis: FakeRedis.new(
162 "jmp_customer_trust_level-customerid_tombed" => "Tomb"
163 )
164 )
165 Web.opts[:common_logger] = FakeLog.new
166 Web.opts[:reachability_repo] = ReachabilityRepo::Voice.new(
167 redis: ReachableRedis,
168 senders: ["+14445556666"]
169 )
170 Web.instance_variable_set(:@outbound_transfers, { "bcall" => "oocall" })
171 Web.app
172 end
173
174 def test_outbound_forwards
175 CustomerPlan::DB.expect(
176 :query_one, {}, [String, "customerid"]
177 )
178
179 post(
180 "/outbound/calls",
181 {
182 from: "ccustomerid",
183 to: "+15557654321",
184 callId: "acall"
185 }.to_json,
186 { "CONTENT_TYPE" => "application/json" }
187 )
188
189 assert last_response.ok?
190 assert_equal(
191 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
192 "<Transfer transferCallerId=\"+15551234567\">" \
193 "<PhoneNumber>+15557654321</PhoneNumber></Transfer></Response>",
194 last_response.body
195 )
196 assert_mock CustomerPlan::DB
197 end
198 em :test_outbound_forwards
199
200 def test_outbound_low_balance
201 CustomerPlan::DB.expect(
202 :query_one, {}, [String, "customerid_low"]
203 )
204
205 ExpiringLock::REDIS.expect(
206 :set,
207 EMPromise.resolve(nil),
208 ["jmp_customer_low_balance-customerid_low", Time, "EX", 604800, "NX"]
209 )
210
211 post(
212 "/outbound/calls",
213 {
214 from: "ccustomerid_low",
215 to: "+15557654321",
216 callId: "acall"
217 }.to_json,
218 { "CONTENT_TYPE" => "application/json" }
219 )
220
221 assert last_response.ok?
222 assert_equal(
223 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
224 "<SpeakSentence>Your balance of $0.01 is not enough to " \
225 "complete this call.</SpeakSentence></Response>",
226 last_response.body
227 )
228 assert_mock ExpiringLock::REDIS
229 assert_mock CustomerPlan::DB
230 end
231 em :test_outbound_low_balance
232
233 def test_outbound_low_balance_top_up
234 CustomerPlan::DB.expect(
235 :query_one, {}, [String, "customerid_topup"]
236 )
237
238 LowBalance::AutoTopUp::CreditCardSale.expect(
239 :create,
240 EMPromise.resolve(
241 OpenStruct.new(total: 15)
242 ),
243 [Customer], amount: 15
244 )
245
246 ExpiringLock::REDIS.expect(
247 :set,
248 EMPromise.resolve("OK"),
249 ["jmp_customer_low_balance-customerid_topup", Time, "EX", 604800, "NX"]
250 )
251
252 CustomerFinancials::REDIS.expect(
253 :smembers,
254 EMPromise.resolve([]),
255 ["block_credit_cards"]
256 )
257 LowBalance::AutoTopUp::REDIS.expect(
258 :exists,
259 0,
260 ["jmp_auto_top_up_block-abcd"]
261 )
262 LowBalance::AutoTopUp::REDIS.expect(
263 :del,
264 EMPromise.resolve(1),
265 ["jmp_customer_low_balance-customerid_topup"]
266 )
267 braintree_customer = Minitest::Mock.new
268 CustomerFinancials::BRAINTREE.expect(:customer, braintree_customer)
269 payment_methods = OpenStruct.new(payment_methods: [
270 OpenStruct.new(default?: true, unique_number_identifier: "abcd")
271 ])
272 braintree_customer.expect(
273 :find,
274 EMPromise.resolve(payment_methods),
275 ["customerid_topup"]
276 )
277
278 Customer::BLATHER.expect(
279 :<<,
280 nil,
281 [Blather::Stanza]
282 )
283
284 post(
285 "/outbound/calls",
286 {
287 from: "ccustomerid_topup",
288 to: "+15557654321",
289 callId: "acall"
290 }.to_json,
291 { "CONTENT_TYPE" => "application/json" }
292 )
293
294 assert last_response.ok?
295 assert_equal(
296 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
297 "<Transfer transferCallerId=\"+15551234567\">" \
298 "<PhoneNumber>+15557654321</PhoneNumber></Transfer></Response>",
299 last_response.body
300 )
301 assert_mock ExpiringLock::REDIS
302 assert_mock Customer::BLATHER
303 assert_mock LowBalance::AutoTopUp::CreditCardSale
304 assert_mock LowBalance::AutoTopUp::REDIS
305 assert_mock CustomerPlan::DB
306 end
307 em :test_outbound_low_balance_top_up
308
309 def test_outbound_unsupported
310 CustomerPlan::DB.expect(
311 :query_one, {}, [String, "customerid"]
312 )
313
314 post(
315 "/outbound/calls",
316 {
317 from: "ccustomerid",
318 to: "+95557654321",
319 callId: "acall"
320 }.to_json,
321 { "CONTENT_TYPE" => "application/json" }
322 )
323
324 assert last_response.ok?
325 assert_equal(
326 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
327 "<SpeakSentence>The number you have dialled is not " \
328 "supported on your account.</SpeakSentence></Response>",
329 last_response.body
330 )
331 assert_mock CustomerPlan::DB
332 end
333 em :test_outbound_unsupported
334
335 def test_outbound_unsupported_short_numbers_911
336 CustomerPlan::DB.expect(
337 :query_one, {}, [String, "customerid"]
338 )
339
340 post(
341 "/outbound/calls",
342 {
343 from: "ccustomerid",
344 to: "+1911",
345 callId: "acall"
346 }.to_json,
347 { "CONTENT_TYPE" => "application/json" }
348 )
349
350 assert last_response.ok?
351 assert_equal(
352 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
353 "<SpeakSentence>The number you have dialled is not " \
354 "supported on your account.</SpeakSentence></Response>",
355 last_response.body
356 )
357 assert_mock CustomerPlan::DB
358 end
359 em :test_outbound_unsupported_short_numbers_911
360
361 def test_outbound_supported_9116
362 CustomerPlan::DB.expect(
363 :query_one, {}, [String, "customerid"]
364 )
365
366 post(
367 "/outbound/calls",
368 {
369 from: "ccustomerid",
370 to: "+19116",
371 callId: "acall"
372 }.to_json,
373 { "CONTENT_TYPE" => "application/json" }
374 )
375
376 assert last_response.ok?
377 assert_equal(
378 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
379 "<Transfer transferCallerId=\"+15551234567\">" \
380 "<PhoneNumber>+19116</PhoneNumber></Transfer></Response>",
381 last_response.body
382 )
383 assert_mock CustomerPlan::DB
384 end
385 em :test_outbound_supported_9116
386
387 def test_outbound_atlimit
388 CustomerPlan::DB.expect(
389 :query_one, {}, [String, "customerid_limit"]
390 )
391
392 post(
393 "/outbound/calls",
394 {
395 from: "ccustomerid_limit",
396 to: "+15557654321",
397 callId: "acall"
398 }.to_json,
399 { "CONTENT_TYPE" => "application/json" }
400 )
401
402 assert last_response.ok?
403 assert_equal(
404 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
405 "<Gather gatherUrl=\"\/outbound/calls\" maxDigits=\"1\" " \
406 "repeatCount=\"3\"><SpeakSentence>This call will take you over " \
407 "your configured monthly overage limit.</SpeakSentence><SpeakSentence>" \
408 "Change your limit in your account settings or press 1 to accept the " \
409 "charges. You can hang up to cancel.</SpeakSentence></Gather></Response>",
410 last_response.body
411 )
412 assert_mock CustomerPlan::DB
413 end
414 em :test_outbound_atlimit
415
416 def test_outbound_no_customer
417 post(
418 "/outbound/calls",
419 {
420 from: "no_such_customer",
421 to: "+15557654321",
422 callId: "acall"
423 }.to_json,
424 { "CONTENT_TYPE" => "application/json" }
425 )
426
427 assert last_response.ok?
428 assert_equal(
429 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
430 "<SpeakSentence>Your credentials are invalid, please contact support." \
431 "</SpeakSentence></Response>",
432 last_response.body
433 )
434 end
435 em :test_outbound_no_customer
436
437 def test_outbound_atlimit_digits
438 CustomerPlan::DB.expect(
439 :query_one, {}, [String, "customerid_limit"]
440 )
441
442 post(
443 "/outbound/calls",
444 {
445 from: "ccustomerid_limit",
446 to: "+15557654321",
447 callId: "acall",
448 digits: "1"
449 }.to_json,
450 { "CONTENT_TYPE" => "application/json" }
451 )
452
453 assert last_response.ok?
454 assert_equal(
455 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
456 "<Transfer transferCallerId=\"+15551234567\">" \
457 "<PhoneNumber>+15557654321</PhoneNumber></Transfer></Response>",
458 last_response.body
459 )
460 assert_mock CustomerPlan::DB
461 end
462 em :test_outbound_atlimit_digits
463
464 def test_outbound_toll_free
465 CustomerPlan::DB.expect(
466 :query_one, {}, [String, "customerid"]
467 )
468
469 post(
470 "/outbound/calls",
471 {
472 from: "ccustomerid",
473 to: "+18001234567",
474 callId: "acall"
475 }.to_json,
476 { "CONTENT_TYPE" => "application/json" }
477 )
478
479 assert last_response.ok?
480 assert_equal(
481 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
482 "<Transfer transferCallerId=\"+15551234567\">" \
483 "<PhoneNumber>+18001234567</PhoneNumber></Transfer></Response>",
484 last_response.body
485 )
486 assert_mock CustomerPlan::DB
487 end
488 em :test_outbound_toll_free
489
490 def test_outbound_disconnect
491 CustomerPlan::DB.expect(
492 :query_one, {}, [String, "customerid"]
493 )
494
495 post(
496 "/outbound/calls/status",
497 {
498 eventType: "disconnect",
499 from: "ccustomerid",
500 to: "+15557654321",
501 callId: "acall",
502 startTime: Time.now.to_s,
503 endTime: Time.now.to_s,
504 cause: "hangup"
505 }.to_json,
506 { "CONTENT_TYPE" => "application/json" }
507 )
508
509 assert last_response.ok?
510 assert_equal("OK", last_response.body)
511 assert_mock CustomerPlan::DB
512 end
513 em :test_outbound_disconnect
514
515 def test_outbound_disconnect_tombed
516 CustomerPlan::DB.expect(
517 :query_one, {}, [String, "customerid_tombed"]
518 )
519
520 @cdr_repo.stub(:put, ->(*) { raise "put called" }) do
521 post(
522 "/outbound/calls/status",
523 {
524 eventType: "disconnect",
525 from: "ccustomerid_tombed",
526 to: "+15557654321",
527 callId: "acall",
528 startTime: Time.now.to_s,
529 endTime: Time.now.to_s,
530 cause: "hangup"
531 }.to_json,
532 { "CONTENT_TYPE" => "application/json" }
533 )
534 end
535
536 assert last_response.ok?
537 assert_equal("OK", last_response.body)
538 assert_mock CustomerPlan::DB
539 end
540 em :test_outbound_disconnect_tombed
541
542 def test_inbound
543 expected_answer_url =
544 "http://example.org/inbound/calls/acall?customer_id=customerid"
545
546 CustomerPlan::DB.expect(
547 :query_one, {}, [String, "customerid"]
548 )
549 CustomerFwd::BANDWIDTH_VOICE.expect(
550 :create_call,
551 OpenStruct.new(call_id: "ocall")
552 ) do |account, request, *|
553 assert_equal("test_bw_account", account)
554 assert_equal(expected_answer_url, request.answer_url)
555 end
556
557 post(
558 "/inbound/calls",
559 {
560 from: "+15557654321",
561 to: "+15551234567",
562 callId: "acall",
563 applicationId: "app123"
564 }.to_json,
565 { "CONTENT_TYPE" => "application/json" }
566 )
567
568 assert last_response.ok?
569 assert_equal(
570 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
571 "<Ring answerCall=\"false\" duration=\"300\" />" \
572 "</Response>",
573 last_response.body
574 )
575 assert_mock CustomerFwd::BANDWIDTH_VOICE
576 assert_mock CustomerPlan::DB
577 end
578 em :test_inbound
579
580 def test_inbound_from_reachability
581 expected_answer_url =
582 "http://example.org/inbound/calls/acall?customer_id=customerid"
583
584 CustomerPlan::DB.expect(
585 :query_one, {}, [String, "customerid"]
586 )
587 CustomerFwd::BANDWIDTH_VOICE.expect(
588 :create_call,
589 OpenStruct.new(call_id: "ocall")
590 ) do |account, request, *|
591 assert_equal("test_bw_account", account)
592 assert_equal(expected_answer_url, request.answer_url)
593 end
594
595 ReachableRedis.expect(
596 :exists,
597 EMPromise.resolve(0),
598 ["jmp_customer_reachability_voice-customerid"]
599 )
600
601 post(
602 "/inbound/calls",
603 {
604 from: "+14445556666",
605 to: "+15551234567",
606 callId: "acall",
607 applicationId: "app123"
608 }.to_json,
609 { "CONTENT_TYPE" => "application/json" }
610 )
611
612 assert last_response.ok?
613 assert_equal(
614 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
615 "<Ring answerCall=\"false\" duration=\"300\" />" \
616 "</Response>",
617 last_response.body
618 )
619 assert_mock CustomerFwd::BANDWIDTH_VOICE
620 assert_mock ReachableRedis
621 assert_mock CustomerPlan::DB
622 end
623 em :test_inbound_from_reachability
624
625 def test_inbound_no_bwmsgsv2
626 expected_answer_url =
627 "http://example.org/inbound/calls/acall?customer_id=customerid2"
628
629 CustomerPlan::DB.expect(
630 :query_one, {}, [String, "customerid2"]
631 )
632 CustomerFwd::BANDWIDTH_VOICE.expect(
633 :create_call,
634 OpenStruct.new(call_id: "ocall")
635 ) do |account, request, *|
636 assert_equal("test_bw_account", account)
637 assert_equal(expected_answer_url, request.answer_url)
638 end
639
640 post(
641 "/inbound/calls",
642 {
643 from: "+15557654321",
644 to: "+15551230000",
645 callId: "acall",
646 applicationId: "app123"
647 }.to_json,
648 { "CONTENT_TYPE" => "application/json" }
649 )
650
651 assert last_response.ok?
652 assert_equal(
653 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
654 "<Ring answerCall=\"false\" duration=\"300\" />" \
655 "</Response>",
656 last_response.body
657 )
658 assert_mock CustomerFwd::BANDWIDTH_VOICE
659 assert_mock CustomerPlan::DB
660 end
661 em :test_inbound_no_bwmsgsv2
662
663 def test_inbound_low
664 CustomerPlan::DB.expect(
665 :query_one, {}, [String, "customerid_low"]
666 )
667
668 ExpiringLock::REDIS.expect(
669 :set,
670 EMPromise.resolve(nil),
671 ["jmp_customer_low_balance-customerid_low", Time, "EX", 604800, "NX"]
672 )
673
674 post(
675 "/inbound/calls",
676 {
677 from: "+15557654321",
678 to: "+15551234560",
679 callId: "acall"
680 }.to_json,
681 { "CONTENT_TYPE" => "application/json" }
682 )
683
684 assert last_response.ok?
685 assert_equal(
686 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
687 "<Redirect redirectUrl=\"/inbound/calls/acall/voicemail\" />" \
688 "</Response>",
689 last_response.body
690 )
691 assert_mock CustomerFwd::BANDWIDTH_VOICE
692 assert_mock ExpiringLock::REDIS
693 assert_mock CustomerPlan::DB
694 end
695 em :test_inbound_low
696
697 def test_inbound_leg2
698 CustomerPlan::DB.expect(
699 :query_one, {}, [String, "customerid"]
700 )
701
702 post(
703 "/inbound/calls/acall?customer_id=customerid",
704 {
705 from: "+15557654321",
706 to: "sip:boop@example.com",
707 callId: "ocall"
708 }.to_json,
709 { "CONTENT_TYPE" => "application/json" }
710 )
711
712 assert last_response.ok?
713 assert_equal(
714 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
715 "<Tag>connected</Tag><Bridge>acall</Bridge>" \
716 "</Response>",
717 last_response.body
718 )
719 assert_mock CustomerPlan::DB
720 end
721 em :test_inbound_leg2
722
723 def test_inbound_limit_leg2
724 CustomerPlan::DB.expect(
725 :query_one, {}, [String, "customerid_limit"]
726 )
727
728 path = "/inbound/calls/acall?customer_id=customerid_limit"
729
730 post(
731 path,
732 {
733 from: "+15557654321",
734 to: "sip:boop@example.com",
735 callId: "ocall"
736 }.to_json,
737 { "CONTENT_TYPE" => "application/json" }
738 )
739
740 assert last_response.ok?
741 assert_equal(
742 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
743 "<Gather gatherUrl=\"#{path}\" maxDigits=\"1\" " \
744 "repeatCount=\"3\"><SpeakSentence>This call will take you over " \
745 "your configured monthly overage limit.</SpeakSentence><SpeakSentence>" \
746 "Change your limit in your account settings or press 1 to accept the " \
747 "charges. You can hang up to send the caller to voicemail." \
748 "</SpeakSentence></Gather></Response>",
749 last_response.body
750 )
751 assert_mock CustomerPlan::DB
752 end
753 em :test_inbound_limit_leg2
754
755 def test_inbound_limit_digits_leg2
756 CustomerPlan::DB.expect(
757 :query_one, {}, [String, "customerid_limit"]
758 )
759
760 post(
761 "/inbound/calls/acall?customer_id=customerid_limit",
762 {
763 from: "+15557654321",
764 to: "sip:boop@example.com",
765 callId: "ocall",
766 digits: "1"
767 }.to_json,
768 { "CONTENT_TYPE" => "application/json" }
769 )
770
771 assert last_response.ok?
772 assert_equal(
773 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
774 "<Tag>connected</Tag><Bridge>acall</Bridge>" \
775 "</Response>",
776 last_response.body
777 )
778 assert_mock CustomerPlan::DB
779 end
780 em :test_inbound_limit_digits_leg2
781
782 def test_inbound_limit_hangup
783 Web::BANDWIDTH_VOICE.expect(:update_call, nil) do |acc, cid, body, **kw|
784 assert_equal "test_bw_account", acc
785 assert_equal "bcall", cid
786 assert_equal(
787 "http://example.org/inbound/calls/oocall/voicemail",
788 body.redirect_url
789 )
790 assert_equal({}, kw)
791 end
792
793 post(
794 "/inbound/calls/bcall/transfer_complete",
795 {
796 from: "+15557654321",
797 to: "+15551234561",
798 callId: "oocall",
799 cause: "hangup"
800 }.to_json,
801 { "CONTENT_TYPE" => "application/json" }
802 )
803
804 assert last_response.ok?
805 assert_mock Web::BANDWIDTH_VOICE
806 end
807 em :test_inbound_limit_hangup
808
809 def test_voicemail
810 language_id = stub_request(:post, "https://api.rev.ai/languageid/v1/jobs")
811 .with(body: {
812 metadata: {
813 media_url: "https://jmp.chat/media",
814 from_jid: "+15557654321@component",
815 customer_id: "customerid"
816 }.to_json,
817 source_config: {
818 url: "https://jmp.chat/media"
819 },
820 notification_config: {
821 url: "http://example.org/inbound/calls/CALLID/voicemail/language_id"
822 }
823 }.to_json)
824
825 Customer::BLATHER.expect(
826 :<<,
827 nil,
828 [Matching.new do |stanza|
829 assert_equal "+15557654321@component", stanza.from.to_s
830 assert_equal "customer@example.com", stanza.to.to_s
831 assert_equal "https://jmp.chat/media", OOB.find_or_create(stanza).url
832 end]
833 )
834
835 post(
836 "/inbound/calls/CALLID/voicemail/audio",
837 {
838 "startTime" => "2021-01-01T00:00:00Z",
839 "endTime" => "2021-01-01T00:00:06Z",
840 "mediaUrl" => "https://voice.bandwidth.com/api/v2/accounts/1/media",
841 "to" => "+15551234567",
842 "from" => "+15557654321"
843 }.to_json,
844 { "CONTENT_TYPE" => "application/json" }
845 )
846
847 assert last_response.ok?
848 assert_mock Customer::BLATHER
849 assert_requested language_id
850 end
851 em :test_voicemail
852
853 def test_anonymous_voicemail
854 language_id = stub_request(:post, "https://api.rev.ai/languageid/v1/jobs")
855 .with(body: {
856 metadata: {
857 media_url: "https://jmp.chat/media",
858 from_jid:
859 "16;phone-context=anonymous.phone-context.soprani.ca@component",
860 customer_id: "customerid"
861 }.to_json,
862 source_config: {
863 url: "https://jmp.chat/media"
864 },
865 notification_config: {
866 url: "http://example.org/inbound/calls/CALLID/voicemail/language_id"
867 }
868 }.to_json)
869
870 Customer::BLATHER.expect(
871 :<<,
872 nil,
873 [Matching.new do |stanza|
874 assert_equal(
875 "16;phone-context=anonymous.phone-context.soprani.ca@component",
876 stanza.from.to_s
877 )
878 assert_equal "customer@example.com", stanza.to.to_s
879 assert_equal "https://jmp.chat/media", OOB.find_or_create(stanza).url
880 end]
881 )
882
883 post(
884 "/inbound/calls/CALLID/voicemail/audio",
885 {
886 "startTime" => "2021-01-01T00:00:00Z",
887 "endTime" => "2021-01-01T00:00:06Z",
888 "mediaUrl" => "https://voice.bandwidth.com/api/v2/accounts/1/media",
889 "to" => "+15551234567",
890 "from" => "Anonymous"
891 }.to_json,
892 { "CONTENT_TYPE" => "application/json" }
893 )
894
895 assert last_response.ok?
896 assert_mock Customer::BLATHER
897 assert_requested language_id
898 end
899 em :test_anonymous_voicemail
900
901 def test_voicemail_short
902 post(
903 "/inbound/calls/CALLID/voicemail/audio",
904 {
905 "startTime" => "2021-01-01T00:00:00Z",
906 "endTime" => "2021-01-01T00:00:05Z"
907 }.to_json,
908 { "CONTENT_TYPE" => "application/json" }
909 )
910
911 assert last_response.ok?
912 assert_mock Customer::BLATHER
913 end
914 em :test_voicemail_short
915
916 def test_voicemail_no_customer
917 post(
918 "/inbound/calls/CALLID/voicemail",
919 {
920 "startTime" => "2021-01-01T00:00:00Z",
921 "endTime" => "2021-01-01T00:00:06Z",
922 "mediaUrl" => "https://voice.bandwidth.com/api/v2/accounts/1/media",
923 "to" => "+15551200000",
924 "from" => "+15557654321"
925 }.to_json,
926 { "CONTENT_TYPE" => "application/json" }
927 )
928
929 assert last_response.ok?
930 assert_equal(
931 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
932 "<SpeakSentence>The number you have dialled is not in service." \
933 "</SpeakSentence></Response>",
934 last_response.body
935 )
936 end
937 em :test_voicemail_no_customer
938
939 def test_inbound_from_reachability_during_reachability
940 ReachableRedis.expect(
941 :exists,
942 EMPromise.resolve(1),
943 ["jmp_customer_reachability_voice-customerid_reach"]
944 )
945 ReachableRedis.expect(
946 :incr,
947 EMPromise.resolve(1),
948 ["jmp_customer_reachability_voice-customerid_reach"]
949 )
950
951 post(
952 "/inbound/calls",
953 {
954 from: "+14445556666",
955 to: "+15551234563",
956 callId: "acall"
957 }.to_json,
958 { "CONTENT_TYPE" => "application/json" }
959 )
960
961 assert last_response.ok?
962 assert_equal(
963 "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Response>" \
964 "<Hangup />" \
965 "</Response>",
966 last_response.body
967 )
968 assert_mock CustomerFwd::BANDWIDTH_VOICE
969 assert_mock ReachableRedis
970 end
971 em :test_inbound_from_reachability_during_reachability
972
973 def test_bulk_order
974 create_order = stub_request(
975 :post,
976 "https://dashboard.bandwidth.com/v1.0/accounts//orders"
977 ).to_return(status: 201, body: <<~RESPONSE)
978 <OrderResponse>
979 <Order>
980 <id>test_order</id>
981 </Order>
982 </OrderResponse>
983 RESPONSE
984
985 post(
986 "/orders",
987 { quantity: 100 },
988 "HTTP_ACCEPT" => "application/json",
989 "HTTP_AUTHORIZATION" => "Bearer sometoken"
990 )
991
992 assert last_response.ok?
993 assert_equal(
994 { id: "test_order" }.to_json,
995 last_response.body
996 )
997 assert_requested create_order
998 end
999 em :test_bulk_order
1000
1001 def test_bulk_order_low_balance
1002 post(
1003 "/orders",
1004 { quantity: 100 },
1005 "HTTP_ACCEPT" => "application/json",
1006 "HTTP_AUTHORIZATION" => "Bearer lowtoken"
1007 )
1008
1009 assert_equal 402, last_response.status
1010 end
1011 em :test_bulk_order_low_balance
1012
1013 def test_bulk_order_bad_token
1014 post(
1015 "/orders",
1016 { quantity: 100 },
1017 "HTTP_ACCEPT" => "application/json",
1018 "HTTP_AUTHORIZATION" => "Bearer badtoken"
1019 )
1020
1021 assert_equal 401, last_response.status
1022 end
1023 em :test_bulk_order_bad_token
1024
1025 def test_order_get
1026 stub_request(
1027 :get,
1028 "https://dashboard.bandwidth.com/v1.0/accounts//orders/testorder"
1029 ).to_return(status: 200, body: <<~RESPONSE)
1030 <OrderResponse>
1031 <id>testorder</id>
1032 <OrderStatus>complete</OrderStatus>
1033 <CompletedNumbers>
1034 <TelephoneNumber>
1035 <FullNumber>5551234567</FullNumber>
1036 </TelephoneNumber>
1037 </CompletedNumbers>
1038 </OrderResponse>
1039 RESPONSE
1040
1041 Transaction::DB.expect(:transaction, nil) do |&blk|
1042 blk.call
1043 true
1044 end
1045 Transaction::DB.expect(
1046 :exec,
1047 nil,
1048 [String, Matching.new { |params|
1049 assert_equal "bulkcustomer", params[0]
1050 assert_equal "testorder", params[1]
1051 assert_equal(-1.75, params[4])
1052 assert_equal "Bulk order", params[5]
1053 }]
1054 )
1055
1056 get(
1057 "/orders/testorder",
1058 "",
1059 "HTTP_ACCEPT" => "application/json",
1060 "HTTP_AUTHORIZATION" => "Bearer sometoken"
1061 )
1062
1063 assert last_response.ok?
1064 assert_equal(
1065 { id: "testorder", status: "complete", tels: ["+15551234567"] }.to_json,
1066 last_response.body
1067 )
1068 assert_mock Transaction::DB
1069 end
1070 em :test_order_get
1071
1072 def test_order_get_multi
1073 stub_request(
1074 :get,
1075 "https://dashboard.bandwidth.com/v1.0/accounts//orders/testorder"
1076 ).to_return(status: 200, body: <<~RESPONSE)
1077 <OrderResponse>
1078 <id>testorder</id>
1079 <OrderStatus>complete</OrderStatus>
1080 <CompletedNumbers>
1081 <TelephoneNumber>
1082 <FullNumber>5551234567</FullNumber>
1083 </TelephoneNumber>
1084 <TelephoneNumber>
1085 <FullNumber>5551234568</FullNumber>
1086 </TelephoneNumber>
1087 </CompletedNumbers>
1088 </OrderResponse>
1089 RESPONSE
1090
1091 Transaction::DB.expect(:transaction, nil) do |&blk|
1092 blk.call
1093 true
1094 end
1095 Transaction::DB.expect(
1096 :exec,
1097 nil,
1098 [String, Matching.new { |params|
1099 assert_equal "bulkcustomer", params[0]
1100 assert_equal "testorder", params[1]
1101 assert_equal (-1.75 * 2), params[4]
1102 assert_equal "Bulk order", params[5]
1103 }]
1104 )
1105
1106 get(
1107 "/orders/testorder",
1108 "",
1109 "HTTP_ACCEPT" => "application/json",
1110 "HTTP_AUTHORIZATION" => "Bearer sometoken"
1111 )
1112
1113 assert last_response.ok?
1114 assert_equal(
1115 {
1116 id: "testorder",
1117 status: "complete",
1118 tels: ["+15551234567", "+15551234568"]
1119 }.to_json,
1120 last_response.body
1121 )
1122 assert_mock Transaction::DB
1123 end
1124 em :test_order_get_multi
1125
1126 def test_order_get_received
1127 stub_request(
1128 :get,
1129 "https://dashboard.bandwidth.com/v1.0/accounts//orders/testorder"
1130 ).to_return(status: 200, body: <<~RESPONSE)
1131 <OrderResponse>
1132 <id>testorder</id>
1133 <OrderStatus>received</OrderStatus>
1134 </OrderResponse>
1135 RESPONSE
1136
1137 get(
1138 "/orders/testorder",
1139 "",
1140 "HTTP_ACCEPT" => "application/json",
1141 "HTTP_AUTHORIZATION" => "Bearer sometoken"
1142 )
1143
1144 assert last_response.ok?
1145 assert_equal(
1146 { id: "testorder", status: "received" }.to_json,
1147 last_response.body
1148 )
1149 end
1150 em :test_order_get_received
1151
1152 def test_order_get_failed
1153 stub_request(
1154 :get,
1155 "https://dashboard.bandwidth.com/v1.0/accounts//orders/testorder"
1156 ).to_return(status: 200, body: <<~RESPONSE)
1157 <OrderResponse>
1158 <id>testorder</id>
1159 <OrderStatus>failed</OrderStatus>
1160 </OrderResponse>
1161 RESPONSE
1162
1163 get(
1164 "/orders/testorder",
1165 "",
1166 "HTTP_ACCEPT" => "application/json",
1167 "HTTP_AUTHORIZATION" => "Bearer sometoken"
1168 )
1169
1170 assert last_response.ok?
1171 assert_equal(
1172 { id: "testorder", status: "failed" }.to_json,
1173 last_response.body
1174 )
1175 end
1176 em :test_order_get_failed
1177
1178 def test_order_get_bad_token
1179 get(
1180 "/orders/testorder",
1181 "",
1182 "HTTP_ACCEPT" => "application/json",
1183 "HTTP_AUTHORIZATION" => "Bearer badtoken"
1184 )
1185
1186 assert_equal 401, last_response.status
1187 end
1188 em :test_order_get_bad_token
1189
1190 def test_delete_tel
1191 stub_request(
1192 :get,
1193 "https://dashboard.bandwidth.com/v1.0/tns/+15551234567/tndetails"
1194 ).to_return(status: 200, body: <<~RESPONSE)
1195 <Response>
1196 <TelephoneNumberDetails>
1197 <SipPeer><PeerId>bulkpeer</PeerId></SipPeer>
1198 </TelephoneNumberDetails>
1199 </Response>
1200 RESPONSE
1201
1202 req = stub_request(
1203 :post,
1204 "https://dashboard.bandwidth.com/v1.0/accounts//disconnects"
1205 ).to_return(status: 200, body: "")
1206
1207 delete(
1208 "/orders/tels/+15551234567",
1209 "",
1210 "HTTP_ACCEPT" => "application/json",
1211 "HTTP_AUTHORIZATION" => "Bearer sometoken"
1212 )
1213
1214 assert last_response.ok?
1215 assert_requested req
1216 end
1217 em :test_delete_tel
1218
1219 def test_delete_tel_not_yours
1220 stub_request(
1221 :get,
1222 "https://dashboard.bandwidth.com/v1.0/tns/+15551234567/tndetails"
1223 ).to_return(status: 200, body: <<~RESPONSE)
1224 <Response>
1225 <TelephoneNumberDetails>
1226 <SipPeer><PeerId>mainpeer</PeerId></SipPeer>
1227 </TelephoneNumberDetails>
1228 </Response>
1229 RESPONSE
1230
1231 delete(
1232 "/orders/tels/+15551234567",
1233 "",
1234 "HTTP_ACCEPT" => "application/json",
1235 "HTTP_AUTHORIZATION" => "Bearer sometoken"
1236 )
1237
1238 assert_equal 401, last_response.status
1239 end
1240 em :test_delete_tel_not_yours
1241
1242 def test_delete_tel_bad_token
1243 delete(
1244 "/orders/tels/+15551234567",
1245 "",
1246 "HTTP_ACCEPT" => "application/json",
1247 "HTTP_AUTHORIZATION" => "Bearer badtoken"
1248 )
1249
1250 assert_equal 401, last_response.status
1251 end
1252 em :test_delete_tel_bad_token
1253end