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					[
269						customer,
270						CONFIG[:activation_amount],
271						:test_default_method
272					]
273				)
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					[
302						customer,
303						CONFIG[:activation_amount],
304						:test_default_method
305					]
306				)
307				iq = Blather::Stanza::Iq::Command.new
308				iq.from = "test@example.com"
309				result = Minitest::Mock.new
310				result.expect(:then, nil)
311				Registration::Payment::CreditCard::Activate::COMMAND_MANAGER.expect(
312					:write,
313					result,
314					[Matching.new do |reply|
315						assert_equal :error, reply.note_type
316						assert_equal(
317							Registration::Payment::CreditCard::Activate::DECLINE_MESSAGE +
318							": http://creditcard.example.com",
319							reply.note.content
320						)
321					end]
322				)
323				Registration::Payment::CreditCard::Activate.new(
324					iq,
325					customer,
326					:test_default_method,
327					"+15555550000"
328				).write.sync
329				Registration::Payment::CreditCard::Activate::Transaction.verify
330			end
331			em :test_write_declines
332		end
333
334		class InviteCodeTest < Minitest::Test
335			Registration::Payment::InviteCode::DB =
336				Minitest::Mock.new
337			Registration::Payment::InviteCode::REDIS =
338				Minitest::Mock.new
339			Registration::Payment::InviteCode::COMMAND_MANAGER =
340				Minitest::Mock.new
341			Registration::Payment::InviteCode::Finish =
342				Minitest::Mock.new
343
344			def test_write
345				customer = Customer.new("test", plan_name: "test_usd")
346				Registration::Payment::InviteCode::REDIS.expect(
347					:get,
348					EMPromise.resolve(0),
349					["jmp_invite_tries-test"]
350				)
351				Registration::Payment::InviteCode::COMMAND_MANAGER.expect(
352					:write,
353					EMPromise.resolve(
354						Blather::Stanza::Iq::Command.new.tap { |iq|
355							iq.form.fields = [{ var: "code", value: "abc" }]
356						}
357					),
358					[Matching.new do |reply|
359						assert_equal :form, reply.form.type
360						assert_nil reply.form.instructions
361					end]
362				)
363				Registration::Payment::InviteCode::DB.expect(:transaction, true, [])
364				Registration::Payment::InviteCode::Finish.expect(
365					:new,
366					OpenStruct.new(write: nil),
367					[
368						Blather::Stanza::Iq::Command,
369						customer,
370						"+15555550000"
371					]
372				)
373				iq = Blather::Stanza::Iq::Command.new
374				iq.from = "test@example.com"
375				Registration::Payment::InviteCode.new(
376					iq,
377					customer,
378					"+15555550000"
379				).write.sync
380				Registration::Payment::InviteCode::COMMAND_MANAGER.verify
381				Registration::Payment::InviteCode::DB.verify
382				Registration::Payment::InviteCode::REDIS.verify
383				Registration::Payment::InviteCode::Finish.verify
384			end
385			em :test_write
386
387			def test_write_bad_code
388				customer = Customer.new("test", plan_name: "test_usd")
389				Registration::Payment::InviteCode::REDIS.expect(
390					:get,
391					EMPromise.resolve(0),
392					["jmp_invite_tries-test"]
393				)
394				Registration::Payment::InviteCode::COMMAND_MANAGER.expect(
395					:write,
396					EMPromise.resolve(
397						Blather::Stanza::Iq::Command.new.tap { |iq|
398							iq.form.fields = [{ var: "code", value: "abc" }]
399						}
400					),
401					[Matching.new do |reply|
402						assert_equal :form, reply.form.type
403						assert_nil reply.form.instructions
404					end]
405				)
406				Registration::Payment::InviteCode::DB.expect(:transaction, []) do
407					raise Registration::Payment::InviteCode::Invalid, "wut"
408				end
409				Registration::Payment::InviteCode::REDIS.expect(
410					:incr,
411					EMPromise.resolve(nil),
412					["jmp_invite_tries-test"]
413				)
414				Registration::Payment::InviteCode::REDIS.expect(
415					:expire,
416					EMPromise.resolve(nil),
417					["jmp_invite_tries-test", 60 * 60]
418				)
419				Registration::Payment::InviteCode::COMMAND_MANAGER.expect(
420					:write,
421					EMPromise.reject(Promise::Error.new),
422					[Matching.new do |reply|
423						assert_equal :form, reply.form.type
424						assert_equal "wut", reply.form.instructions
425					end]
426				)
427				iq = Blather::Stanza::Iq::Command.new
428				iq.from = "test@example.com"
429				assert_raises Promise::Error do
430					Registration::Payment::InviteCode.new(
431						iq,
432						customer,
433						"+15555550000"
434					).write.sync
435				end
436				Registration::Payment::InviteCode::COMMAND_MANAGER.verify
437				Registration::Payment::InviteCode::DB.verify
438				Registration::Payment::InviteCode::REDIS.verify
439			end
440			em :test_write_bad_code
441
442			def test_write_bad_code_over_limit
443				customer = Customer.new("test", plan_name: "test_usd")
444				Registration::Payment::InviteCode::REDIS.expect(
445					:get,
446					EMPromise.resolve(11),
447					["jmp_invite_tries-test"]
448				)
449				Registration::Payment::InviteCode::COMMAND_MANAGER.expect(
450					:write,
451					EMPromise.resolve(
452						Blather::Stanza::Iq::Command.new.tap { |iq|
453							iq.form.fields = [{ var: "code", value: "abc" }]
454						}
455					),
456					[Matching.new do |reply|
457						assert_equal :form, reply.form.type
458						assert_nil reply.form.instructions
459					end]
460				)
461				Registration::Payment::InviteCode::REDIS.expect(
462					:incr,
463					EMPromise.resolve(nil),
464					["jmp_invite_tries-test"]
465				)
466				Registration::Payment::InviteCode::REDIS.expect(
467					:expire,
468					EMPromise.resolve(nil),
469					["jmp_invite_tries-test", 60 * 60]
470				)
471				Registration::Payment::InviteCode::COMMAND_MANAGER.expect(
472					:write,
473					EMPromise.reject(Promise::Error.new),
474					[Matching.new do |reply|
475						assert_equal :form, reply.form.type
476						assert_equal "Too many wrong attempts", reply.form.instructions
477					end]
478				)
479				iq = Blather::Stanza::Iq::Command.new
480				iq.from = "test@example.com"
481				assert_raises Promise::Error do
482					Registration::Payment::InviteCode.new(
483						iq,
484						customer,
485						"+15555550000"
486					).write.sync
487				end
488				Registration::Payment::InviteCode::COMMAND_MANAGER.verify
489				Registration::Payment::InviteCode::REDIS.verify
490			end
491			em :test_write_bad_code_over_limit
492		end
493	end
494
495	class FinishTest < Minitest::Test
496		Registration::Finish::BLATHER = Minitest::Mock.new
497		Registration::Finish::REDIS = Minitest::Mock.new
498
499		def setup
500			@sgx = Minitest::Mock.new(BackendSgx.new("test"))
501			iq = Blather::Stanza::Iq::Command.new
502			iq.from = "test\\40example.com@cheogram.com"
503			@finish = Registration::Finish.new(
504				iq,
505				Customer.new("test", sgx: @sgx),
506				"+15555550000"
507			)
508		end
509
510		def test_write
511			create_order = stub_request(
512				:post,
513				"https://dashboard.bandwidth.com/v1.0/accounts//orders"
514			).to_return(status: 201, body: <<~RESPONSE)
515				<OrderResponse>
516					<Order>
517						<id>test_order</id>
518					</Order>
519				</OrderResponse>
520			RESPONSE
521			stub_request(
522				:get,
523				"https://dashboard.bandwidth.com/v1.0/accounts//orders/test_order"
524			).to_return(status: 201, body: <<~RESPONSE)
525				<OrderResponse>
526					<OrderStatus>COMPLETE</OrderStatus>
527					<CompletedNumbers>
528						<TelephoneNumber>
529							<FullNumber>5555550000</FullNumber>
530						</TelephoneNumber>
531					</CompletedNumbers>
532				</OrderResponse>
533			RESPONSE
534			stub_request(
535				:post,
536				"https://api.catapult.inetwork.com/v1/users/catapult_user/phoneNumbers"
537			).with(
538				body: open(__dir__ + "/data/catapult_import_body.json").read.chomp,
539				headers: {
540					"Authorization" => "Basic Y2F0YXB1bHRfdG9rZW46Y2F0YXB1bHRfc2VjcmV0",
541					"Content-Type" => "application/json"
542				}
543			).to_return(status: 201)
544			@sgx.expect(
545				:register!,
546				EMPromise.resolve(OpenStruct.new(error?: false)),
547				["+15555550000"]
548			)
549			Registration::Finish::REDIS.expect(
550				:set,
551				nil,
552				[
553					"catapult_fwd-+15555550000",
554					"sip:test%5C40example.com%40cheogram.com@sip.cheogram.com"
555				]
556			)
557			Registration::Finish::REDIS.expect(
558				:set,
559				nil,
560				["catapult_fwd_timeout-test\\40example.com@cheogram.com", 25]
561			)
562			Registration::Finish::BLATHER.expect(
563				:<<,
564				nil,
565				[Matching.new do |reply|
566					assert_equal :completed, reply.status
567					assert_equal :info, reply.note_type
568					assert_equal(
569						"Your JMP account has been activated as +15555550000",
570						reply.note.content
571					)
572				end]
573			)
574			@finish.write.sync
575			assert_requested create_order
576			@sgx.verify
577			Registration::Finish::REDIS.verify
578			Registration::Finish::BLATHER.verify
579		end
580		em :test_write
581
582		def test_write_tn_fail
583			create_order = stub_request(
584				:post,
585				"https://dashboard.bandwidth.com/v1.0/accounts//orders"
586			).to_return(status: 201, body: <<~RESPONSE)
587				<OrderResponse>
588					<Order>
589						<id>test_order</id>
590					</Order>
591				</OrderResponse>
592			RESPONSE
593			stub_request(
594				:get,
595				"https://dashboard.bandwidth.com/v1.0/accounts//orders/test_order"
596			).to_return(status: 201, body: <<~RESPONSE)
597				<OrderResponse>
598					<OrderStatus>FAILED</OrderStatus>
599				</OrderResponse>
600			RESPONSE
601			Registration::Finish::BLATHER.expect(
602				:<<,
603				nil,
604				[Matching.new do |reply|
605					assert_equal :completed, reply.status
606					assert_equal :error, reply.note_type
607					assert_equal(
608						"The JMP number +15555550000 is no longer available, " \
609						"please visit https://jmp.chat and choose another.",
610						reply.note.content
611					)
612				end]
613			)
614			@finish.write.sync
615			assert_requested create_order
616			Registration::Finish::BLATHER.verify
617		end
618		em :test_write_tn_fail
619	end
620end