# frozen_string_literal: true require "test_helper" require "customer" require "registration" def execute_command( iq=Blather::Stanza::Iq::Command.new.tap { |i| i.from = "test@example.com" }, blather: BLATHER, &blk ) Command::Execution.new( Minitest::Mock.new, blather, :to_s.to_proc, iq ).execute(&blk).sync end 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 = execute_command(iq) do Registration.for( customer(sgx: sgx), Minitest::Mock.new ) end assert_kind_of Registration::Registered, result end em :test_for_registered def test_for_activated web_manager = WebRegisterManager.new web_manager["test@example.net"] = "+15555550000" result = execute_command do sgx = OpenStruct.new(registered?: EMPromise.resolve(nil)) Registration.for( customer( plan_name: "test_usd", expires_at: Time.now + 999, sgx: sgx ), web_manager ) end 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.net"] = "+15555550000" iq = Blather::Stanza::Iq::Command.new iq.from = "test@example.com" result = execute_command(iq) do Registration.for( customer(sgx: sgx), web_manager ) end assert_kind_of Registration::Activation, result end em :test_for_not_activated_with_customer_id class ActivationTest < Minitest::Test Command::COMMAND_MANAGER = Minitest::Mock.new def setup @activation = Registration::Activation.new("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 Command::COMMAND_MANAGER.expect( :write, EMPromise.reject(:test_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, execute_command { @activation.write.catch { |e| e } } ) assert_mock Command::COMMAND_MANAGER end em :test_write end class PaymentTest < Minitest::Test Customer::BRAINTREE = Minitest::Mock.new def test_for_bitcoin cust = Minitest::Mock.new(customer) cust.expect( :add_btc_address, EMPromise.resolve("testaddr") ) 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, cust, "+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, "+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, "+15555550000" ) assert_kind_of Registration::Payment::InviteCode, result end class BitcoinTest < Minitest::Test Registration::Payment::Bitcoin::BTC_SELL_PRICES = Minitest::Mock.new Customer::REDIS = Minitest::Mock.new def setup @customer = Minitest::Mock.new( customer(plan_name: "test_usd") ) @customer.expect( :add_btc_address, EMPromise.resolve("testaddr") ) @bitcoin = Registration::Payment::Bitcoin.new( @customer, "+15555550000" ) end def test_write Customer::REDIS.expect( :smembers, EMPromise.resolve([]), ["jmp_customer_btc_addresses-test"] ) 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 blather = Minitest::Mock.new blather.expect( :<<, nil, [Matching.new do |reply| assert_equal :canceled, 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(1)) ) @bitcoin.stub(:save, EMPromise.resolve(nil)) do execute_command(blather: blather) do @bitcoin.write end end assert_mock blather end em :test_write end class CreditCardTest < Minitest::Test def setup @credit_card = Registration::Payment::CreditCard.new( customer, "+15555550000" ) end def test_for customer = Minitest::Mock.new(customer) customer.expect( :payment_methods, EMPromise.resolve(OpenStruct.new(default_payment_method: :test)) ) assert_kind_of( Registration::Payment::CreditCard::Activate, Registration::Payment::CreditCard.for( customer, "+15555550000" ).sync ) end em :test_for def test_write result = execute_command do Command::COMMAND_MANAGER.expect( :write, EMPromise.reject(:test_result), [Matching.new do |reply| assert_equal [:execute, :next], reply.allowed_actions assert_equal( "Add credit card, then return here to continue: " \ "http://creditcard.example.com", reply.note.content ) end] ) @credit_card.write.catch { |e| e } end assert_equal :test_result, result end em :test_write end class ActivateTest < Minitest::Test Registration::Payment::CreditCard::Activate::Finish = Minitest::Mock.new Registration::Payment::CreditCard::Activate::Transaction = Minitest::Mock.new Command::COMMAND_MANAGER = Minitest::Mock.new def test_write transaction = PromiseMock.new transaction.expect( :insert, EMPromise.resolve(nil) ) customer = Minitest::Mock.new( customer(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 customer.expect(:bill_plan, nil) Registration::Payment::CreditCard::Activate::Finish.expect( :new, OpenStruct.new(write: nil), [customer, "+15555550000"] ) execute_command do Registration::Payment::CreditCard::Activate.new( customer, :test_default_method, "+15555550000" ).write end 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(plan_name: "test_usd") ) iq = Blather::Stanza::Iq::Command.new iq.from = "test@example.com" Command::COMMAND_MANAGER.expect( :write, EMPromise.reject(:test_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] ) result = execute_command do 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 Registration::Payment::CreditCard::Activate.new( customer, :test_default_method, "+15555550000" ).write.catch { |e| e } end assert_equal :test_result, result 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 Command::COMMAND_MANAGER = Minitest::Mock.new Registration::Payment::InviteCode::Finish = Minitest::Mock.new def test_write customer = customer(plan_name: "test_usd") Registration::Payment::InviteCode::DB.expect(:transaction, true, []) Registration::Payment::InviteCode::Finish.expect( :new, OpenStruct.new(write: nil), [ customer, "+15555550000" ] ) execute_command do Registration::Payment::InviteCode::REDIS.expect( :get, EMPromise.resolve(nil), ["jmp_invite_tries-test"] ) Command::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.new( customer, "+15555550000" ).write end assert_mock Command::COMMAND_MANAGER assert_mock Registration::Payment::InviteCode::DB assert_mock Registration::Payment::InviteCode::REDIS assert_mock Registration::Payment::InviteCode::Finish end em :test_write def test_write_bad_code result = execute_command do customer = customer(plan_name: "test_usd") Registration::Payment::InviteCode::REDIS.expect( :get, EMPromise.resolve(0), ["jmp_invite_tries-test"] ) 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] ) Command::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] ) Command::COMMAND_MANAGER.expect( :write, EMPromise.reject(:test_result), [Matching.new do |reply| assert_equal :form, reply.form.type assert_equal "wut", reply.form.instructions end] ) Registration::Payment::InviteCode.new( customer, "+15555550000" ).write.catch { |e| e } end assert_equal :test_result, result assert_mock Command::COMMAND_MANAGER assert_mock Registration::Payment::InviteCode::DB assert_mock Registration::Payment::InviteCode::REDIS end em :test_write_bad_code def test_write_bad_code_over_limit result = execute_command do customer = customer(plan_name: "test_usd") Registration::Payment::InviteCode::REDIS.expect( :get, EMPromise.resolve(11), ["jmp_invite_tries-test"] ) Command::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] ) Command::COMMAND_MANAGER.expect( :write, EMPromise.reject(:test_result), [Matching.new do |reply| assert_equal :form, reply.form.type assert_equal "Too many wrong attempts", reply.form.instructions end] ) Registration::Payment::InviteCode.new( customer, "+15555550000" ).write.catch { |e| e } end assert_equal :test_result, result assert_mock Command::COMMAND_MANAGER assert_mock Registration::Payment::InviteCode::REDIS end em :test_write_bad_code_over_limit end end class FinishTest < Minitest::Test Registration::Finish::REDIS = Minitest::Mock.new BackendSgx::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( customer(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) Registration::Finish::REDIS.expect( :set, nil, [ "catapult_fwd-+15555550000", "sip:test%40example.net@sip.cheogram.com" ] ) BackendSgx::REDIS.expect( :set, nil, ["catapult_fwd_timeout-customer_test@component", 25] ) blather = Minitest::Mock.new 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] ) execute_command(blather: blather) do @sgx.expect( :register!, EMPromise.resolve(OpenStruct.new(error?: false)), ["+15555550000"] ) @finish.write end assert_requested create_order assert_mock @sgx assert_mock Registration::Finish::REDIS assert_mock BackendSgx::REDIS assert_mock blather 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 blather = Minitest::Mock.new 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] ) execute_command(blather: blather) { @finish.write } assert_requested create_order assert_mock blather end em :test_write_tn_fail end end