Inject BackendSgx per customer

Stephen Paul Weber created

Instead of being a singleton that represents the entire relationship
with the backend, the object is now per-customer (since any meaningful
method requires a customer anyway for the from JID at least) and can be
delegated to directly from Customer.

Change summary

lib/backend_sgx.rb        | 19 +++++++++++------
lib/customer.rb           | 14 ++++--------
sgx_jmp.rb                |  1 
test/test_backend_sgx.rb  |  8 +++---
test/test_helper.rb       |  2 -
test/test_registration.rb | 42 ++++++++++++++++++++--------------------
6 files changed, 42 insertions(+), 44 deletions(-)

Detailed changes

lib/backend_sgx.rb 🔗

@@ -1,13 +1,14 @@
 # frozen_string_literal: true
 
 class BackendSgx
-	def initialize(jid=CONFIG[:sgx], creds=CONFIG[:creds])
+	def initialize(customer_id, jid=CONFIG[:sgx], creds=CONFIG[:creds])
+		@customer_id = customer_id
 		@jid = jid
 		@creds = creds
 	end
 
-	def register!(customer_id, tel)
-		ibr = mkibr(:set, customer_id)
+	def register!(tel)
+		ibr = mkibr(:set)
 		ibr.nick = @creds[:account]
 		ibr.username = @creds[:username]
 		ibr.password = @creds[:password]
@@ -15,8 +16,8 @@ class BackendSgx
 		IQ_MANAGER.write(ibr)
 	end
 
-	def registered?(customer_id)
-		IQ_MANAGER.write(mkibr(:get, customer_id)).catch { nil }.then do |result|
+	def registered?
+		IQ_MANAGER.write(mkibr(:get)).catch { nil }.then do |result|
 			if result&.respond_to?(:registered?) && result&.registered?
 				result
 			else
@@ -27,9 +28,13 @@ class BackendSgx
 
 protected
 
-	def mkibr(type, customer_id)
+	def from_jid
+		"customer_#{@customer_id}@#{CONFIG[:component][:jid]}"
+	end
+
+	def mkibr(type)
 		ibr = IBR.new(type, @jid)
-		ibr.from = "customer_#{customer_id}@#{CONFIG[:component][:jid]}"
+		ibr.from = from_jid
 		ibr
 	end
 end

lib/customer.rb 🔗

@@ -2,6 +2,7 @@
 
 require "forwardable"
 
+require_relative "./backend_sgx"
 require_relative "./ibr"
 require_relative "./payment_methods"
 require_relative "./plan"
@@ -30,17 +31,20 @@ class Customer
 	attr_reader :customer_id, :balance
 	def_delegator :@plan, :name, :plan_name
 	def_delegators :@plan, :currency, :merchant_account
+	def_delegators :@sgx, :register!, :registered?
 
 	def initialize(
 		customer_id,
 		plan_name: nil,
 		expires_at: Time.now,
-		balance: BigDecimal.new(0)
+		balance: BigDecimal.new(0),
+		sgx: BackendSgx.new(customer_id)
 	)
 		@plan = plan_name && Plan.for(plan_name)
 		@expires_at = expires_at
 		@customer_id = customer_id
 		@balance = balance
+		@sgx = sgx
 	end
 
 	def with_plan(plan_name)
@@ -82,14 +86,6 @@ class Customer
 		@plan && @expires_at > Time.now
 	end
 
-	def register!(tel)
-		BACKEND_SGX.register!(customer_id, tel)
-	end
-
-	def registered?
-		BACKEND_SGX.registered?(customer_id)
-	end
-
 protected
 
 	def charge_for_plan

sgx_jmp.rb 🔗

@@ -77,7 +77,6 @@ class AsyncBraintree
 end
 
 BRAINTREE = AsyncBraintree.new(**CONFIG[:braintree])
-BACKEND_SGX = BackendSgx.new
 
 def panic(e)
 	m = e.respond_to?(:message) ? e.message : e

test/test_backend_sgx.rb 🔗

@@ -7,7 +7,7 @@ BackendSgx::IQ_MANAGER = Minitest::Mock.new
 
 class BackendSgxTest < Minitest::Test
 	def setup
-		@sgx = BackendSgx.new
+		@sgx = BackendSgx.new("test")
 	end
 
 	def test_registered
@@ -19,7 +19,7 @@ class BackendSgxTest < Minitest::Test
 				assert_equal "customer_test@component", ibr.from.to_s
 			end]
 		)
-		assert @sgx.registered?("test").sync
+		assert @sgx.registered?.sync
 	end
 	em :test_registered
 
@@ -32,7 +32,7 @@ class BackendSgxTest < Minitest::Test
 				assert_equal "customer_test@component", ibr.from.to_s
 			end]
 		)
-		refute @sgx.registered?("test").sync
+		refute @sgx.registered?.sync
 	end
 	em :test_registered_not_registered
 
@@ -48,7 +48,7 @@ class BackendSgxTest < Minitest::Test
 				assert_equal "+15555550000", ibr.phone
 			end]
 		)
-		@sgx.register!("test", "+15555550000")
+		@sgx.register!("+15555550000")
 		BackendSgx::IQ_MANAGER.verify
 	end
 end

test/test_helper.rb 🔗

@@ -70,8 +70,6 @@ CONFIG = {
 	credit_card_url: ->(*) { "http://creditcard.example.com" }
 }.freeze
 
-BACKEND_SGX = Minitest::Mock.new(BackendSgx.new)
-
 BLATHER = Class.new {
 	def <<(*); end
 }.new.freeze

test/test_registration.rb 🔗

@@ -5,31 +5,34 @@ require "registration"
 
 class RegistrationTest < Minitest::Test
 	def test_for_registered
-		BACKEND_SGX.expect(
-			:registered?,
-			EMPromise.resolve(OpenStruct.new(phone: "+15555550000")),
-			["test"]
+		sgx = OpenStruct.new(
+			registered?: EMPromise.resolve(OpenStruct.new(phone: "+15555550000"))
 		)
 		iq = Blather::Stanza::Iq::Command.new
 		iq.from = "test@example.com"
-		result = Registration.for(iq, Customer.new("test"), Minitest::Mock.new).sync
+		result = Registration.for(
+			iq,
+			Customer.new("test", sgx: sgx),
+			Minitest::Mock.new
+		).sync
 		assert_kind_of Registration::Registered, result
 	end
 	em :test_for_registered
 
 	def test_for_activated
-		BACKEND_SGX.expect(
-			:registered?,
-			EMPromise.resolve(nil),
-			["test"]
-		)
+		sgx = OpenStruct.new(registered?: EMPromise.resolve(nil))
 		web_manager = WebRegisterManager.new
 		web_manager["test@example.com"] = "+15555550000"
 		iq = Blather::Stanza::Iq::Command.new
 		iq.from = "test@example.com"
 		result = Registration.for(
 			iq,
-			Customer.new("test", plan_name: "test_usd", expires_at: Time.now + 999),
+			Customer.new(
+				"test",
+				plan_name: "test_usd",
+				expires_at: Time.now + 999,
+				sgx: sgx
+			),
 			web_manager
 		).sync
 		assert_kind_of Registration::Finish, result
@@ -37,18 +40,14 @@ class RegistrationTest < Minitest::Test
 	em :test_for_activated
 
 	def test_for_not_activated_with_customer_id
-		BACKEND_SGX.expect(
-			:registered?,
-			EMPromise.resolve(nil),
-			["test"]
-		)
+		sgx = OpenStruct.new(registered?: EMPromise.resolve(nil))
 		web_manager = WebRegisterManager.new
 		web_manager["test@example.com"] = "+15555550000"
 		iq = Blather::Stanza::Iq::Command.new
 		iq.from = "test@example.com"
 		result = Registration.for(
 			iq,
-			Customer.new("test"),
+			Customer.new("test", sgx: sgx),
 			web_manager
 		).sync
 		assert_kind_of Registration::Activation, result
@@ -505,11 +504,12 @@ class RegistrationTest < Minitest::Test
 		Registration::Finish::REDIS = Minitest::Mock.new
 
 		def setup
+			@sgx = Minitest::Mock.new(BackendSgx.new("test"))
 			iq = Blather::Stanza::Iq::Command.new
 			iq.from = "test\\40example.com@cheogram.com"
 			@finish = Registration::Finish.new(
 				iq,
-				Customer.new("test"),
+				Customer.new("test", sgx: @sgx),
 				"+15555550000"
 			)
 		end
@@ -548,10 +548,10 @@ class RegistrationTest < Minitest::Test
 					"Content-Type" => "application/json"
 				}
 			).to_return(status: 201)
-			BACKEND_SGX.expect(
+			@sgx.expect(
 				:register!,
 				EMPromise.resolve(OpenStruct.new(error?: false)),
-				["test", "+15555550000"]
+				["+15555550000"]
 			)
 			Registration::Finish::REDIS.expect(
 				:set,
@@ -580,7 +580,7 @@ class RegistrationTest < Minitest::Test
 			)
 			@finish.write.sync
 			assert_requested create_order
-			BACKEND_SGX.verify
+			@sgx.verify
 			Registration::Finish::REDIS.verify
 			Registration::Finish::BLATHER.verify
 		end