test_registration.rb

  1# frozen_string_literal: true
  2
  3require "test_helper"
  4require "customer"
  5require "registration"
  6
  7class RegistrationTest < Minitest::Test
  8	def test_for_registered
  9		sgx = OpenStruct.new(
 10			registered?: EMPromise.resolve(OpenStruct.new(phone: "+15555550000"))
 11		)
 12		iq = Blather::Stanza::Iq::Command.new
 13		iq.from = "test@example.com"
 14		result = Registration.for(
 15			iq,
 16			Customer.new("test", sgx: sgx),
 17			Minitest::Mock.new
 18		).sync
 19		assert_kind_of Registration::Registered, result
 20	end
 21	em :test_for_registered
 22
 23	def test_for_activated
 24		sgx = OpenStruct.new(registered?: EMPromise.resolve(nil))
 25		web_manager = WebRegisterManager.new
 26		web_manager["test@example.com"] = "+15555550000"
 27		iq = Blather::Stanza::Iq::Command.new
 28		iq.from = "test@example.com"
 29		result = Registration.for(
 30			iq,
 31			Customer.new(
 32				"test",
 33				plan_name: "test_usd",
 34				expires_at: Time.now + 999,
 35				sgx: sgx
 36			),
 37			web_manager
 38		).sync
 39		assert_kind_of Registration::Finish, result
 40	end
 41	em :test_for_activated
 42
 43	def test_for_not_activated_with_customer_id
 44		sgx = OpenStruct.new(registered?: EMPromise.resolve(nil))
 45		web_manager = WebRegisterManager.new
 46		web_manager["test@example.com"] = "+15555550000"
 47		iq = Blather::Stanza::Iq::Command.new
 48		iq.from = "test@example.com"
 49		result = Registration.for(
 50			iq,
 51			Customer.new("test", sgx: sgx),
 52			web_manager
 53		).sync
 54		assert_kind_of Registration::Activation, result
 55	end
 56	em :test_for_not_activated_with_customer_id
 57
 58	class ActivationTest < Minitest::Test
 59		Registration::Activation::COMMAND_MANAGER = Minitest::Mock.new
 60		def setup
 61			iq = Blather::Stanza::Iq::Command.new
 62			@activation = Registration::Activation.new(iq, "test", "+15555550000")
 63		end
 64
 65		def test_write
 66			stub_request(
 67				:get,
 68				"https://dashboard.bandwidth.com/v1.0/tns/+15555550000"
 69			).to_return(status: 201, body: <<~RESPONSE)
 70				<TelephoneNumberResponse>
 71					<TelephoneNumber>5555550000</TelephoneNumber>
 72				</TelephoneNumberResponse>
 73			RESPONSE
 74			stub_request(
 75				:get,
 76				"https://dashboard.bandwidth.com/v1.0/tns/5555550000/ratecenter"
 77			).to_return(status: 201, body: <<~RESPONSE)
 78				<TelephoneNumberResponse>
 79					<TelephoneNumberDetails>
 80						<State>KE</State>
 81						<RateCenter>FA</RateCenter>
 82					</TelephoneNumberDetails>
 83				</TelephoneNumberResponse>
 84			RESPONSE
 85			result = Minitest::Mock.new
 86			result.expect(:then, result)
 87			result.expect(:then, EMPromise.resolve(:test_result))
 88			Registration::Activation::COMMAND_MANAGER.expect(
 89				:write,
 90				result,
 91				[Matching.new do |iq|
 92					assert_equal :form, iq.form.type
 93					assert_equal(
 94						"You've selected +15555550000 (FA, KE) as your JMP number",
 95						iq.form.instructions
 96					)
 97				end]
 98			)
 99			assert_equal :test_result, @activation.write.sync
100		end
101		em :test_write
102	end
103
104	class PaymentTest < Minitest::Test
105		Customer::BRAINTREE = Minitest::Mock.new
106
107		def test_for_bitcoin
108			customer = Minitest::Mock.new(Customer.new("test"))
109			customer.expect(
110				:add_btc_address,
111				EMPromise.resolve("testaddr")
112			)
113			iq = Blather::Stanza::Iq::Command.new
114			iq.form.fields = [
115				{ var: "activation_method", value: "bitcoin" },
116				{ var: "plan_name", value: "test_usd" }
117			]
118			result = Registration::Payment.for(iq, customer, "+15555550000")
119			assert_kind_of Registration::Payment::Bitcoin, result
120		end
121
122		def test_for_credit_card
123			braintree_customer = Minitest::Mock.new
124			Customer::BRAINTREE.expect(
125				:customer,
126				braintree_customer
127			)
128			braintree_customer.expect(
129				:find,
130				EMPromise.resolve(OpenStruct.new(payment_methods: [])),
131				["test"]
132			)
133			iq = Blather::Stanza::Iq::Command.new
134			iq.from = "test@example.com"
135			iq.form.fields = [
136				{ var: "activation_method", value: "credit_card" },
137				{ var: "plan_name", value: "test_usd" }
138			]
139			result = Registration::Payment.for(
140				iq,
141				Customer.new("test"),
142				"+15555550000"
143			).sync
144			assert_kind_of Registration::Payment::CreditCard, result
145		end
146		em :test_for_credit_card
147
148		def test_for_code
149			iq = Blather::Stanza::Iq::Command.new
150			iq.form.fields = [
151				{ var: "activation_method", value: "code" },
152				{ var: "plan_name", value: "test_usd" }
153			]
154			result = Registration::Payment.for(
155				iq,
156				Customer.new("test"),
157				"+15555550000"
158			)
159			assert_kind_of Registration::Payment::InviteCode, result
160		end
161
162		class BitcoinTest < Minitest::Test
163			Registration::Payment::Bitcoin::BTC_SELL_PRICES = Minitest::Mock.new
164			Registration::Payment::Bitcoin::BLATHER = Minitest::Mock.new
165			Customer::REDIS = Minitest::Mock.new
166
167			def setup
168				@customer = Minitest::Mock.new(
169					Customer.new("test", plan_name: "test_usd")
170				)
171				@customer.expect(
172					:add_btc_address,
173					EMPromise.resolve("testaddr")
174				)
175				iq = Blather::Stanza::Iq::Command.new
176				@bitcoin = Registration::Payment::Bitcoin.new(
177					iq,
178					@customer,
179					"+15555550000"
180				)
181			end
182
183			def test_write
184				Customer::REDIS.expect(
185					:smembers,
186					EMPromise.resolve([]),
187					["jmp_customer_btc_addresses-test"]
188				)
189				reply_text = <<~NOTE
190					Activate your account by sending at least 1.000000 BTC to
191					testaddr
192
193					You will receive a notification when your payment is complete.
194				NOTE
195				Registration::Payment::Bitcoin::BLATHER.expect(
196					:<<,
197					nil,
198					[Matching.new do |reply|
199						assert_equal :canceled, reply.status
200						assert_equal :info, reply.note_type
201						assert_equal reply_text, reply.note.content
202						true
203					end]
204				)
205				Registration::Payment::Bitcoin::BTC_SELL_PRICES.expect(
206					:usd,
207					EMPromise.resolve(BigDecimal.new(1))
208				)
209				@bitcoin.stub(:save, EMPromise.resolve(nil)) do
210					@bitcoin.write.sync
211				end
212				Registration::Payment::Bitcoin::BLATHER.verify
213			end
214			em :test_write
215		end
216
217		class CreditCardTest < Minitest::Test
218			def setup
219				@iq = Blather::Stanza::Iq::Command.new
220				@iq.from = "test@example.com"
221				@credit_card = Registration::Payment::CreditCard.new(
222					@iq,
223					Customer.new("test"),
224					"+15555550000"
225				)
226			end
227
228			def test_for
229				customer = Minitest::Mock.new(Customer.new("test"))
230				customer.expect(
231					:payment_methods,
232					EMPromise.resolve(OpenStruct.new(default_payment_method: :test))
233				)
234				assert_kind_of(
235					Registration::Payment::CreditCard::Activate,
236					Registration::Payment::CreditCard.for(
237						@iq,
238						customer,
239						"+15555550000"
240					).sync
241				)
242			end
243			em :test_for
244
245			def test_reply
246				assert_equal [:execute, :next], @credit_card.reply.allowed_actions
247				assert_equal(
248					"Add credit card, then return here to continue: " \
249					"http://creditcard.example.com",
250					@credit_card.reply.note.content
251				)
252			end
253		end
254
255		class ActivateTest < Minitest::Test
256			Registration::Payment::CreditCard::Activate::Finish =
257				Minitest::Mock.new
258			Registration::Payment::CreditCard::Activate::Transaction =
259				Minitest::Mock.new
260			Registration::Payment::CreditCard::Activate::COMMAND_MANAGER =
261				Minitest::Mock.new
262
263			def test_write
264				transaction = PromiseMock.new
265				transaction.expect(
266					:insert,
267					EMPromise.resolve(nil)
268				)
269				customer = Minitest::Mock.new(
270					Customer.new("test", plan_name: "test_usd")
271				)
272				Registration::Payment::CreditCard::Activate::Transaction.expect(
273					:sale,
274					transaction
275				) do |acustomer, amount:, payment_method:|
276					assert_operator customer, :===, acustomer
277					assert_equal CONFIG[:activation_amount], amount
278					assert_equal :test_default_method, payment_method
279				end
280				iq = Blather::Stanza::Iq::Command.new
281				customer.expect(:bill_plan, nil)
282				Registration::Payment::CreditCard::Activate::Finish.expect(
283					:new,
284					OpenStruct.new(write: nil),
285					[Blather::Stanza::Iq, customer, "+15555550000"]
286				)
287				Registration::Payment::CreditCard::Activate.new(
288					iq,
289					customer,
290					:test_default_method,
291					"+15555550000"
292				).write.sync
293				Registration::Payment::CreditCard::Activate::Transaction.verify
294				transaction.verify
295				customer.verify
296				Registration::Payment::CreditCard::Activate::Finish.verify
297			end
298			em :test_write
299
300			def test_write_declines
301				customer = Minitest::Mock.new(
302					Customer.new("test", plan_name: "test_usd")
303				)
304				Registration::Payment::CreditCard::Activate::Transaction.expect(
305					:sale,
306					EMPromise.reject("declined")
307				) do |acustomer, amount:, payment_method:|
308					assert_operator customer, :===, acustomer
309					assert_equal CONFIG[:activation_amount], amount
310					assert_equal :test_default_method, payment_method
311				end
312				iq = Blather::Stanza::Iq::Command.new
313				iq.from = "test@example.com"
314				result = Minitest::Mock.new
315				result.expect(:then, nil)
316				Registration::Payment::CreditCard::Activate::COMMAND_MANAGER.expect(
317					:write,
318					result,
319					[Matching.new do |reply|
320						assert_equal :error, reply.note_type
321						assert_equal(
322							Registration::Payment::CreditCard::Activate::DECLINE_MESSAGE +
323							": http://creditcard.example.com",
324							reply.note.content
325						)
326					end]
327				)
328				Registration::Payment::CreditCard::Activate.new(
329					iq,
330					customer,
331					:test_default_method,
332					"+15555550000"
333				).write.sync
334				Registration::Payment::CreditCard::Activate::Transaction.verify
335			end
336			em :test_write_declines
337		end
338
339		class InviteCodeTest < Minitest::Test
340			Registration::Payment::InviteCode::DB =
341				Minitest::Mock.new
342			Registration::Payment::InviteCode::REDIS =
343				Minitest::Mock.new
344			Registration::Payment::InviteCode::COMMAND_MANAGER =
345				Minitest::Mock.new
346			Registration::Payment::InviteCode::Finish =
347				Minitest::Mock.new
348
349			def test_write
350				customer = Customer.new("test", plan_name: "test_usd")
351				Registration::Payment::InviteCode::REDIS.expect(
352					:get,
353					EMPromise.resolve(nil),
354					["jmp_invite_tries-test"]
355				)
356				Registration::Payment::InviteCode::COMMAND_MANAGER.expect(
357					:write,
358					EMPromise.resolve(
359						Blather::Stanza::Iq::Command.new.tap { |iq|
360							iq.form.fields = [{ var: "code", value: "abc" }]
361						}
362					),
363					[Matching.new do |reply|
364						assert_equal :form, reply.form.type
365						assert_nil reply.form.instructions
366					end]
367				)
368				Registration::Payment::InviteCode::DB.expect(:transaction, true, [])
369				Registration::Payment::InviteCode::Finish.expect(
370					:new,
371					OpenStruct.new(write: nil),
372					[
373						Blather::Stanza::Iq::Command,
374						customer,
375						"+15555550000"
376					]
377				)
378				iq = Blather::Stanza::Iq::Command.new
379				iq.from = "test@example.com"
380				Registration::Payment::InviteCode.new(
381					iq,
382					customer,
383					"+15555550000"
384				).write.sync
385				Registration::Payment::InviteCode::COMMAND_MANAGER.verify
386				Registration::Payment::InviteCode::DB.verify
387				Registration::Payment::InviteCode::REDIS.verify
388				Registration::Payment::InviteCode::Finish.verify
389			end
390			em :test_write
391
392			def test_write_bad_code
393				customer = Customer.new("test", plan_name: "test_usd")
394				Registration::Payment::InviteCode::REDIS.expect(
395					:get,
396					EMPromise.resolve(0),
397					["jmp_invite_tries-test"]
398				)
399				Registration::Payment::InviteCode::COMMAND_MANAGER.expect(
400					:write,
401					EMPromise.resolve(
402						Blather::Stanza::Iq::Command.new.tap { |iq|
403							iq.form.fields = [{ var: "code", value: "abc" }]
404						}
405					),
406					[Matching.new do |reply|
407						assert_equal :form, reply.form.type
408						assert_nil reply.form.instructions
409					end]
410				)
411				Registration::Payment::InviteCode::DB.expect(:transaction, []) do
412					raise Registration::Payment::InviteCode::Invalid, "wut"
413				end
414				Registration::Payment::InviteCode::REDIS.expect(
415					:incr,
416					EMPromise.resolve(nil),
417					["jmp_invite_tries-test"]
418				)
419				Registration::Payment::InviteCode::REDIS.expect(
420					:expire,
421					EMPromise.resolve(nil),
422					["jmp_invite_tries-test", 60 * 60]
423				)
424				Registration::Payment::InviteCode::COMMAND_MANAGER.expect(
425					:write,
426					EMPromise.reject(Promise::Error.new),
427					[Matching.new do |reply|
428						assert_equal :form, reply.form.type
429						assert_equal "wut", reply.form.instructions
430					end]
431				)
432				iq = Blather::Stanza::Iq::Command.new
433				iq.from = "test@example.com"
434				assert_raises Promise::Error do
435					Registration::Payment::InviteCode.new(
436						iq,
437						customer,
438						"+15555550000"
439					).write.sync
440				end
441				Registration::Payment::InviteCode::COMMAND_MANAGER.verify
442				Registration::Payment::InviteCode::DB.verify
443				Registration::Payment::InviteCode::REDIS.verify
444			end
445			em :test_write_bad_code
446
447			def test_write_bad_code_over_limit
448				customer = Customer.new("test", plan_name: "test_usd")
449				Registration::Payment::InviteCode::REDIS.expect(
450					:get,
451					EMPromise.resolve(11),
452					["jmp_invite_tries-test"]
453				)
454				Registration::Payment::InviteCode::COMMAND_MANAGER.expect(
455					:write,
456					EMPromise.resolve(
457						Blather::Stanza::Iq::Command.new.tap { |iq|
458							iq.form.fields = [{ var: "code", value: "abc" }]
459						}
460					),
461					[Matching.new do |reply|
462						assert_equal :form, reply.form.type
463						assert_nil reply.form.instructions
464					end]
465				)
466				Registration::Payment::InviteCode::REDIS.expect(
467					:incr,
468					EMPromise.resolve(nil),
469					["jmp_invite_tries-test"]
470				)
471				Registration::Payment::InviteCode::REDIS.expect(
472					:expire,
473					EMPromise.resolve(nil),
474					["jmp_invite_tries-test", 60 * 60]
475				)
476				Registration::Payment::InviteCode::COMMAND_MANAGER.expect(
477					:write,
478					EMPromise.reject(Promise::Error.new),
479					[Matching.new do |reply|
480						assert_equal :form, reply.form.type
481						assert_equal "Too many wrong attempts", reply.form.instructions
482					end]
483				)
484				iq = Blather::Stanza::Iq::Command.new
485				iq.from = "test@example.com"
486				assert_raises Promise::Error do
487					Registration::Payment::InviteCode.new(
488						iq,
489						customer,
490						"+15555550000"
491					).write.sync
492				end
493				Registration::Payment::InviteCode::COMMAND_MANAGER.verify
494				Registration::Payment::InviteCode::REDIS.verify
495			end
496			em :test_write_bad_code_over_limit
497		end
498	end
499
500	class FinishTest < Minitest::Test
501		Registration::Finish::BLATHER = Minitest::Mock.new
502		Registration::Finish::REDIS = Minitest::Mock.new
503		BackendSgx::REDIS = Minitest::Mock.new
504
505		def setup
506			@sgx = Minitest::Mock.new(BackendSgx.new("test"))
507			iq = Blather::Stanza::Iq::Command.new
508			iq.from = "test\\40example.com@cheogram.com"
509			@finish = Registration::Finish.new(
510				iq,
511				Customer.new("test", sgx: @sgx),
512				"+15555550000"
513			)
514		end
515
516		def test_write
517			create_order = stub_request(
518				:post,
519				"https://dashboard.bandwidth.com/v1.0/accounts//orders"
520			).to_return(status: 201, body: <<~RESPONSE)
521				<OrderResponse>
522					<Order>
523						<id>test_order</id>
524					</Order>
525				</OrderResponse>
526			RESPONSE
527			stub_request(
528				:get,
529				"https://dashboard.bandwidth.com/v1.0/accounts//orders/test_order"
530			).to_return(status: 201, body: <<~RESPONSE)
531				<OrderResponse>
532					<OrderStatus>COMPLETE</OrderStatus>
533					<CompletedNumbers>
534						<TelephoneNumber>
535							<FullNumber>5555550000</FullNumber>
536						</TelephoneNumber>
537					</CompletedNumbers>
538				</OrderResponse>
539			RESPONSE
540			stub_request(
541				:post,
542				"https://api.catapult.inetwork.com/v1/users/catapult_user/phoneNumbers"
543			).with(
544				body: open(__dir__ + "/data/catapult_import_body.json").read.chomp,
545				headers: {
546					"Authorization" => "Basic Y2F0YXB1bHRfdG9rZW46Y2F0YXB1bHRfc2VjcmV0",
547					"Content-Type" => "application/json"
548				}
549			).to_return(status: 201)
550			@sgx.expect(
551				:register!,
552				EMPromise.resolve(OpenStruct.new(error?: false)),
553				["+15555550000"]
554			)
555			Registration::Finish::REDIS.expect(
556				:set,
557				nil,
558				[
559					"catapult_fwd-+15555550000",
560					"sip:test%5C40example.com%40cheogram.com@sip.cheogram.com"
561				]
562			)
563			BackendSgx::REDIS.expect(
564				:set,
565				nil,
566				["catapult_fwd_timeout-customer_test@component", 25]
567			)
568			Registration::Finish::BLATHER.expect(
569				:<<,
570				nil,
571				[Matching.new do |reply|
572					assert_equal :completed, reply.status
573					assert_equal :info, reply.note_type
574					assert_equal(
575						"Your JMP account has been activated as +15555550000",
576						reply.note.content
577					)
578				end]
579			)
580			@finish.write.sync
581			assert_requested create_order
582			@sgx.verify
583			Registration::Finish::REDIS.verify
584			BackendSgx::REDIS.verify
585			Registration::Finish::BLATHER.verify
586		end
587		em :test_write
588
589		def test_write_tn_fail
590			create_order = stub_request(
591				:post,
592				"https://dashboard.bandwidth.com/v1.0/accounts//orders"
593			).to_return(status: 201, body: <<~RESPONSE)
594				<OrderResponse>
595					<Order>
596						<id>test_order</id>
597					</Order>
598				</OrderResponse>
599			RESPONSE
600			stub_request(
601				:get,
602				"https://dashboard.bandwidth.com/v1.0/accounts//orders/test_order"
603			).to_return(status: 201, body: <<~RESPONSE)
604				<OrderResponse>
605					<OrderStatus>FAILED</OrderStatus>
606				</OrderResponse>
607			RESPONSE
608			Registration::Finish::BLATHER.expect(
609				:<<,
610				nil,
611				[Matching.new do |reply|
612					assert_equal :completed, reply.status
613					assert_equal :error, reply.note_type
614					assert_equal(
615						"The JMP number +15555550000 is no longer available, " \
616						"please visit https://jmp.chat and choose another.",
617						reply.note.content
618					)
619				end]
620			)
621			@finish.write.sync
622			assert_requested create_order
623			Registration::Finish::BLATHER.verify
624		end
625		em :test_write_tn_fail
626	end
627end