test_registration.rb

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