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