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