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