test_tel_selections.rb

  1# frozen_string_literal: true
  2
  3require "test_helper"
  4require "tel_selections"
  5
  6class TelSelectionsTest < Minitest::Test
  7	def setup
  8		@manager = TelSelections.new(
  9			redis: FakeRedis.new,
 10			db: FakeDB.new,
 11			memcache: FakeMemcache.new
 12		)
 13	end
 14
 15	def test_set_get
 16		cust = OpenStruct.new(jid: "jid@example.com")
 17		assert_kind_of TelSelections::ChooseTel, @manager[cust].sync
 18		@manager.set(
 19			"jid@example.com",
 20			TelSelections::ChooseTel::Tn.for_pending_value("+15555550000")
 21		).sync
 22		assert_kind_of TelSelections::HaveTel, @manager[cust].sync
 23	end
 24	em :test_set_get
 25
 26	def test_choose_tel_have_tel
 27		jid = "jid@example.com"
 28		@manager.set(
 29			jid,
 30			TelSelections::ChooseTel::Tn.for_pending_value("+15555550000")
 31		).sync
 32		assert_equal(
 33			"+15555550000",
 34			@manager[OpenStruct.new(jid: jid)].then(&:choose_tel_or_data).sync.tel
 35		)
 36	end
 37	em :test_choose_tel_have_tel
 38
 39	class AvailableNumberTest < Minitest::Test
 40		def test_for_no_rsm
 41			form = Blather::Stanza::X.new
 42			form.fields = [{ var: "q", value: "226" }]
 43			iris_query = TelSelections::ChooseTel::AvailableNumber
 44				.for(
 45					form,
 46					redis: FakeRedis.new, db: FakeDB.new, memcache: FakeMemcache.new
 47				).sync.instance_variable_get(:@iris_query)
 48			assert_equal(
 49				{ areaCode: "226", enableTNDetail: true, LCA: false, quantity: 10 },
 50				iris_query
 51			)
 52		end
 53		em :test_for_no_rsm
 54
 55		def test_for_rsm
 56			form = Blather::Stanza::X.new
 57			form.fields = [{ var: "q", value: "226" }]
 58			Nokogiri::XML::Builder.with(form) do
 59				set(xmlns: "http://jabber.org/protocol/rsm") do
 60					max 500
 61				end
 62			end
 63			iris_query = TelSelections::ChooseTel::AvailableNumber
 64				.for(
 65					form,
 66					redis: FakeRedis.new, db: FakeDB.new, memcache: FakeMemcache.new
 67				).sync.instance_variable_get(:@iris_query)
 68			# quantity should be 500 due to max inside tel selections
 69			assert_equal(
 70				{ areaCode: "226", enableTNDetail: true, LCA: false, quantity: 500 },
 71				iris_query
 72			)
 73		end
 74		em :test_for_rsm
 75
 76		def test_for_feelinglucky
 77			form = Blather::Stanza::X.new
 78			form.fields = [
 79				{ var: "q", value: "" },
 80				{
 81					var: "http://jabber.org/protocol/commands#actions",
 82					value: "feelinglucky"
 83				}
 84			]
 85			iris_query = TelSelections::ChooseTel::AvailableNumber
 86				.for(
 87					form,
 88					redis: FakeRedis.new, db: FakeDB.new, memcache: FakeMemcache.new
 89				).sync.instance_variable_get(:@iris_query)
 90			assert_equal(
 91				{ areaCode: "810", enableTNDetail: true, LCA: false, quantity: 10 },
 92				iris_query
 93			)
 94		end
 95		em :test_for_feelinglucky
 96
 97		def test_fallback
 98			stub_request(
 99				:get,
100				"https://dashboard.bandwidth.com/v1.0/accounts//availableNumbers" \
101				"?city=Kitchener-Waterloo&enableTNDetail=true&lCA=false&" \
102				"quantity=10&state=ON"
103			).to_return(status: 200, body: "")
104
105			stub_request(
106				:get,
107				"https://geocoder.ca/?json=1&locate=Kitchener-Waterloo,%20ON"
108			).to_return(status: 200, body: {
109				postal: "N2H", longt: 0, latt: 0
110			}.to_json)
111
112			stub_request(
113				:get,
114				"https://dashboard.bandwidth.com/v1.0/accounts//availableNumbers" \
115				"?areaCode=226&enableTNDetail=true&quantity=10"
116			).to_return(status: 200, body: <<~XML)
117				<SearchResult>
118					<TelephoneNumberList>
119						<TelephoneNumber>
120							<FullNumber>22655512345</FullNumber>
121							<City>Somewhere</City>
122							<State>ON</State>
123						</TelephoneNumber>
124					</TelephoneNumberList>
125				</SearchResult>
126			XML
127
128			db = FakeDB.new(
129				["CA", "POINT(0.0000000000 0.0000000000)", 3] =>
130					[{ "area_code" => "226" }]
131			)
132			form = Blather::Stanza::X.new
133			form.fields = [{ var: "q", value: "Kitchener, ON" }]
134			tns = execute_command do
135				TelSelections::ChooseTel::AvailableNumber
136					.for(
137						form,
138						redis: FakeRedis.new, db: db, memcache: FakeMemcache.new
139					).sync.tns
140			end
141			assert_equal(
142				["(226) 555-12345 (Somewhere, ON)"],
143				tns.map(&:to_s)
144			)
145		end
146		em :test_fallback
147
148		def test_local_inventory
149			stub_request(
150				:get,
151				"https://dashboard.bandwidth.com/v1.0/accounts//availableNumbers" \
152					"?city=Kitchener-Waterloo&enableTNDetail=true&lCA=false&" \
153					"quantity=10&state=ON"
154			).to_return(status: 200, body: "")
155
156			db = FakeDB.new(
157				["ON", "Kitchener-Waterloo"] => [{
158					"tel" => "+122655512345",
159					"region" => "ON",
160					"locality" => "Kitchener-Waterloo"
161				}]
162			)
163			form = Blather::Stanza::X.new
164			form.fields = [{ var: "q", value: "Kitchener, ON" }]
165			tns = execute_command do
166				TelSelections::ChooseTel::AvailableNumber
167					.for(
168						form,
169						redis: FakeRedis.new, db: db, memcache: FakeMemcache.new
170					).sync.tns
171			end
172			assert_equal(
173				["(226) 555-12345 (Kitchener-Waterloo, ON)"],
174				tns.map(&:to_s)
175			)
176		end
177		em :test_local_inventory
178
179		def test_local_inventory_whole_number_query
180			stub_request(
181				:get,
182				"https://dashboard.bandwidth.com/v1.0/accounts//availableNumbers" \
183					"?city=Kitchener-Waterloo&enableTNDetail=true&lCA=false&" \
184					"quantity=10&state=ON"
185			).to_return(status: 200, body: "")
186
187			db = FakeDB.new(
188				["ON", "Kitchener-Waterloo"] => [{
189					"tel" => "+122655512345",
190					"region" => "ON",
191					"locality" => "Kitchener-Waterloo"
192				}]
193			)
194			form = Blather::Stanza::X.new
195			form.fields = [{ var: "q", value: "+12265551234" }]
196			tn = execute_command do
197				TelSelections::ChooseTel::AvailableNumber
198					.for(
199						form,
200						redis: FakeRedis.new, db: db, memcache: FakeMemcache.new
201					).sync
202			end
203			assert_equal(
204				"+12265551234",
205				tn.tel
206			)
207		end
208		em :test_local_inventory_whole_number_query
209	end
210
211	class TnOptionTest < Minitest::Test
212		def setup
213			@tn = TelSelections::ChooseTel::Tn::Option.new(
214				full_number: "5551234567",
215				city: "Toronto",
216				state: "ON",
217				garbage: "stuff"
218			)
219			@local_tel = TelSelections::ChooseTel::Tn::LocalInventory.new(
220				@tn,
221				"test_account",
222				price: 10.0
223			)
224		end
225
226		def test_to_s
227			assert_equal "(555) 123-4567 (Toronto, ON)", @tn.to_s
228		end
229
230		def test_tel
231			assert_equal "+15551234567", @tn.tel
232		end
233
234		def test_option
235			assert_equal(
236				Blather::Stanza::X::Field::Option.new(
237					label: "(555) 123-4567 (Toronto, ON)",
238					value: "+15551234567"
239				),
240				@tn.option
241			)
242		end
243
244		def test_option_positive_price
245			assert_equal(
246				Blather::Stanza::X::Field::Option.new(
247					label: "(555) 123-4567 (Toronto, ON) +$10.00",
248					value: "+15551234567"
249				),
250				@local_tel.option
251			)
252		end
253
254		def test_option_reference
255			ref = @tn.option.find("ns:reference", ns: "urn:xmpp:reference:0").first
256			assert_equal(
257				@tn.formatted_tel,
258				@tn.option.label[ref["begin"].to_i..ref["end"].to_i]
259			)
260			assert_equal "tel:+15551234567", ref["uri"]
261		end
262	end
263
264	class QTest < Minitest::Test
265		def test_for_area_code
266			q = TelSelections::ChooseTel::Q.for("226").sync
267			assert_equal({ areaCode: "226" }, q.iris_query)
268		end
269		em :test_for_area_code
270
271		def test_for_area_code_sql
272			q = TelSelections::ChooseTel::Q.for("226").sync
273			assert_equal(
274				[
275					"SELECT * FROM tel_inventory " \
276					"WHERE available_after < LOCALTIMESTAMP AND tel LIKE $1 " \
277					"AND source NOT LIKE 'xmpp:%'",
278					"+1226%"
279				],
280				q.sql_query
281			)
282		end
283		em :test_for_area_code_sql
284
285		def test_for_npanxx
286			q = TelSelections::ChooseTel::Q.for("226666").sync
287			assert_equal({ npaNxx: "226666" }, q.iris_query)
288		end
289		em :test_for_npanxx
290
291		def test_for_npanxx_sql
292			q = TelSelections::ChooseTel::Q.for("226666").sync
293			assert_equal(
294				[
295					"SELECT * FROM tel_inventory " \
296					"WHERE available_after < LOCALTIMESTAMP AND tel LIKE $1 " \
297					"AND source NOT LIKE 'xmpp:%'",
298					"+1226666%"
299				],
300				q.sql_query
301			)
302		end
303		em :test_for_npanxx_sql
304
305		def test_for_npanxxx
306			q = TelSelections::ChooseTel::Q.for("2266667").sync
307			assert_equal({ npaNxxx: "2266667" }, q.iris_query)
308		end
309		em :test_for_npanxxx
310
311		def test_for_npanxxx_sql
312			q = TelSelections::ChooseTel::Q.for("2266667").sync
313			assert_equal(
314				[
315					"SELECT * FROM tel_inventory " \
316					"WHERE available_after < LOCALTIMESTAMP AND tel LIKE $1 "\
317					"AND source NOT LIKE 'xmpp:%'",
318					"+12266667%"
319				],
320				q.sql_query
321			)
322		end
323		em :test_for_npanxxx_sql
324
325		def test_for_zip
326			q = TelSelections::ChooseTel::Q.for("90210").sync
327			assert_equal({ zip: "90210" }, q.iris_query)
328		end
329		em :test_for_zip
330
331		def test_for_zip_sql
332			q = TelSelections::ChooseTel::Q.for("90210").sync
333			refute q.sql_query
334		end
335		em :test_for_zip_sql
336
337		def test_for_localvanity
338			q = TelSelections::ChooseTel::Q.for("~mboa").sync
339			assert_equal({ localVanity: "mboa" }, q.iris_query)
340		end
341		em :test_for_localvanity
342
343		def test_for_localvanity_sql
344			q = TelSelections::ChooseTel::Q.for("~mboa").sync
345			assert_equal(
346				[
347					"SELECT * FROM tel_inventory " \
348					"WHERE available_after < LOCALTIMESTAMP AND tel LIKE $1 " \
349					"AND source NOT LIKE 'xmpp:%'",
350					"%6262%"
351				],
352				q.sql_query
353			)
354		end
355		em :test_for_localvanity_sql
356
357		def test_for_state
358			q = TelSelections::ChooseTel::Q.for("ON").sync
359			assert_equal({ state: "ON" }, q.iris_query)
360		end
361		em :test_for_state
362
363		def test_for_state_sql
364			q = TelSelections::ChooseTel::Q.for("ON").sync
365			assert_equal(
366				[
367					"SELECT * FROM tel_inventory " \
368					"WHERE available_after < LOCALTIMESTAMP AND region = $1 " \
369					"AND source NOT LIKE 'xmpp:%'",
370					"ON"
371				],
372				q.sql_query
373			)
374		end
375		em :test_for_state_sql
376
377		def test_for_state_name
378			q = TelSelections::ChooseTel::Q.for("ontario").sync
379			assert_equal({ state: "ON" }, q.iris_query)
380		end
381		em :test_for_state_name
382
383		def test_for_state_name_sql
384			q = TelSelections::ChooseTel::Q.for("ontario").sync
385			assert_equal(
386				[
387					"SELECT * FROM tel_inventory " \
388					"WHERE available_after < LOCALTIMESTAMP AND region = $1 " \
389					"AND source NOT LIKE 'xmpp:%'",
390					"ON"
391				],
392				q.sql_query
393			)
394		end
395		em :test_for_state_name_sql
396
397		def test_for_new_york
398			q = TelSelections::ChooseTel::Q.for("New York").sync
399			assert_equal({ state: "NY" }, q.iris_query)
400		end
401		em :test_for_new_york
402
403		def test_for_new_york_sql
404			q = TelSelections::ChooseTel::Q.for("New York").sync
405			assert_equal(
406				[
407					"SELECT * FROM tel_inventory " \
408					"WHERE available_after < LOCALTIMESTAMP AND region = $1 " \
409					"AND source NOT LIKE 'xmpp:%'",
410					"NY"
411				],
412				q.sql_query
413			)
414		end
415		em :test_for_new_york_sql
416
417		def test_for_new_york_ny
418			q = TelSelections::ChooseTel::Q.for(
419				"New York, NY",
420				redis: FakeRedis.new, db: FakeDB.new,
421				memcache: FakeMemcache.new
422			).sync
423			assert_equal({ city: "New York City", state: "NY" }, q.iris_query)
424		end
425		em :test_for_new_york_ny
426
427		def test_for_new_york_ny_sql
428			q = TelSelections::ChooseTel::Q.for(
429				"New York, NY",
430				redis: FakeRedis.new, db: FakeDB.new,
431				memcache: FakeMemcache.new
432			).sync
433			assert_equal(
434				[
435					"SELECT * FROM tel_inventory " \
436					"WHERE available_after < LOCALTIMESTAMP " \
437					"AND region = $1 AND locality = $2 " \
438					"AND source NOT LIKE 'xmpp:%'",
439					"NY", "New York City"
440				],
441				q.sql_query
442			)
443		end
444		em :test_for_new_york_ny_sql
445
446		def test_for_new_york_new_york
447			q = TelSelections::ChooseTel::Q.for(
448				"New York, New York",
449				redis: FakeRedis.new, db: FakeDB.new,
450				memcache: FakeMemcache.new
451			).sync
452			assert_equal({ city: "New York City", state: "NY" }, q.iris_query)
453		end
454		em :test_for_new_york_new_york
455
456		def test_for_new_york_new_york_sql
457			q = TelSelections::ChooseTel::Q.for(
458				"New York, New York",
459				redis: FakeRedis.new, db: FakeDB.new,
460				memcache: FakeMemcache.new
461			).sync
462			assert_equal(
463				[
464					"SELECT * FROM tel_inventory " \
465					"WHERE available_after < LOCALTIMESTAMP " \
466					"AND region = $1 AND locality = $2 " \
467					"AND source NOT LIKE 'xmpp:%'",
468					"NY", "New York City"
469				],
470				q.sql_query
471			)
472		end
473		em :test_for_new_york_new_york_sql
474
475		def test_for_citystate
476			q = TelSelections::ChooseTel::Q.for(
477				"Toronto, ON",
478				redis: FakeRedis.new, db: FakeDB.new,
479				memcache: FakeMemcache.new
480			).sync
481			assert_equal({ city: "Toronto", state: "ON" }, q.iris_query)
482		end
483		em :test_for_citystate
484
485		def test_for_citystate_sql
486			q = TelSelections::ChooseTel::Q.for(
487				"Toronto, ON",
488				redis: FakeRedis.new, db: FakeDB.new,
489				memcache: FakeMemcache.new
490			).sync
491			assert_equal(
492				[
493					"SELECT * FROM tel_inventory " \
494					"WHERE available_after < LOCALTIMESTAMP " \
495					"AND region = $1 AND locality = $2 " \
496					"AND source NOT LIKE 'xmpp:%'",
497					"ON", "Toronto"
498				],
499				q.sql_query
500			)
501		end
502		em :test_for_citystate_sql
503
504		def test_for_citystate_name
505			q = TelSelections::ChooseTel::Q.for(
506				"Toronto, Ontario",
507				redis: FakeRedis.new, db: FakeDB.new,
508				memcache: FakeMemcache.new
509			).sync
510			assert_equal({ city: "Toronto", state: "ON" }, q.iris_query)
511		end
512		em :test_for_citystate_name
513
514		def test_for_citystate_name_sql
515			q = TelSelections::ChooseTel::Q.for(
516				"Toronto, Ontario",
517				redis: FakeRedis.new, db: FakeDB.new,
518				memcache: FakeMemcache.new
519			).sync
520			assert_equal(
521				[
522					"SELECT * FROM tel_inventory " \
523					"WHERE available_after < LOCALTIMESTAMP " \
524					"AND region = $1 AND locality = $2 " \
525					"AND source NOT LIKE 'xmpp:%'",
526					"ON", "Toronto"
527				],
528				q.sql_query
529			)
530		end
531		em :test_for_citystate_name_sql
532
533		def test_for_garbage
534			assert_raises { TelSelections::ChooseTel::Q.for("garbage").sync }
535		end
536		em :test_for_garbage
537
538		def test_offer_code
539			CustomerPlan::DB.expect(
540				:exec,
541				OpenStruct.new(cmd_tuples: 1),
542				[String, ["test", "USD", nil]]
543			)
544			CustomerPlan::DB.expect(
545				:exec,
546				OpenStruct.new(cmd_tuples: 0),
547				[String, ["test"]]
548			)
549			db = FakeDB.new(
550				["test", "DEADBEEF"] => [{ "creator_id" => "pplus" }]
551			)
552			q = TelSelections::ChooseTel::Q.for(
553				"DEADBEEF",
554				customer: customer,
555				redis: FakeRedis.new, db: db, memcache: FakeMemcache.new
556			).sync
557			assert_equal(
558				[
559					"SELECT * FROM tel_inventory " \
560					"WHERE available_after < LOCALTIMESTAMP AND source=$1",
561					"xmpp:pplus"
562				],
563				q.sql_query
564			)
565			assert_mock CustomerPlan::DB
566		end
567		em :test_offer_code
568
569		def test_offer_code_invalid
570			db = FakeDB.new
571			assert_raises do
572				TelSelections::ChooseTel::Q.for(
573					"DEADBEEF",
574					customer: customer,
575					redis: FakeRedis.new, db: db, memcache: FakeMemcache.new
576				).sync
577			end
578			assert_mock CustomerPlan::DB
579		end
580		em :test_offer_code_invalid
581
582		def test_offer_code_just_invite
583			CustomerPlan::DB.expect(
584				:exec,
585				OpenStruct.new(cmd_tuples: 1),
586				[String, ["test", "USD", nil]]
587			)
588			CustomerPlan::DB.expect(
589				:exec,
590				OpenStruct.new(cmd_tuples: 0),
591				[String, ["test"]]
592			)
593			db = FakeDB.new(
594				["test", "DEADBEEF"] => [{ "creator_id" => "notpplus" }]
595			)
596			assert_raises do
597				TelSelections::ChooseTel::Q.for(
598					"DEADBEEF",
599					customer: customer,
600					redis: FakeRedis.new, db: db, memcache: FakeMemcache.new
601				).sync
602			end
603			assert_mock CustomerPlan::DB
604		end
605		em :test_offer_code_just_invite
606	end
607end