# frozen_string_literal: true require "test_helper" require "customer" require "registration" class RegistrationTest < Minitest::Test def test_for_registered sgx = OpenStruct.new( registered?: EMPromise.resolve(OpenStruct.new(phone: "+15555550000")) ) iq = Blather::Stanza::Iq::Command.new iq.from = "test@example.com" result = Registration.for( iq, Customer.new("test", sgx: sgx), Minitest::Mock.new ).sync assert_kind_of Registration::Registered, result end em :test_for_registered def test_for_activated sgx = OpenStruct.new(registered?: EMPromise.resolve(nil)) web_manager = WebRegisterManager.new web_manager["test@example.com"] = "+15555550000" iq = Blather::Stanza::Iq::Command.new iq.from = "test@example.com" result = Registration.for( iq, Customer.new( "test", plan_name: "test_usd", expires_at: Time.now + 999, sgx: sgx ), web_manager ).sync assert_kind_of Registration::Finish, result end em :test_for_activated def test_for_not_activated_with_customer_id sgx = OpenStruct.new(registered?: EMPromise.resolve(nil)) web_manager = WebRegisterManager.new web_manager["test@example.com"] = "+15555550000" iq = Blather::Stanza::Iq::Command.new iq.from = "test@example.com" result = Registration.for( iq, Customer.new("test", sgx: sgx), web_manager ).sync assert_kind_of Registration::Activation, result end em :test_for_not_activated_with_customer_id class ActivationTest < Minitest::Test Registration::Activation::COMMAND_MANAGER = Minitest::Mock.new def setup iq = Blather::Stanza::Iq::Command.new @activation = Registration::Activation.new(iq, "test", "+15555550000") end def test_write stub_request( :get, "https://dashboard.bandwidth.com/v1.0/tns/+15555550000" ).to_return(status: 201, body: <<~RESPONSE) 5555550000 RESPONSE stub_request( :get, "https://dashboard.bandwidth.com/v1.0/tns/5555550000/ratecenter" ).to_return(status: 201, body: <<~RESPONSE) KE FA RESPONSE result = Minitest::Mock.new result.expect(:then, result) result.expect(:then, EMPromise.resolve(:test_result)) Registration::Activation::COMMAND_MANAGER.expect( :write, result, [Matching.new do |iq| assert_equal :form, iq.form.type assert_equal( "You've selected +15555550000 (FA, KE) as your JMP number", iq.form.instructions ) end] ) assert_equal :test_result, @activation.write.sync end em :test_write end class PaymentTest < Minitest::Test Customer::BRAINTREE = Minitest::Mock.new Registration::Payment::Bitcoin::ELECTRUM = Minitest::Mock.new def test_for_bitcoin Registration::Payment::Bitcoin::ELECTRUM.expect(:createnewaddress, "addr") iq = Blather::Stanza::Iq::Command.new iq.form.fields = [ { var: "activation_method", value: "bitcoin" }, { var: "plan_name", value: "test_usd" } ] result = Registration::Payment.for( iq, Customer.new("test"), "+15555550000" ) assert_kind_of Registration::Payment::Bitcoin, result end def test_for_credit_card braintree_customer = Minitest::Mock.new Customer::BRAINTREE.expect( :customer, braintree_customer ) braintree_customer.expect( :find, EMPromise.resolve(OpenStruct.new(payment_methods: [])), ["test"] ) iq = Blather::Stanza::Iq::Command.new iq.from = "test@example.com" iq.form.fields = [ { var: "activation_method", value: "credit_card" }, { var: "plan_name", value: "test_usd" } ] result = Registration::Payment.for( iq, Customer.new("test"), "+15555550000" ).sync assert_kind_of Registration::Payment::CreditCard, result end em :test_for_credit_card def test_for_code iq = Blather::Stanza::Iq::Command.new iq.form.fields = [ { var: "activation_method", value: "code" }, { var: "plan_name", value: "test_usd" } ] result = Registration::Payment.for( iq, Customer.new("test"), "+15555550000" ) assert_kind_of Registration::Payment::InviteCode, result end class BitcoinTest < Minitest::Test Registration::Payment::Bitcoin::BTC_SELL_PRICES = Minitest::Mock.new Registration::Payment::Bitcoin::BLATHER = Minitest::Mock.new Customer::REDIS = Minitest::Mock.new Customer::ELECTRUM = Minitest::Mock.new def setup Customer::ELECTRUM.expect( :createnewaddress, EMPromise.resolve("testaddr") ) iq = Blather::Stanza::Iq::Command.new @bitcoin = Registration::Payment::Bitcoin.new( iq, Customer.new("test", plan_name: "test_usd"), "+15555550000" ) end def test_write Customer::REDIS.expect( :smembers, EMPromise.resolve([]), ["jmp_customer_btc_addresses-test"] ) Customer::REDIS.expect( :sadd, EMPromise.resolve(1), ["jmp_customer_btc_addresses-test", "testaddr"] ) reply_text = <<~NOTE Activate your account by sending at least 1.000000 BTC to testaddr You will receive a notification when your payment is complete. NOTE Registration::Payment::Bitcoin::BLATHER.expect( :<<, nil, [Matching.new do |reply| assert_equal :completed, reply.status assert_equal :info, reply.note_type assert_equal reply_text, reply.note.content true end] ) Registration::Payment::Bitcoin::BTC_SELL_PRICES.expect( :usd, EMPromise.resolve(BigDecimal.new(1)) ) @bitcoin.stub(:save, EMPromise.resolve(nil)) do @bitcoin.write.sync end Registration::Payment::Bitcoin::BLATHER.verify end em :test_write end class CreditCardTest < Minitest::Test def setup @iq = Blather::Stanza::Iq::Command.new @iq.from = "test@example.com" @credit_card = Registration::Payment::CreditCard.new( @iq, Customer.new("test"), "+15555550000" ) end def test_for customer = Minitest::Mock.new(Customer.new("test")) customer.expect( :payment_methods, EMPromise.resolve(OpenStruct.new(default_payment_method: :test)) ) assert_kind_of( Registration::Payment::CreditCard::Activate, Registration::Payment::CreditCard.for( @iq, customer, "+15555550000" ).sync ) end em :test_for def test_reply assert_equal [:execute, :next], @credit_card.reply.allowed_actions assert_equal( "Add credit card, then return here and choose next: " \ "http://creditcard.example.com", @credit_card.reply.note.content ) end end class ActivateTest < Minitest::Test Registration::Payment::CreditCard::Activate::Finish = Minitest::Mock.new Registration::Payment::CreditCard::Activate::Transaction = Minitest::Mock.new Registration::Payment::CreditCard::Activate::COMMAND_MANAGER = Minitest::Mock.new def test_write transaction = PromiseMock.new transaction.expect( :insert, EMPromise.resolve(nil) ) customer = Minitest::Mock.new( Customer.new("test", plan_name: "test_usd") ) Registration::Payment::CreditCard::Activate::Transaction.expect( :sale, transaction ) do |acustomer, amount:, payment_method:| assert_operator customer, :===, acustomer assert_equal CONFIG[:activation_amount], amount assert_equal :test_default_method, payment_method end iq = Blather::Stanza::Iq::Command.new customer.expect(:bill_plan, nil) Registration::Payment::CreditCard::Activate::Finish.expect( :new, OpenStruct.new(write: nil), [Blather::Stanza::Iq, customer, "+15555550000"] ) Registration::Payment::CreditCard::Activate.new( iq, customer, :test_default_method, "+15555550000" ).write.sync Registration::Payment::CreditCard::Activate::Transaction.verify transaction.verify customer.verify Registration::Payment::CreditCard::Activate::Finish.verify end em :test_write def test_write_declines customer = Minitest::Mock.new( Customer.new("test", plan_name: "test_usd") ) Registration::Payment::CreditCard::Activate::Transaction.expect( :sale, EMPromise.reject("declined") ) do |acustomer, amount:, payment_method:| assert_operator customer, :===, acustomer assert_equal CONFIG[:activation_amount], amount assert_equal :test_default_method, payment_method end iq = Blather::Stanza::Iq::Command.new iq.from = "test@example.com" result = Minitest::Mock.new result.expect(:then, nil) Registration::Payment::CreditCard::Activate::COMMAND_MANAGER.expect( :write, result, [Matching.new do |reply| assert_equal :error, reply.note_type assert_equal( Registration::Payment::CreditCard::Activate::DECLINE_MESSAGE + ": http://creditcard.example.com", reply.note.content ) end] ) Registration::Payment::CreditCard::Activate.new( iq, customer, :test_default_method, "+15555550000" ).write.sync Registration::Payment::CreditCard::Activate::Transaction.verify end em :test_write_declines end class InviteCodeTest < Minitest::Test Registration::Payment::InviteCode::DB = Minitest::Mock.new Registration::Payment::InviteCode::REDIS = Minitest::Mock.new Registration::Payment::InviteCode::COMMAND_MANAGER = Minitest::Mock.new Registration::Payment::InviteCode::Finish = Minitest::Mock.new def test_write customer = Customer.new("test", plan_name: "test_usd") Registration::Payment::InviteCode::REDIS.expect( :get, EMPromise.resolve(0), ["jmp_invite_tries-test"] ) Registration::Payment::InviteCode::COMMAND_MANAGER.expect( :write, EMPromise.resolve( Blather::Stanza::Iq::Command.new.tap { |iq| iq.form.fields = [{ var: "code", value: "abc" }] } ), [Matching.new do |reply| assert_equal :form, reply.form.type assert_nil reply.form.instructions end] ) Registration::Payment::InviteCode::DB.expect(:transaction, true, []) Registration::Payment::InviteCode::Finish.expect( :new, OpenStruct.new(write: nil), [ Blather::Stanza::Iq::Command, customer, "+15555550000" ] ) iq = Blather::Stanza::Iq::Command.new iq.from = "test@example.com" Registration::Payment::InviteCode.new( iq, customer, "+15555550000" ).write.sync Registration::Payment::InviteCode::COMMAND_MANAGER.verify Registration::Payment::InviteCode::DB.verify Registration::Payment::InviteCode::REDIS.verify Registration::Payment::InviteCode::Finish.verify end em :test_write def test_write_bad_code customer = Customer.new("test", plan_name: "test_usd") Registration::Payment::InviteCode::REDIS.expect( :get, EMPromise.resolve(0), ["jmp_invite_tries-test"] ) Registration::Payment::InviteCode::COMMAND_MANAGER.expect( :write, EMPromise.resolve( Blather::Stanza::Iq::Command.new.tap { |iq| iq.form.fields = [{ var: "code", value: "abc" }] } ), [Matching.new do |reply| assert_equal :form, reply.form.type assert_nil reply.form.instructions end] ) Registration::Payment::InviteCode::DB.expect(:transaction, []) do raise Registration::Payment::InviteCode::Invalid, "wut" end Registration::Payment::InviteCode::REDIS.expect( :incr, EMPromise.resolve(nil), ["jmp_invite_tries-test"] ) Registration::Payment::InviteCode::REDIS.expect( :expire, EMPromise.resolve(nil), ["jmp_invite_tries-test", 60 * 60] ) Registration::Payment::InviteCode::COMMAND_MANAGER.expect( :write, EMPromise.reject(Promise::Error.new), [Matching.new do |reply| assert_equal :form, reply.form.type assert_equal "wut", reply.form.instructions end] ) iq = Blather::Stanza::Iq::Command.new iq.from = "test@example.com" assert_raises Promise::Error do Registration::Payment::InviteCode.new( iq, customer, "+15555550000" ).write.sync end Registration::Payment::InviteCode::COMMAND_MANAGER.verify Registration::Payment::InviteCode::DB.verify Registration::Payment::InviteCode::REDIS.verify end em :test_write_bad_code def test_write_bad_code_over_limit customer = Customer.new("test", plan_name: "test_usd") Registration::Payment::InviteCode::REDIS.expect( :get, EMPromise.resolve(11), ["jmp_invite_tries-test"] ) Registration::Payment::InviteCode::COMMAND_MANAGER.expect( :write, EMPromise.resolve( Blather::Stanza::Iq::Command.new.tap { |iq| iq.form.fields = [{ var: "code", value: "abc" }] } ), [Matching.new do |reply| assert_equal :form, reply.form.type assert_nil reply.form.instructions end] ) Registration::Payment::InviteCode::REDIS.expect( :incr, EMPromise.resolve(nil), ["jmp_invite_tries-test"] ) Registration::Payment::InviteCode::REDIS.expect( :expire, EMPromise.resolve(nil), ["jmp_invite_tries-test", 60 * 60] ) Registration::Payment::InviteCode::COMMAND_MANAGER.expect( :write, EMPromise.reject(Promise::Error.new), [Matching.new do |reply| assert_equal :form, reply.form.type assert_equal "Too many wrong attempts", reply.form.instructions end] ) iq = Blather::Stanza::Iq::Command.new iq.from = "test@example.com" assert_raises Promise::Error do Registration::Payment::InviteCode.new( iq, customer, "+15555550000" ).write.sync end Registration::Payment::InviteCode::COMMAND_MANAGER.verify Registration::Payment::InviteCode::REDIS.verify end em :test_write_bad_code_over_limit end end class FinishTest < Minitest::Test Registration::Finish::BLATHER = Minitest::Mock.new Registration::Finish::REDIS = Minitest::Mock.new def setup @sgx = Minitest::Mock.new(BackendSgx.new("test")) iq = Blather::Stanza::Iq::Command.new iq.from = "test\\40example.com@cheogram.com" @finish = Registration::Finish.new( iq, Customer.new("test", sgx: @sgx), "+15555550000" ) end def test_write create_order = stub_request( :post, "https://dashboard.bandwidth.com/v1.0/accounts//orders" ).to_return(status: 201, body: <<~RESPONSE) test_order RESPONSE stub_request( :get, "https://dashboard.bandwidth.com/v1.0/accounts//orders/test_order" ).to_return(status: 201, body: <<~RESPONSE) COMPLETE 5555550000 RESPONSE stub_request( :post, "https://api.catapult.inetwork.com/v1/users/catapult_user/phoneNumbers" ).with( body: open(__dir__ + "/data/catapult_import_body.json").read.chomp, headers: { "Authorization" => "Basic Y2F0YXB1bHRfdG9rZW46Y2F0YXB1bHRfc2VjcmV0", "Content-Type" => "application/json" } ).to_return(status: 201) @sgx.expect( :register!, EMPromise.resolve(OpenStruct.new(error?: false)), ["+15555550000"] ) Registration::Finish::REDIS.expect( :set, nil, [ "catapult_fwd-+15555550000", "sip:test%5C40example.com%40cheogram.com@sip.cheogram.com" ] ) Registration::Finish::REDIS.expect( :set, nil, ["catapult_fwd_timeout-test\\40example.com@cheogram.com", 25] ) Registration::Finish::BLATHER.expect( :<<, nil, [Matching.new do |reply| assert_equal :completed, reply.status assert_equal :info, reply.note_type assert_equal( "Your JMP account has been activated as +15555550000", reply.note.content ) end] ) @finish.write.sync assert_requested create_order @sgx.verify Registration::Finish::REDIS.verify Registration::Finish::BLATHER.verify end em :test_write def test_write_tn_fail create_order = stub_request( :post, "https://dashboard.bandwidth.com/v1.0/accounts//orders" ).to_return(status: 201, body: <<~RESPONSE) test_order RESPONSE stub_request( :get, "https://dashboard.bandwidth.com/v1.0/accounts//orders/test_order" ).to_return(status: 201, body: <<~RESPONSE) FAILED RESPONSE Registration::Finish::BLATHER.expect( :<<, nil, [Matching.new do |reply| assert_equal :completed, reply.status assert_equal :error, reply.note_type assert_equal( "The JMP number +15555550000 is no longer available, " \ "please visit https://jmp.chat and choose another.", reply.note.content ) end] ) @finish.write.sync assert_requested create_order Registration::Finish::BLATHER.verify end em :test_write_tn_fail end end