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