test_web.rb

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