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