test_low_balance.rb

  1# frozen_string_literal: true
  2
  3require "test_helper"
  4require "low_balance"
  5
  6ExpiringLock::REDIS = Minitest::Mock.new
  7CustomerPlan::REDIS = Minitest::Mock.new
  8CustomerFinancials::REDIS = Minitest::Mock.new
  9LowBalance::AutoTopUp::REDIS = Minitest::Mock.new
 10LowBalance::DB = Minitest::Mock.new
 11
 12class LowBalanceTest < Minitest::Test
 13	def test_for_locked
 14		ExpiringLock::REDIS.expect(
 15			:set,
 16			EMPromise.resolve(nil),
 17			["jmp_customer_low_balance-test", Time, "EX", 604800, "NX"]
 18		)
 19		assert_kind_of LowBalance::Locked, LowBalance.for(customer).sync
 20	end
 21	em :test_for_locked
 22
 23	def test_for_no_auto_top_up
 24		ExpiringLock::REDIS.expect(
 25			:set,
 26			EMPromise.resolve("OK"),
 27			["jmp_customer_low_balance-test", Time, "EX", 604800, "NX"]
 28		)
 29		CustomerFinancials::REDIS.expect(
 30			:smembers,
 31			EMPromise.resolve([]),
 32			["jmp_customer_btc_addresses-test"]
 33		)
 34		assert_kind_of(
 35			LowBalance,
 36			LowBalance.for(customer).sync
 37		)
 38		assert_mock ExpiringLock::REDIS
 39	end
 40	em :test_for_no_auto_top_up
 41
 42	def test_for_auto_top_up_on_transaction_amount
 43		ExpiringLock::REDIS.expect(
 44			:set,
 45			EMPromise.resolve("OK"),
 46			["jmp_customer_low_balance-test", Time, "EX", 604800, "NX"]
 47		)
 48		CustomerFinancials::REDIS.expect(
 49			:smembers,
 50			EMPromise.resolve([]),
 51			["block_credit_cards"]
 52		)
 53		LowBalance::AutoTopUp::REDIS.expect(
 54			:exists,
 55			0,
 56			["jmp_auto_top_up_block-abcd"]
 57		)
 58		braintree_customer = Minitest::Mock.new
 59		CustomerFinancials::BRAINTREE.expect(:customer, braintree_customer)
 60		payment_methods = OpenStruct.new(payment_methods: [
 61			OpenStruct.new(default?: true, unique_number_identifier: "abcd")
 62		])
 63		braintree_customer.expect(
 64			:find,
 65			EMPromise.resolve(payment_methods),
 66			["test"]
 67		)
 68		assert_kind_of(
 69			LowBalance::AutoTopUp,
 70			LowBalance.for(customer(auto_top_up_amount: 1), 15).sync
 71		)
 72		assert_mock ExpiringLock::REDIS
 73		assert_mock CustomerFinancials::REDIS
 74		assert_mock CustomerFinancials::BRAINTREE
 75		assert_mock braintree_customer
 76	end
 77	em :test_for_auto_top_up_on_transaction_amount
 78
 79	def test_for_auto_top_up
 80		ExpiringLock::REDIS.expect(
 81			:set,
 82			EMPromise.resolve("OK"),
 83			["jmp_customer_low_balance-test", Time, "EX", 604800, "NX"]
 84		)
 85		CustomerFinancials::REDIS.expect(
 86			:smembers,
 87			EMPromise.resolve([]),
 88			["block_credit_cards"]
 89		)
 90		LowBalance::AutoTopUp::REDIS.expect(
 91			:exists,
 92			0,
 93			["jmp_auto_top_up_block-abcd"]
 94		)
 95		braintree_customer = Minitest::Mock.new
 96		CustomerFinancials::BRAINTREE.expect(:customer, braintree_customer)
 97		payment_methods = OpenStruct.new(payment_methods: [
 98			OpenStruct.new(default?: true, unique_number_identifier: "abcd")
 99		])
100		braintree_customer.expect(
101			:find,
102			EMPromise.resolve(payment_methods),
103			["test"]
104		)
105		assert_kind_of(
106			LowBalance::AutoTopUp,
107			LowBalance.for(customer(auto_top_up_amount: 15)).sync
108		)
109		assert_mock ExpiringLock::REDIS
110		assert_mock CustomerFinancials::REDIS
111		assert_mock CustomerFinancials::BRAINTREE
112		assert_mock braintree_customer
113	end
114	em :test_for_auto_top_up
115
116	def test_for_auto_top_up_blocked
117		ExpiringLock::REDIS.expect(
118			:set,
119			EMPromise.resolve("OK"),
120			["jmp_customer_low_balance-test", Time, "EX", 604800, "NX"]
121		)
122		CustomerFinancials::REDIS.expect(
123			:smembers,
124			EMPromise.resolve([]),
125			["block_credit_cards"]
126		)
127		CustomerFinancials::REDIS.expect(
128			:smembers,
129			EMPromise.resolve([]),
130			["jmp_customer_btc_addresses-test"]
131		)
132		LowBalance::AutoTopUp::REDIS.expect(
133			:exists,
134			1,
135			["jmp_auto_top_up_block-blocked"]
136		)
137		braintree_customer = Minitest::Mock.new
138		CustomerFinancials::BRAINTREE.expect(:customer, braintree_customer)
139		payment_methods = OpenStruct.new(payment_methods: [
140			OpenStruct.new(default?: true, unique_number_identifier: "blocked")
141		])
142		braintree_customer.expect(
143			:find,
144			EMPromise.resolve(payment_methods),
145			["test"]
146		)
147		assert_kind_of(
148			LowBalance,
149			LowBalance.for(customer(auto_top_up_amount: 15)).sync
150		)
151		assert_mock ExpiringLock::REDIS
152		assert_mock CustomerFinancials::REDIS
153		assert_mock CustomerFinancials::BRAINTREE
154		assert_mock braintree_customer
155	end
156	em :test_for_auto_top_up_blocked
157
158	class AutoTopUpTest < Minitest::Test
159		LowBalance::AutoTopUp::CreditCardSale = Minitest::Mock.new
160
161		def setup
162			@customer = Minitest::Mock.new(
163				customer(auto_top_up_amount: 100, plan_name: "test_usd")
164			)
165			@auto_top_up = LowBalance::AutoTopUp.new(@customer)
166		end
167
168		def test_notify!
169			tx = OpenStruct.new(total: 13)
170			LowBalance::AutoTopUp::CreditCardSale.expect(
171				:create,
172				EMPromise.resolve(tx),
173				[@customer], amount: 100
174			)
175			@auto_top_up.notify!
176		end
177		em :test_notify!
178
179		def test_top_up_amount_when_target_greater_than_expected_balance
180			customer = Minitest::Mock.new(customer(
181				balance: 10,
182				auto_top_up_amount: 15
183			))
184			auto_top_up = LowBalance::AutoTopUp.new(customer, nil, 30, margin: 5)
185
186			assert_equal 25, auto_top_up.top_up_amount
187		end
188		em :test_top_up_amount_when_target_greater_than_expected_balance
189
190		def test_top_up_amount_when_target_less_than_expected_balance
191			customer = Minitest::Mock.new(customer(
192				balance: 10,
193				auto_top_up_amount: 15
194			))
195			auto_top_up = LowBalance::AutoTopUp.new(customer, nil, 12, margin: 5)
196
197			assert_equal 15, auto_top_up.top_up_amount
198		end
199		em :test_top_up_amount_when_target_less_than_expected_balance
200
201		def test_negative_balance_target_less_than_expected_balance
202			customer = Minitest::Mock.new(customer(
203				balance: -11,
204				auto_top_up_amount: 15
205			))
206			auto_top_up = LowBalance::AutoTopUp.new(customer, nil, 35, margin: 5)
207
208			assert_equal 51, auto_top_up.top_up_amount
209		end
210		em :test_negative_balance_target_less_than_expected_balance
211
212		def test_very_low_balance_notify!
213			customer = Minitest::Mock.new(customer(
214				balance: -100,
215				auto_top_up_amount: 15
216			))
217			auto_top_up = LowBalance::AutoTopUp.new(customer)
218			tx = OpenStruct.new(total: 13)
219
220			LowBalance::AutoTopUp::CreditCardSale.expect(
221				:create,
222				EMPromise.resolve(tx),
223				[customer], amount: 110
224			)
225			auto_top_up.notify!
226		end
227		em :test_very_low_balance_notify!
228
229		def test_border_low_balance_notify!
230			customer = Minitest::Mock.new(customer(
231				balance: -11,
232				auto_top_up_amount: 15
233			))
234			auto_top_up = LowBalance::AutoTopUp.new(customer)
235			tx = OpenStruct.new(total: 13)
236
237			LowBalance::AutoTopUp::CreditCardSale.expect(
238				:create,
239				EMPromise.resolve(tx),
240				[customer], amount: 21
241			)
242			auto_top_up.notify!
243		end
244		em :test_border_low_balance_notify!
245
246		def test_decline_notify!
247			stub_request(:post, "https://api.churnbuster.io/v1/failed_payments")
248				.with(
249					body: {
250						customer: {
251							source: "braintree",
252							source_id: "test",
253							email: "test@smtp.cheogram.com",
254							properties: {}
255						},
256						payment: {
257							source: "braintree",
258							source_id: "tx",
259							amount_in_cents: 10000,
260							currency: "USD"
261						}
262					}.to_json,
263					headers: {
264						"Authorization" => ["", ""],
265						"Content-Type" => "application/json"
266					}
267				).to_return(status: 200, body: "", headers: {})
268
269			@customer.expect(
270				:stanza_to,
271				nil,
272				[Matching.new { |m|
273					assert_equal(
274						"Automatic top-up transaction for $100.00 failed: test",
275						m.body
276					)
277				}]
278			)
279			LowBalance::AutoTopUp::CreditCardSale.expect(
280				:create,
281				EMPromise.reject(BraintreeFailure.new(OpenStruct.new(
282					message: "test",
283					transaction: OpenStruct.new(id: "tx")
284				))),
285				[@customer], amount: 100.to_d
286			)
287			@auto_top_up.notify!.sync
288			assert_mock @customer
289		end
290		em :test_decline_notify!
291	end
292end