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