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	end
179
180	class TnOptionTest < Minitest::Test
181		def setup
182			@tn = TelSelections::ChooseTel::Tn::Option.new(
183				full_number: "5551234567",
184				city: "Toronto",
185				state: "ON",
186				garbage: "stuff"
187			)
188			@local_tel = TelSelections::ChooseTel::Tn::LocalInventory.new(
189				@tn,
190				"test_account",
191				price: 10.0
192			)
193		end
194
195		def test_to_s
196			assert_equal "(555) 123-4567 (Toronto, ON)", @tn.to_s
197		end
198
199		def test_tel
200			assert_equal "+15551234567", @tn.tel
201		end
202
203		def test_option
204			assert_equal(
205				Blather::Stanza::X::Field::Option.new(
206					label: "(555) 123-4567 (Toronto, ON)",
207					value: "+15551234567"
208				),
209				@tn.option
210			)
211		end
212
213		def test_option_positive_price
214			assert_equal(
215				Blather::Stanza::X::Field::Option.new(
216					label: "(555) 123-4567 (Toronto, ON) +$10.00",
217					value: "+15551234567"
218				),
219				@local_tel.option
220			)
221		end
222
223		def test_option_reference
224			ref = @tn.option.find("ns:reference", ns: "urn:xmpp:reference:0").first
225			assert_equal(
226				@tn.formatted_tel,
227				@tn.option.label[ref["begin"].to_i..ref["end"].to_i]
228			)
229			assert_equal "tel:+15551234567", ref["uri"]
230		end
231	end
232
233	class QTest < Minitest::Test
234		def test_for_area_code
235			q = TelSelections::ChooseTel::Q.for("226").sync
236			assert_equal({ areaCode: "226" }, q.iris_query)
237		end
238		em :test_for_area_code
239
240		def test_for_area_code_sql
241			q = TelSelections::ChooseTel::Q.for("226").sync
242			assert_equal(
243				[
244					"SELECT * FROM tel_inventory " \
245					"WHERE available_after < LOCALTIMESTAMP AND tel LIKE $1 " \
246					"AND source NOT LIKE 'xmpp:%'",
247					"+1226%"
248				],
249				q.sql_query
250			)
251		end
252		em :test_for_area_code_sql
253
254		def test_for_npanxx
255			q = TelSelections::ChooseTel::Q.for("226666").sync
256			assert_equal({ npaNxx: "226666" }, q.iris_query)
257		end
258		em :test_for_npanxx
259
260		def test_for_npanxx_sql
261			q = TelSelections::ChooseTel::Q.for("226666").sync
262			assert_equal(
263				[
264					"SELECT * FROM tel_inventory " \
265					"WHERE available_after < LOCALTIMESTAMP AND tel LIKE $1 " \
266					"AND source NOT LIKE 'xmpp:%'",
267					"+1226666%"
268				],
269				q.sql_query
270			)
271		end
272		em :test_for_npanxx_sql
273
274		def test_for_npanxxx
275			q = TelSelections::ChooseTel::Q.for("2266667").sync
276			assert_equal({ npaNxxx: "2266667" }, q.iris_query)
277		end
278		em :test_for_npanxxx
279
280		def test_for_npanxxx_sql
281			q = TelSelections::ChooseTel::Q.for("2266667").sync
282			assert_equal(
283				[
284					"SELECT * FROM tel_inventory " \
285					"WHERE available_after < LOCALTIMESTAMP AND tel LIKE $1 "\
286					"AND source NOT LIKE 'xmpp:%'",
287					"+12266667%"
288				],
289				q.sql_query
290			)
291		end
292		em :test_for_npanxxx_sql
293
294		def test_for_zip
295			q = TelSelections::ChooseTel::Q.for("90210").sync
296			assert_equal({ zip: "90210" }, q.iris_query)
297		end
298		em :test_for_zip
299
300		def test_for_zip_sql
301			q = TelSelections::ChooseTel::Q.for("90210").sync
302			refute q.sql_query
303		end
304		em :test_for_zip_sql
305
306		def test_for_localvanity
307			q = TelSelections::ChooseTel::Q.for("~mboa").sync
308			assert_equal({ localVanity: "mboa" }, q.iris_query)
309		end
310		em :test_for_localvanity
311
312		def test_for_localvanity_sql
313			q = TelSelections::ChooseTel::Q.for("~mboa").sync
314			assert_equal(
315				[
316					"SELECT * FROM tel_inventory " \
317					"WHERE available_after < LOCALTIMESTAMP AND tel LIKE $1 " \
318					"AND source NOT LIKE 'xmpp:%'",
319					"%6262%"
320				],
321				q.sql_query
322			)
323		end
324		em :test_for_localvanity_sql
325
326		def test_for_state
327			q = TelSelections::ChooseTel::Q.for("ON").sync
328			assert_equal({ state: "ON" }, q.iris_query)
329		end
330		em :test_for_state
331
332		def test_for_state_sql
333			q = TelSelections::ChooseTel::Q.for("ON").sync
334			assert_equal(
335				[
336					"SELECT * FROM tel_inventory " \
337					"WHERE available_after < LOCALTIMESTAMP AND region = $1 " \
338					"AND source NOT LIKE 'xmpp:%'",
339					"ON"
340				],
341				q.sql_query
342			)
343		end
344		em :test_for_state_sql
345
346		def test_for_state_name
347			q = TelSelections::ChooseTel::Q.for("ontario").sync
348			assert_equal({ state: "ON" }, q.iris_query)
349		end
350		em :test_for_state_name
351
352		def test_for_state_name_sql
353			q = TelSelections::ChooseTel::Q.for("ontario").sync
354			assert_equal(
355				[
356					"SELECT * FROM tel_inventory " \
357					"WHERE available_after < LOCALTIMESTAMP AND region = $1 " \
358					"AND source NOT LIKE 'xmpp:%'",
359					"ON"
360				],
361				q.sql_query
362			)
363		end
364		em :test_for_state_name_sql
365
366		def test_for_new_york
367			q = TelSelections::ChooseTel::Q.for("New York").sync
368			assert_equal({ state: "NY" }, q.iris_query)
369		end
370		em :test_for_new_york
371
372		def test_for_new_york_sql
373			q = TelSelections::ChooseTel::Q.for("New York").sync
374			assert_equal(
375				[
376					"SELECT * FROM tel_inventory " \
377					"WHERE available_after < LOCALTIMESTAMP AND region = $1 " \
378					"AND source NOT LIKE 'xmpp:%'",
379					"NY"
380				],
381				q.sql_query
382			)
383		end
384		em :test_for_new_york_sql
385
386		def test_for_new_york_ny
387			q = TelSelections::ChooseTel::Q.for(
388				"New York, NY",
389				redis: FakeRedis.new, db: FakeDB.new,
390				memcache: FakeMemcache.new
391			).sync
392			assert_equal({ city: "New York City", state: "NY" }, q.iris_query)
393		end
394		em :test_for_new_york_ny
395
396		def test_for_new_york_ny_sql
397			q = TelSelections::ChooseTel::Q.for(
398				"New York, NY",
399				redis: FakeRedis.new, db: FakeDB.new,
400				memcache: FakeMemcache.new
401			).sync
402			assert_equal(
403				[
404					"SELECT * FROM tel_inventory " \
405					"WHERE available_after < LOCALTIMESTAMP " \
406					"AND region = $1 AND locality = $2 " \
407					"AND source NOT LIKE 'xmpp:%'",
408					"NY", "New York City"
409				],
410				q.sql_query
411			)
412		end
413		em :test_for_new_york_ny_sql
414
415		def test_for_new_york_new_york
416			q = TelSelections::ChooseTel::Q.for(
417				"New York, New York",
418				redis: FakeRedis.new, db: FakeDB.new,
419				memcache: FakeMemcache.new
420			).sync
421			assert_equal({ city: "New York City", state: "NY" }, q.iris_query)
422		end
423		em :test_for_new_york_new_york
424
425		def test_for_new_york_new_york_sql
426			q = TelSelections::ChooseTel::Q.for(
427				"New York, New York",
428				redis: FakeRedis.new, db: FakeDB.new,
429				memcache: FakeMemcache.new
430			).sync
431			assert_equal(
432				[
433					"SELECT * FROM tel_inventory " \
434					"WHERE available_after < LOCALTIMESTAMP " \
435					"AND region = $1 AND locality = $2 " \
436					"AND source NOT LIKE 'xmpp:%'",
437					"NY", "New York City"
438				],
439				q.sql_query
440			)
441		end
442		em :test_for_new_york_new_york_sql
443
444		def test_for_citystate
445			q = TelSelections::ChooseTel::Q.for(
446				"Toronto, ON",
447				redis: FakeRedis.new, db: FakeDB.new,
448				memcache: FakeMemcache.new
449			).sync
450			assert_equal({ city: "Toronto", state: "ON" }, q.iris_query)
451		end
452		em :test_for_citystate
453
454		def test_for_citystate_sql
455			q = TelSelections::ChooseTel::Q.for(
456				"Toronto, ON",
457				redis: FakeRedis.new, db: FakeDB.new,
458				memcache: FakeMemcache.new
459			).sync
460			assert_equal(
461				[
462					"SELECT * FROM tel_inventory " \
463					"WHERE available_after < LOCALTIMESTAMP " \
464					"AND region = $1 AND locality = $2 " \
465					"AND source NOT LIKE 'xmpp:%'",
466					"ON", "Toronto"
467				],
468				q.sql_query
469			)
470		end
471		em :test_for_citystate_sql
472
473		def test_for_citystate_name
474			q = TelSelections::ChooseTel::Q.for(
475				"Toronto, Ontario",
476				redis: FakeRedis.new, db: FakeDB.new,
477				memcache: FakeMemcache.new
478			).sync
479			assert_equal({ city: "Toronto", state: "ON" }, q.iris_query)
480		end
481		em :test_for_citystate_name
482
483		def test_for_citystate_name_sql
484			q = TelSelections::ChooseTel::Q.for(
485				"Toronto, Ontario",
486				redis: FakeRedis.new, db: FakeDB.new,
487				memcache: FakeMemcache.new
488			).sync
489			assert_equal(
490				[
491					"SELECT * FROM tel_inventory " \
492					"WHERE available_after < LOCALTIMESTAMP " \
493					"AND region = $1 AND locality = $2 " \
494					"AND source NOT LIKE 'xmpp:%'",
495					"ON", "Toronto"
496				],
497				q.sql_query
498			)
499		end
500		em :test_for_citystate_name_sql
501
502		def test_for_garbage
503			assert_raises { TelSelections::ChooseTel::Q.for("garbage").sync }
504		end
505		em :test_for_garbage
506
507		def test_offer_code
508			CustomerPlan::DB.expect(
509				:exec,
510				OpenStruct.new(cmd_tuples: 1),
511				[String, ["test", "USD", nil]]
512			)
513			CustomerPlan::DB.expect(
514				:exec,
515				OpenStruct.new(cmd_tuples: 0),
516				[String, ["test"]]
517			)
518			db = FakeDB.new(
519				["test", "DEADBEEF"] => [{ "creator_id" => "pplus" }]
520			)
521			q = TelSelections::ChooseTel::Q.for(
522				"DEADBEEF",
523				customer: customer,
524				redis: FakeRedis.new, db: db, memcache: FakeMemcache.new
525			).sync
526			assert_equal(
527				[
528					"SELECT * FROM tel_inventory " \
529					"WHERE available_after < LOCALTIMESTAMP AND source=$1",
530					"xmpp:pplus"
531				],
532				q.sql_query
533			)
534			assert_mock CustomerPlan::DB
535		end
536		em :test_offer_code
537
538		def test_offer_code_invalid
539			db = FakeDB.new
540			assert_raises do
541				TelSelections::ChooseTel::Q.for(
542					"DEADBEEF",
543					customer: customer,
544					redis: FakeRedis.new, db: db, memcache: FakeMemcache.new
545				).sync
546			end
547			assert_mock CustomerPlan::DB
548		end
549		em :test_offer_code_invalid
550
551		def test_offer_code_just_invite
552			CustomerPlan::DB.expect(
553				:exec,
554				OpenStruct.new(cmd_tuples: 1),
555				[String, ["test", "USD", nil]]
556			)
557			CustomerPlan::DB.expect(
558				:exec,
559				OpenStruct.new(cmd_tuples: 0),
560				[String, ["test"]]
561			)
562			db = FakeDB.new(
563				["test", "DEADBEEF"] => [{ "creator_id" => "notpplus" }]
564			)
565			assert_raises do
566				TelSelections::ChooseTel::Q.for(
567					"DEADBEEF",
568					customer: customer,
569					redis: FakeRedis.new, db: db, memcache: FakeMemcache.new
570				).sync
571			end
572			assert_mock CustomerPlan::DB
573		end
574		em :test_offer_code_just_invite
575	end
576end