test_low_balance.rb

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