test_registration.rb

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