From a32e407bc5881d43e082839d0aaa6675e7c69b35 Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Wed, 21 Jan 2026 14:20:42 -0500 Subject: [PATCH] Pass through customer, redis, allow promise in Q.for --- lib/registration.rb | 6 +- lib/tel_selections.rb | 65 ++++++++++-------- test/test_helper.rb | 11 ++- test/test_registration.rb | 4 +- test/test_tel_selections.rb | 131 +++++++++++++++++++++++------------- 5 files changed, 137 insertions(+), 80 deletions(-) diff --git a/lib/registration.rb b/lib/registration.rb index 390f2e78546c79887859940da61698131d00ec28..7f35893661dd512c52eb6fddb5ff0743336b38a4 100644 --- a/lib/registration.rb +++ b/lib/registration.rb @@ -128,7 +128,7 @@ class Registration if (reg = customer.registered?) Registered.for(customer, reg.phone) else - tel_selections[customer.jid].then(&:choose_tel_or_data).then do |product| + tel_selections[customer].then(&:choose_tel_or_data).then do |product| reserve_and_continue(tel_selections, customer, product).then do RegistrationType.for(customer, google_play_userid, product) end @@ -142,7 +142,7 @@ class Registration def self.reserve_and_continue(tel_selections, customer, product) product.reserve(customer).catch do tel_selections.delete(customer.jid).then { - tel_selections[customer.jid] + tel_selections[customer] }.then { |choose| choose.choose_tel_or_data( error: "The JMP number #{tel} is no longer available." @@ -752,7 +752,7 @@ class Registration def number_purchase_error(e) Command.log.error "number_purchase_error", e TEL_SELECTIONS.delete(@customer.jid) - .then { TEL_SELECTIONS[@customer.jid] } + .then { TEL_SELECTIONS[@customer] } .then { |c| c.choose_tel_or_data( error: TN_UNAVAILABLE % @tel, diff --git a/lib/tel_selections.rb b/lib/tel_selections.rb index 55550c2ea739b05e69b778ba87fc918b0aa20d4d..06e86cc0cf23442fc934cc0265b09ea8cdbb5fc3 100644 --- a/lib/tel_selections.rb +++ b/lib/tel_selections.rb @@ -46,9 +46,11 @@ class TelSelections @redis.del("pending_tel_for-#{jid}") end - def [](jid) - @redis.get("pending_tel_for-#{jid}").then do |tel| - tel ? HaveTel.new(tel) : ChooseTel.new(db: @db, memcache: @memcache) + def [](customer) + @redis.get("pending_tel_for-#{customer.jid}").then do |tel| + next HaveTel.new(tel) if tel + + ChooseTel.new(customer, redis: @redis, db: @db, memcache: @memcache) end end @@ -65,8 +67,10 @@ class TelSelections class ChooseTel class Fail < RuntimeError; end - def initialize(db: DB, memcache: MEMCACHE) + def initialize(customer, redis: REDIS, db: DB, memcache: MEMCACHE) + @customer = customer @db = db + @redis = redis @memcache = memcache end @@ -92,12 +96,15 @@ class TelSelections end def choose_tel(iq) - available = AvailableNumber.for(iq.form, db: @db, memcache: @memcache) - return available if available.is_a?(Tn::Bandwidth) - - choose_from_list(available.tns) - rescue Fail - choose_tel_or_data(error: $!.to_s) + AvailableNumber.for( + iq.form, customer: customer, redis: @redis, db: @db, memcache: @memcache + ).then { |avail| + next avail if avail.is_a?(Tn::Bandwidth) + + choose_from_list(avail.tns) + }.catch_only(Fail) do + choose_tel_or_data(error: $!.to_s) + end end def choose_from_list(tns) @@ -119,19 +126,18 @@ class TelSelections end class AvailableNumber - def self.for(form, db: DB, memcache: MEMCACHE) + def self.for(form, **kwargs) qs = form.field("q")&.value.to_s.strip return Tn.for_pending_value(qs) if qs =~ /\A\+1\d{10}\Z/ - quantity = Quantity.for(form) - q = Q.for(feelinglucky(qs, form), db: db, memcache: memcache) - - new( - q.iris_query - .merge(enableTNDetail: true, LCA: false), - q.sql_query, quantity, - fallback: q.fallback, memcache: memcache, db: db - ) + Q.for(feelinglucky(qs, form), **kwargs).then do |q| + new( + q.iris_query + .merge(enableTNDetail: true, LCA: false), + q.sql_query, Quantity.for(form), + fallback: q.fallback, **kwargs + ) + end end ACTION_FIELD = "http://jabber.org/protocol/commands#actions" @@ -145,9 +151,9 @@ class TelSelections def initialize( iris_query, sql_query, quantity, - fallback: [], memcache: MEMCACHE, db: DB + fallback: [], memcache: MEMCACHE, db: DB, ** ) - @iris_query = iris_query.merge(quantity.iris_query) + @iris_query = iris_query&.merge(quantity.iris_query) @sql_query = sql_query @quantity = quantity @fallback = fallback @@ -166,6 +172,8 @@ class TelSelections end def fetch_bandwidth_inventory + return [] unless @iris_query + BandwidthIris::AvailableNumber .list(@iris_query) .map { |tn| Tn::Bandwidth.new(Tn::Option.new(**tn)) } @@ -402,12 +410,15 @@ class TelSelections def self.for(q, **kwa) q = replace_region_names(q) unless q.start_with?("~") - @queries.each do |(regex, block)| + EMPromise.all(@queries.map { |(regex, block)| match_data = (q =~ regex) - return block.call($1 || $&, *$~.to_a[2..-1], **kwa) if match_data - end + block.call($1 || $&, *$~.to_a[2..-1], **kwa) if match_data + }).then do |qs| + qs = qs.compact + raise Fail, "Format not recognized: #{q}" if qs.empty? - raise Fail, "Format not recognized: #{q}" + qs.first + end end def self.replace_region_names(query) @@ -547,7 +558,7 @@ class TelSelections "west durham" => "Durham" }.freeze - def initialize(city, state, db: DB, memcache: MEMCACHE) + def initialize(city, state, db: DB, memcache: MEMCACHE, **) @city = CITY_MAP.fetch(city.downcase, city) @state = State.new(state) @db = db diff --git a/test/test_helper.rb b/test/test_helper.rb index 18790a9eafd519e6c59890a46af239fd07998e9c..4e567ba167108cce308148d1d40a904db1aeb1c9 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -264,9 +264,14 @@ class FakeTelSelections EMPromise.resolve("OK") end - def [](jid) - @selections.fetch(jid) do - TelSelections::ChooseTel.new(db: FakeDB.new, memcache: FakeMemcache.new) + def [](customer) + @selections.fetch(customer.jid) do + TelSelections::ChooseTel.new( + customer, + redis: FakeRedis.new, + db: FakeDB.new, + memcache: FakeMemcache.new + ) end end end diff --git a/test/test_registration.rb b/test/test_registration.rb index 7f3c7c3a46e2fd9970f522993ea195909130cf33..e028c5f997396dd2f3adf43214f4e7c5b94d7b56 100644 --- a/test/test_registration.rb +++ b/test/test_registration.rb @@ -1834,7 +1834,9 @@ class RegistrationTest < Minitest::Test assert_mock Command::COMMAND_MANAGER assert_instance_of( TelSelections::ChooseTel, - Registration::Finish::TEL_SELECTIONS["test@example.com"] + Registration::Finish::TEL_SELECTIONS[ + OpenStruct.new(jid: "test@example.com") + ] ) assert_requested create_order end diff --git a/test/test_tel_selections.rb b/test/test_tel_selections.rb index d5abd1470bfdc851f8fe944a6f8b99878d2c6328..19681217263909d8c2d4f5d3c0e9a7bba348e93c 100644 --- a/test/test_tel_selections.rb +++ b/test/test_tel_selections.rb @@ -13,12 +13,13 @@ class TelSelectionsTest < Minitest::Test end def test_set_get - assert_kind_of TelSelections::ChooseTel, @manager["jid@example.com"].sync + cust = OpenStruct.new(jid: "jid@example.com") + assert_kind_of TelSelections::ChooseTel, @manager[cust].sync @manager.set( "jid@example.com", TelSelections::ChooseTel::Tn.for_pending_value("+15555550000") ).sync - assert_kind_of TelSelections::HaveTel, @manager["jid@example.com"].sync + assert_kind_of TelSelections::HaveTel, @manager[cust].sync end em :test_set_get @@ -30,7 +31,7 @@ class TelSelectionsTest < Minitest::Test ).sync assert_equal( "+15555550000", - @manager[jid].then(&:choose_tel_or_data).sync.tel + @manager[OpenStruct.new(jid: jid)].then(&:choose_tel_or_data).sync.tel ) end em :test_choose_tel_have_tel @@ -40,13 +41,16 @@ class TelSelectionsTest < Minitest::Test form = Blather::Stanza::X.new form.fields = [{ var: "q", value: "226" }] iris_query = TelSelections::ChooseTel::AvailableNumber - .for(form, db: FakeDB.new, memcache: FakeMemcache.new) - .instance_variable_get(:@iris_query) + .for( + form, + redis: FakeRedis.new, db: FakeDB.new, memcache: FakeMemcache.new + ).sync.instance_variable_get(:@iris_query) assert_equal( { areaCode: "226", enableTNDetail: true, LCA: false, quantity: 10 }, iris_query ) end + em :test_for_no_rsm def test_for_rsm form = Blather::Stanza::X.new @@ -57,14 +61,17 @@ class TelSelectionsTest < Minitest::Test end end iris_query = TelSelections::ChooseTel::AvailableNumber - .for(form, db: FakeDB.new, memcache: FakeMemcache.new) - .instance_variable_get(:@iris_query) + .for( + form, + redis: FakeRedis.new, db: FakeDB.new, memcache: FakeMemcache.new + ).sync.instance_variable_get(:@iris_query) # quantity should be 500 due to max inside tel selections assert_equal( { areaCode: "226", enableTNDetail: true, LCA: false, quantity: 500 }, iris_query ) end + em :test_for_rsm def test_for_feelinglucky form = Blather::Stanza::X.new @@ -76,13 +83,16 @@ class TelSelectionsTest < Minitest::Test } ] iris_query = TelSelections::ChooseTel::AvailableNumber - .for(form, db: FakeDB.new, memcache: FakeMemcache.new) - .instance_variable_get(:@iris_query) + .for( + form, + redis: FakeRedis.new, db: FakeDB.new, memcache: FakeMemcache.new + ).sync.instance_variable_get(:@iris_query) assert_equal( { areaCode: "810", enableTNDetail: true, LCA: false, quantity: 10 }, iris_query ) end + em :test_for_feelinglucky def test_fallback stub_request( @@ -123,8 +133,10 @@ class TelSelectionsTest < Minitest::Test form.fields = [{ var: "q", value: "Kitchener, ON" }] tns = execute_command do TelSelections::ChooseTel::AvailableNumber - .for(form, db: db, memcache: FakeMemcache.new) - .tns + .for( + form, + redis: FakeRedis.new, db: db, memcache: FakeMemcache.new + ).sync.tns end assert_equal( ["(226) 555-12345 (Somewhere, ON)"], @@ -152,8 +164,10 @@ class TelSelectionsTest < Minitest::Test form.fields = [{ var: "q", value: "Kitchener, ON" }] tns = execute_command do TelSelections::ChooseTel::AvailableNumber - .for(form, db: db, memcache: FakeMemcache.new) - .tns + .for( + form, + redis: FakeRedis.new, db: db, memcache: FakeMemcache.new + ).sync.tns end assert_equal( ["(226) 555-12345 (Kitchener-Waterloo, ON)"], @@ -218,12 +232,13 @@ class TelSelectionsTest < Minitest::Test class QTest < Minitest::Test def test_for_area_code - q = TelSelections::ChooseTel::Q.for("226") + q = TelSelections::ChooseTel::Q.for("226").sync assert_equal({ areaCode: "226" }, q.iris_query) end + em :test_for_area_code def test_for_area_code_sql - q = TelSelections::ChooseTel::Q.for("226") + q = TelSelections::ChooseTel::Q.for("226").sync assert_equal( [ "SELECT * FROM tel_inventory " \ @@ -234,14 +249,16 @@ class TelSelectionsTest < Minitest::Test q.sql_query ) end + em :test_for_area_code_sql def test_for_npanxx - q = TelSelections::ChooseTel::Q.for("226666") + q = TelSelections::ChooseTel::Q.for("226666").sync assert_equal({ npaNxx: "226666" }, q.iris_query) end + em :test_for_npanxx def test_for_npanxx_sql - q = TelSelections::ChooseTel::Q.for("226666") + q = TelSelections::ChooseTel::Q.for("226666").sync assert_equal( [ "SELECT * FROM tel_inventory " \ @@ -252,14 +269,16 @@ class TelSelectionsTest < Minitest::Test q.sql_query ) end + em :test_for_npanxx_sql def test_for_npanxxx - q = TelSelections::ChooseTel::Q.for("2266667") + q = TelSelections::ChooseTel::Q.for("2266667").sync assert_equal({ npaNxxx: "2266667" }, q.iris_query) end + em :test_for_npanxxx def test_for_npanxxx_sql - q = TelSelections::ChooseTel::Q.for("2266667") + q = TelSelections::ChooseTel::Q.for("2266667").sync assert_equal( [ "SELECT * FROM tel_inventory " \ @@ -270,24 +289,28 @@ class TelSelectionsTest < Minitest::Test q.sql_query ) end + em :test_for_npanxxx_sql def test_for_zip - q = TelSelections::ChooseTel::Q.for("90210") + q = TelSelections::ChooseTel::Q.for("90210").sync assert_equal({ zip: "90210" }, q.iris_query) end + em :test_for_zip def test_for_zip_sql - q = TelSelections::ChooseTel::Q.for("90210") + q = TelSelections::ChooseTel::Q.for("90210").sync refute q.sql_query end + em :test_for_zip_sql def test_for_localvanity - q = TelSelections::ChooseTel::Q.for("~mboa") + q = TelSelections::ChooseTel::Q.for("~mboa").sync assert_equal({ localVanity: "mboa" }, q.iris_query) end + em :test_for_localvanity def test_for_localvanity_sql - q = TelSelections::ChooseTel::Q.for("~mboa") + q = TelSelections::ChooseTel::Q.for("~mboa").sync assert_equal( [ "SELECT * FROM tel_inventory " \ @@ -298,14 +321,16 @@ class TelSelectionsTest < Minitest::Test q.sql_query ) end + em :test_for_localvanity_sql def test_for_state - q = TelSelections::ChooseTel::Q.for("ON") + q = TelSelections::ChooseTel::Q.for("ON").sync assert_equal({ state: "ON" }, q.iris_query) end + em :test_for_state def test_for_state_sql - q = TelSelections::ChooseTel::Q.for("ON") + q = TelSelections::ChooseTel::Q.for("ON").sync assert_equal( [ "SELECT * FROM tel_inventory " \ @@ -316,14 +341,16 @@ class TelSelectionsTest < Minitest::Test q.sql_query ) end + em :test_for_state_sql def test_for_state_name - q = TelSelections::ChooseTel::Q.for("ontario") + q = TelSelections::ChooseTel::Q.for("ontario").sync assert_equal({ state: "ON" }, q.iris_query) end + em :test_for_state_name def test_for_state_name_sql - q = TelSelections::ChooseTel::Q.for("ontario") + q = TelSelections::ChooseTel::Q.for("ontario").sync assert_equal( [ "SELECT * FROM tel_inventory " \ @@ -334,14 +361,16 @@ class TelSelectionsTest < Minitest::Test q.sql_query ) end + em :test_for_state_name_sql def test_for_new_york - q = TelSelections::ChooseTel::Q.for("New York") + q = TelSelections::ChooseTel::Q.for("New York").sync assert_equal({ state: "NY" }, q.iris_query) end + em :test_for_new_york def test_for_new_york_sql - q = TelSelections::ChooseTel::Q.for("New York") + q = TelSelections::ChooseTel::Q.for("New York").sync assert_equal( [ "SELECT * FROM tel_inventory " \ @@ -352,22 +381,24 @@ class TelSelectionsTest < Minitest::Test q.sql_query ) end + em :test_for_new_york_sql def test_for_new_york_ny q = TelSelections::ChooseTel::Q.for( "New York, NY", - db: FakeDB.new, + redis: FakeRedis.new, db: FakeDB.new, memcache: FakeMemcache.new - ) + ).sync assert_equal({ city: "New York City", state: "NY" }, q.iris_query) end + em :test_for_new_york_ny def test_for_new_york_ny_sql q = TelSelections::ChooseTel::Q.for( "New York, NY", - db: FakeDB.new, + redis: FakeRedis.new, db: FakeDB.new, memcache: FakeMemcache.new - ) + ).sync assert_equal( [ "SELECT * FROM tel_inventory " \ @@ -379,22 +410,24 @@ class TelSelectionsTest < Minitest::Test q.sql_query ) end + em :test_for_new_york_ny_sql def test_for_new_york_new_york q = TelSelections::ChooseTel::Q.for( "New York, New York", - db: FakeDB.new, + redis: FakeRedis.new, db: FakeDB.new, memcache: FakeMemcache.new - ) + ).sync assert_equal({ city: "New York City", state: "NY" }, q.iris_query) end + em :test_for_new_york_new_york def test_for_new_york_new_york_sql q = TelSelections::ChooseTel::Q.for( "New York, New York", - db: FakeDB.new, + redis: FakeRedis.new, db: FakeDB.new, memcache: FakeMemcache.new - ) + ).sync assert_equal( [ "SELECT * FROM tel_inventory " \ @@ -406,22 +439,24 @@ class TelSelectionsTest < Minitest::Test q.sql_query ) end + em :test_for_new_york_new_york_sql def test_for_citystate q = TelSelections::ChooseTel::Q.for( "Toronto, ON", - db: FakeDB.new, + redis: FakeRedis.new, db: FakeDB.new, memcache: FakeMemcache.new - ) + ).sync assert_equal({ city: "Toronto", state: "ON" }, q.iris_query) end + em :test_for_citystate def test_for_citystate_sql q = TelSelections::ChooseTel::Q.for( "Toronto, ON", - db: FakeDB.new, + redis: FakeRedis.new, db: FakeDB.new, memcache: FakeMemcache.new - ) + ).sync assert_equal( [ "SELECT * FROM tel_inventory " \ @@ -433,22 +468,24 @@ class TelSelectionsTest < Minitest::Test q.sql_query ) end + em :test_for_citystate_sql def test_for_citystate_name q = TelSelections::ChooseTel::Q.for( "Toronto, Ontario", - db: FakeDB.new, + redis: FakeRedis.new, db: FakeDB.new, memcache: FakeMemcache.new - ) + ).sync assert_equal({ city: "Toronto", state: "ON" }, q.iris_query) end + em :test_for_citystate_name def test_for_citystate_name_sql q = TelSelections::ChooseTel::Q.for( "Toronto, Ontario", - db: FakeDB.new, + redis: FakeRedis.new, db: FakeDB.new, memcache: FakeMemcache.new - ) + ).sync assert_equal( [ "SELECT * FROM tel_inventory " \ @@ -460,9 +497,11 @@ class TelSelectionsTest < Minitest::Test q.sql_query ) end + em :test_for_citystate_name_sql def test_for_garbage - assert_raises { TelSelections::ChooseTel::Q.for("garbage") } + assert_raises { TelSelections::ChooseTel::Q.for("garbage").sync } end + em :test_for_garbage end end