test_registration.rb

   1# frozen_string_literal: true
   2
   3require "test_helper"
   4require "customer"
   5require "registration"
   6
   7BandwidthTnReservationRepo::REDIS = FakeRedis.new
   8
   9class RegistrationTest < Minitest::Test
  10	def test_for_registered
  11		sgx = OpenStruct.new(
  12			registered?: OpenStruct.new(phone: "+15555550000")
  13		)
  14		iq = Blather::Stanza::Iq::Command.new
  15		iq.from = "test@example.com"
  16		result = execute_command(iq) do
  17			Registration.for(
  18				customer(sgx: sgx),
  19				nil,
  20				Minitest::Mock.new
  21			)
  22		end
  23		assert_kind_of Registration::Registered, result
  24	end
  25	em :test_for_registered
  26
  27	def test_for_activated
  28		reservation_req = stub_request(
  29			:post,
  30			"https://dashboard.bandwidth.com/v1.0/accounts//tnreservation"
  31		).to_return(
  32			status: 201,
  33			headers: {
  34				location: "https://dashboard.bandwidth.com/api/accounts//TnReservation/8da0f39c-043c-4806-9f0f-497b2d197bc5"
  35			}
  36		)
  37		stub_request(
  38			:get, "https://dashboard.bandwidth.com/v1.0/accounts//tnreservation/8da0f39c-043c-4806-9f0f-497b2d197bc5"
  39		).to_return(status: 200, body: <<~RESPONSE)
  40			<ReservationResponse>
  41				<Reservation>
  42					<ReservationId>f342904f-b03a-4499-bac0-e8f43a2664a1</ReservationId>
  43					<AccountId>12346099</AccountId>
  44					<ReservationExpires>1492</ReservationExpires>
  45					<ReservedTn>4354776010</ReservedTn>
  46				</Reservation>
  47			</ReservationResponse>
  48		RESPONSE
  49		web_manager = TelSelections.new(
  50			redis: FakeRedis.new, db: FakeDB.new, memcache: FakeMemcache.new
  51		)
  52		web_manager.set(
  53			"test@example.net",
  54			TelSelections::ChooseTel::Tn.for_pending_value("+15555550000")
  55		)
  56		result = execute_command do
  57			sgx = OpenStruct.new(registered?: false)
  58			Registration.for(
  59				customer(
  60					plan_name: "test_usd",
  61					expires_at: Time.now + 999,
  62					sgx: sgx
  63				),
  64				nil,
  65				web_manager
  66			)
  67		end
  68		assert_kind_of Registration::Finish, result
  69		assert_requested reservation_req
  70	end
  71	em :test_for_activated
  72
  73	def test_for_not_activated_approved
  74		sgx = OpenStruct.new(registered?: false)
  75		web_manager = TelSelections.new(
  76			redis: FakeRedis.new, db: FakeDB.new, memcache: FakeMemcache.new
  77		)
  78		web_manager.set(
  79			"test\\40approved.example.com@component",
  80			TelSelections::ChooseTel::Tn.for_pending_value("+15555550000")
  81		)
  82		iq = Blather::Stanza::Iq::Command.new
  83		iq.from = "test@approved.example.com"
  84		result = execute_command(iq) do
  85			Registration::Activation.for(
  86				customer(
  87					sgx: sgx,
  88					jid: Blather::JID.new("test\\40approved.example.com@component")
  89				),
  90				nil,
  91				web_manager
  92			)
  93		end
  94		assert_kind_of Registration::Activation::Allow, result
  95	end
  96	em :test_for_not_activated_approved
  97
  98	def test_for_not_activated_googleplay
  99		sgx = OpenStruct.new(registered?: false)
 100		web_manager = TelSelections.new(
 101			redis: FakeRedis.new, db: FakeDB.new, memcache: FakeMemcache.new
 102		)
 103		web_manager.set(
 104			"test@example.net",
 105			TelSelections::ChooseTel::Tn.for_pending_value("+15555550000")
 106		)
 107		iq = Blather::Stanza::Iq::Command.new
 108		iq.from = "test@approved.example.com"
 109		result = execute_command(iq) do
 110			Registration::Activation.for(
 111				customer(sgx: sgx),
 112				"GARBLEDYGOOK==",
 113				web_manager
 114			)
 115		end
 116		assert_kind_of Registration::Activation::GooglePlay, result
 117	end
 118	em :test_for_not_activated_googleplay
 119
 120	def test_for_not_activated_with_customer_id
 121		sgx = OpenStruct.new(registered?: false)
 122		web_manager = TelSelections.new(
 123			redis: FakeRedis.new, db: FakeDB.new, memcache: FakeMemcache.new
 124		)
 125		web_manager.set(
 126			"test@example.net",
 127			TelSelections::ChooseTel::Tn.for_pending_value("+15555550000")
 128		)
 129		iq = Blather::Stanza::Iq::Command.new
 130		iq.from = "test@example.com"
 131		result = execute_command(iq) do
 132			Registration::Activation.for(
 133				customer(sgx: sgx),
 134				nil,
 135				web_manager
 136			)
 137		end
 138		assert_kind_of Registration::Activation, result
 139	end
 140	em :test_for_not_activated_with_customer_id
 141
 142	class ActivationTest < Minitest::Test
 143		Registration::Activation::DB = Minitest::Mock.new
 144		Registration::Activation::REDIS = FakeRedis.new(
 145			"jmp_parent_codes" => {
 146				"PARENT_CODE" => "1",
 147				"PARENT_TOMB" => "2",
 148				"PARENT_MANY_SUBACCOUNTS" => "many_subaccounts"
 149			},
 150			"jmp_customer_trust_level-2" => "Tomb"
 151		)
 152		Registration::Activation::Payment = Minitest::Mock.new
 153		Registration::Activation::Finish = Minitest::Mock.new
 154		Command::COMMAND_MANAGER = Minitest::Mock.new
 155
 156		def setup
 157			@customer = Minitest::Mock.new(customer)
 158			@activation = Registration::Activation.new(@customer, "+15555550000")
 159		end
 160
 161		def test_write
 162			Command::COMMAND_MANAGER.expect(
 163				:write,
 164				EMPromise.resolve(Blather::Stanza::Iq::Command.new.tap { |iq|
 165					iq.form.fields = [{ var: "plan_name", value: "test_usd" }]
 166				}),
 167				[Matching.new do |iq|
 168					assert_equal :form, iq.form.type
 169					assert_equal(
 170						"You've selected +15555550000 as your JMP number.",
 171						iq.form.instructions.lines.first.chomp
 172					)
 173				end]
 174			)
 175			@customer.expect(:with_plan, @customer) do |*args, **|
 176				assert_equal ["test_usd"], args
 177			end
 178			@customer.expect(:save_plan!, EMPromise.resolve(nil), [])
 179			Registration::Activation::Payment.expect(
 180				:for,
 181				EMPromise.reject(:test_result),
 182				[Blather::Stanza::Iq, @customer, "+15555550000"]
 183			)
 184			assert_equal(
 185				:test_result,
 186				execute_command { @activation.write.catch { |e| e } }
 187			)
 188			assert_mock Command::COMMAND_MANAGER
 189			assert_mock @customer
 190			assert_mock Registration::Activation::Payment
 191		end
 192		em :test_write
 193
 194		def test_write_bad_plan
 195			Command::COMMAND_MANAGER.expect(
 196				:write,
 197				EMPromise.resolve(Blather::Stanza::Iq::Command.new.tap { |iq|
 198					iq.form.fields = [{ var: "plan_name", value: "test_usd_no_register" }]
 199				}),
 200				[Matching.new do |iq|
 201					assert_equal :form, iq.form.type
 202					assert_equal(
 203						"You've selected +15555550000 as your JMP number.",
 204						iq.form.instructions.lines.first.chomp
 205					)
 206				end]
 207			)
 208			assert_equal(
 209				"No registration plan by that name",
 210				execute_command { @activation.write.catch { |e| e } }.message
 211			)
 212			assert_mock Command::COMMAND_MANAGER
 213			assert_mock @customer
 214		end
 215		em :test_write_bad_plan
 216
 217		def test_write_with_code
 218			Command::COMMAND_MANAGER.expect(
 219				:write,
 220				EMPromise.resolve(Blather::Stanza::Iq::Command.new.tap { |iq|
 221					iq.form.fields = [
 222						{ var: "plan_name", value: "test_usd" },
 223						{ var: "code", value: "123" }
 224					]
 225				}),
 226				[Matching.new do |iq|
 227					assert_equal :form, iq.form.type
 228					assert_equal(
 229						"You've selected +15555550000 as your JMP number.",
 230						iq.form.instructions.lines.first.chomp
 231					)
 232				end]
 233			)
 234			@customer.expect(:with_plan, @customer) do |*args, **|
 235				assert_equal ["test_usd"], args
 236			end
 237			@customer.expect(:save_plan!, EMPromise.resolve(nil), [])
 238			@customer.expect(:activate_plan_starting_now, EMPromise.resolve(nil), [])
 239			Registration::Activation::DB.expect(:transaction, []) { |&blk| blk.call }
 240			Registration::Activation::DB.expect(
 241				:exec,
 242				OpenStruct.new(cmd_tuples: 1),
 243				[String, ["test", "123"]]
 244			)
 245			Registration::Activation::Finish.expect(
 246				:new,
 247				OpenStruct.new(write: EMPromise.reject(:test_result)),
 248				[@customer, "+15555550000"]
 249			)
 250			assert_equal(
 251				:test_result,
 252				execute_command { @activation.write.catch { |e| e } }
 253			)
 254			assert_mock Command::COMMAND_MANAGER
 255			assert_mock @customer
 256			assert_mock Registration::Activation::Payment
 257			assert_mock Registration::Activation::DB
 258		end
 259		em :test_write_with_code
 260
 261		def test_write_with_group_code
 262			Command::COMMAND_MANAGER.expect(
 263				:write,
 264				EMPromise.resolve(Blather::Stanza::Iq::Command.new.tap { |iq|
 265					iq.form.fields = [
 266						{ var: "plan_name", value: "test_usd" },
 267						{ var: "code", value: "123" }
 268					]
 269				}),
 270				[Matching.new do |iq|
 271					assert_equal :form, iq.form.type
 272					assert_equal(
 273						"You've selected +15555550000 as your JMP number.",
 274						iq.form.instructions.lines.first.chomp
 275					)
 276				end]
 277			)
 278			@customer.expect(:with_plan, @customer) do |*args, **|
 279				assert_equal ["test_usd"], args
 280			end
 281			@customer.expect(:save_plan!, EMPromise.resolve(nil), [])
 282			Registration::Activation::DB.expect(:transaction, []) { |&blk| blk.call }
 283			Registration::Activation::DB.expect(
 284				:exec,
 285				OpenStruct.new(cmd_tuples: 0),
 286				[String, ["test", "123"]]
 287			)
 288			Registration::Activation::Payment.expect(
 289				:for,
 290				EMPromise.reject(:test_result),
 291				[Blather::Stanza::Iq, @customer, "+15555550000"]
 292			)
 293			assert_equal(
 294				:test_result,
 295				execute_command { @activation.write.catch { |e| e } }
 296			)
 297			assert_equal(
 298				"123",
 299				Registration::Activation::REDIS.get(
 300					"jmp_customer_pending_invite-test"
 301				).sync
 302			)
 303			assert_mock Command::COMMAND_MANAGER
 304			assert_mock @customer
 305			assert_mock Registration::Activation::Payment
 306			assert_mock Registration::Activation::DB
 307		end
 308		em :test_write_with_group_code
 309
 310		def test_write_with_parent_code
 311			Command::COMMAND_MANAGER.expect(
 312				:write,
 313				EMPromise.resolve(Blather::Stanza::Iq::Command.new.tap { |iq|
 314					iq.form.fields = [
 315						{ var: "plan_name", value: "test_usd" },
 316						{ var: "code", value: "PARENT_CODE" }
 317					]
 318				}),
 319				[Matching.new do |iq|
 320					assert_equal :form, iq.form.type
 321					assert_equal(
 322						"You've selected +15555550000 as your JMP number.",
 323						iq.form.instructions.lines.first.chomp
 324					)
 325				end]
 326			)
 327			Registration::Activation::DB.expect(
 328				:query_one, {}, [String, "1"], default: {}
 329			)
 330			Registration::Activation::DB.expect(
 331				:query_one, { c: 0 }, [String, "1"], default: { c: 0 }
 332			)
 333			@customer.expect(:with_plan, @customer) do |*args, **kwargs|
 334				assert_equal ["test_usd"], args
 335				assert_equal({ parent_customer_id: "1" }, kwargs)
 336			end
 337			@customer.expect(:save_plan!, EMPromise.resolve(nil), [])
 338			Registration::Activation::DB.expect(:transaction, []) { |&blk| blk.call }
 339			Registration::Activation::DB.expect(
 340				:exec,
 341				OpenStruct.new(cmd_tuples: 0),
 342				[String, ["test", "PARENT_CODE"]]
 343			)
 344			Registration::Activation::Payment.expect(
 345				:for,
 346				EMPromise.reject(:test_result),
 347				[Blather::Stanza::Iq, @customer, "+15555550000"]
 348			)
 349			assert_equal(
 350				:test_result,
 351				execute_command { @activation.write.catch { |e| e } }
 352			)
 353			assert_mock Command::COMMAND_MANAGER
 354			assert_mock @customer
 355			assert_mock Registration::Activation::Payment
 356			assert_mock Registration::Activation::DB
 357		end
 358		em :test_write_with_parent_code
 359
 360		def test_write_with_parent_code_tombed_parent
 361			Command::COMMAND_MANAGER.expect(
 362				:write,
 363				EMPromise.resolve(Blather::Stanza::Iq::Command.new.tap { |iq|
 364					iq.form.fields = [
 365						{ var: "plan_name", value: "test_usd" },
 366						{ var: "code", value: "PARENT_TOMB" }
 367					]
 368				}),
 369				[Matching.new do |iq|
 370					assert_equal :form, iq.form.type
 371					assert_equal(
 372						"You've selected +15555550000 as your JMP number.",
 373						iq.form.instructions.lines.first.chomp
 374					)
 375				end]
 376			)
 377			Registration::Activation::DB.expect(
 378				:query_one, {}, [String, "2"], default: {}
 379			)
 380			Registration::Activation::DB.expect(
 381				:query_one, { c: 0 }, [String, "2"], default: { c: 0 }
 382			)
 383			assert_equal(
 384				"Please contact support to create a subaccount",
 385				execute_command { @activation.write.catch(&:to_s) }
 386			)
 387			assert_mock Command::COMMAND_MANAGER
 388			assert_mock @customer
 389			assert_mock Registration::Activation::Payment
 390			assert_mock Registration::Activation::DB
 391		end
 392		em :test_write_with_parent_code_tombed_parent
 393
 394		def test_write_with_parent_code_too_many
 395			Command::COMMAND_MANAGER.expect(
 396				:write,
 397				EMPromise.resolve(Blather::Stanza::Iq::Command.new.tap { |iq|
 398					iq.form.fields = [
 399						{ var: "plan_name", value: "test_usd" },
 400						{ var: "code", value: "PARENT_MANY_SUBACCOUNTS" }
 401					]
 402				}),
 403				[Matching.new do |iq|
 404					assert_equal :form, iq.form.type
 405					assert_equal(
 406						"You've selected +15555550000 as your JMP number.",
 407						iq.form.instructions.lines.first.chomp
 408					)
 409				end]
 410			)
 411			Registration::Activation::DB.expect(
 412				:query_one, {}, [String, "many_subaccounts"], default: {}
 413			)
 414			Registration::Activation::DB.expect(
 415				:query_one, { c: 2 }, [String, "many_subaccounts"], default: { c: 0 }
 416			)
 417			assert_equal(
 418				"Please contact support to create a subaccount",
 419				execute_command { @activation.write.catch(&:to_s) }
 420			)
 421			assert_mock Command::COMMAND_MANAGER
 422			assert_mock @customer
 423			assert_mock Registration::Activation::Payment
 424			assert_mock Registration::Activation::DB
 425		end
 426		em :test_write_with_parent_code_too_many
 427	end
 428
 429	class AllowTest < Minitest::Test
 430		Command::COMMAND_MANAGER = Minitest::Mock.new
 431		Registration::Activation::Allow::DB = Minitest::Mock.new
 432
 433		def test_write_credit_to_nil
 434			cust = Minitest::Mock.new(customer("test"))
 435			allow = Registration::Activation::Allow.new(cust, "+15555550000", nil)
 436
 437			Command::COMMAND_MANAGER.expect(
 438				:write,
 439				EMPromise.resolve(Blather::Stanza::Iq::Command.new.tap { |iq|
 440					iq.form.fields = [{ var: "plan_name", value: "test_usd" }]
 441				}),
 442				[Matching.new do |iq|
 443					assert_equal :form, iq.form.type
 444					assert_equal(
 445						"You've selected +15555550000 as your JMP number.",
 446						iq.form.instructions.lines.first.chomp
 447					)
 448					assert_equal 1, iq.form.fields.length
 449				end]
 450			)
 451			Registration::Activation::Allow::DB.expect(
 452				:transaction,
 453				EMPromise.reject(:test_result)
 454			) do |&blk|
 455				blk.call
 456				true
 457			end
 458			cust.expect(:with_plan, cust, ["test_usd"])
 459			cust.expect(:activate_plan_starting_now, nil)
 460			assert_equal(
 461				:test_result,
 462				execute_command { allow.write.catch { |e| e } }
 463			)
 464			assert_mock Command::COMMAND_MANAGER
 465		end
 466		em :test_write_credit_to_nil
 467
 468		def test_write_credit_to_refercust
 469			cust = Minitest::Mock.new(customer("test"))
 470			allow = Registration::Activation::Allow.new(
 471				cust, "+15555550000", "refercust"
 472			)
 473
 474			Command::COMMAND_MANAGER.expect(
 475				:write,
 476				EMPromise.resolve(Blather::Stanza::Iq::Command.new.tap { |iq|
 477					iq.form.fields = [{ var: "plan_name", value: "test_usd" }]
 478				}),
 479				[Matching.new do |iq|
 480					assert_equal :form, iq.form.type
 481					assert_equal(
 482						"You've selected +15555550000 as your JMP number.",
 483						iq.form.instructions.lines.first.chomp
 484					)
 485					assert_equal 1, iq.form.fields.length
 486				end]
 487			)
 488			Registration::Activation::Allow::DB.expect(
 489				:transaction,
 490				EMPromise.reject(:test_result)
 491			) do |&blk|
 492				blk.call
 493				true
 494			end
 495			Registration::Activation::Allow::DB.expect(
 496				:exec,
 497				nil,
 498				[String, ["refercust", "test"]]
 499			)
 500			cust.expect(:with_plan, cust, ["test_usd"])
 501			cust.expect(:activate_plan_starting_now, nil)
 502			assert_equal(
 503				:test_result,
 504				execute_command { allow.write.catch { |e| e } }
 505			)
 506			assert_mock Command::COMMAND_MANAGER
 507		end
 508		em :test_write_credit_to_refercust
 509	end
 510
 511	class GooglePlayTest < Minitest::Test
 512		CustomerPlan::DB = Minitest::Mock.new
 513		Registration::Activation::GooglePlay::Finish = Minitest::Mock.new
 514
 515		def setup
 516			@customer = customer
 517			@google_play = Registration::Activation::GooglePlay.new(
 518				@customer,
 519				"abcd",
 520				"+15555550000"
 521			)
 522		end
 523
 524		def test_write
 525			Command::COMMAND_MANAGER.expect(
 526				:write,
 527				EMPromise.resolve(Blather::Stanza::Iq::Command.new.tap { |iq|
 528					iq.form.fields = [{ var: "plan_name", value: "test_usd" }]
 529				}),
 530				[Matching.new do |iq|
 531					assert_equal :form, iq.form.type
 532					assert_equal(
 533						"You've selected +15555550000 as your JMP number.",
 534						iq.form.instructions.lines.first.chomp
 535					)
 536				end]
 537			)
 538			CustomerPlan::DB.expect(
 539				:exec,
 540				OpenStruct.new(cmd_tuples: 1),
 541				[String, ["test", "test_usd", nil]]
 542			)
 543			CustomerPlan::DB.expect(
 544				:exec,
 545				OpenStruct.new(cmd_tuples: 0),
 546				[String, ["test"]]
 547			)
 548			Transaction::DB.expect(:transaction, true, [])
 549			Registration::Activation::GooglePlay::Finish.expect(
 550				:new,
 551				OpenStruct.new(write: EMPromise.reject(:test_result)),
 552				[Customer, "+15555550000"]
 553			)
 554			result = execute_command { @google_play.write.catch { |e| e } }
 555			assert_equal :test_result, result
 556			assert_mock Command::COMMAND_MANAGER
 557			assert_mock CustomerPlan::DB
 558			assert_mock Transaction::DB
 559			assert_mock Registration::Activation::GooglePlay::Finish
 560		end
 561		em :test_write
 562	end
 563
 564	class PaymentTest < Minitest::Test
 565		CustomerFinancials::BRAINTREE = Minitest::Mock.new
 566
 567		def test_for_bitcoin
 568			iq = Blather::Stanza::Iq::Command.new
 569			iq.form.fields = [
 570				{ var: "activation_method", value: "bitcoin" },
 571				{ var: "plan_name", value: "test_usd" }
 572			]
 573			result = Registration::Payment.for(iq, customer, "+15555550000")
 574			assert_kind_of Registration::Payment::Bitcoin, result
 575		end
 576
 577		def test_for_bch
 578			iq = Blather::Stanza::Iq::Command.new
 579			iq.form.fields = [
 580				{ var: "activation_method", value: "bch" },
 581				{ var: "plan_name", value: "test_usd" }
 582			]
 583			result = Registration::Payment.for(iq, customer, "+15555550000")
 584			assert_kind_of Registration::Payment::BCH, result
 585		end
 586
 587		def test_for_credit_card
 588			braintree_customer = Minitest::Mock.new
 589			CustomerFinancials::BRAINTREE.expect(
 590				:customer,
 591				braintree_customer
 592			)
 593			CustomerFinancials::REDIS.expect(:smembers, [], ["block_credit_cards"])
 594			braintree_customer.expect(
 595				:find,
 596				EMPromise.resolve(OpenStruct.new(payment_methods: [])),
 597				["test"]
 598			)
 599			iq = Blather::Stanza::Iq::Command.new
 600			iq.from = "test@example.com"
 601			iq.form.fields = [
 602				{ var: "activation_method", value: "credit_card" },
 603				{ var: "plan_name", value: "test_usd" }
 604			]
 605			cust = customer
 606			result = execute_command do
 607				Command.execution.customer_repo.expect(:find, cust, ["test"])
 608				Registration::Payment.for(
 609					iq,
 610					cust,
 611					""
 612				).sync
 613			end
 614			assert_kind_of Registration::Payment::CreditCard, result
 615		end
 616		em :test_for_credit_card
 617
 618		def test_for_code
 619			iq = Blather::Stanza::Iq::Command.new
 620			iq.form.fields = [
 621				{ var: "activation_method", value: "code" },
 622				{ var: "plan_name", value: "test_usd" }
 623			]
 624			cust = customer
 625			result = execute_command do
 626				Command.execution.customer_repo.expect(:find, cust, ["test"])
 627				Registration::Payment.for(
 628					iq,
 629					cust,
 630					"+15555550000"
 631				)
 632			end
 633			assert_kind_of Registration::Payment::InviteCode, result
 634		end
 635		em :test_for_code
 636
 637		class BitcoinTest < Minitest::Test
 638			Registration::Payment::Bitcoin::BTC_SELL_PRICES = Minitest::Mock.new
 639			CustomerFinancials::REDIS = Minitest::Mock.new
 640
 641			def setup
 642				@customer = Minitest::Mock.new(
 643					customer(plan_name: "test_usd")
 644				)
 645				@customer.expect(
 646					:add_btc_address,
 647					EMPromise.resolve("testaddr")
 648				)
 649				@bitcoin = Registration::Payment::Bitcoin.new(
 650					@customer,
 651					"+15555550000"
 652				)
 653			end
 654
 655			def test_write
 656				CustomerFinancials::REDIS.expect(
 657					:smembers,
 658					EMPromise.resolve([]),
 659					["jmp_customer_btc_addresses-test"]
 660				)
 661				blather = Minitest::Mock.new
 662				Command::COMMAND_MANAGER.expect(
 663					:write,
 664					EMPromise.reject(SessionManager::Timeout.new),
 665					[Matching.new do |reply|
 666						assert_equal :canceled, reply.status
 667						assert_equal "1.000000", reply.form.field("amount").value
 668						assert_equal "testaddr", reply.form.field("btc_addresses").value
 669						true
 670					end]
 671				)
 672				Registration::Payment::Bitcoin::BTC_SELL_PRICES.expect(
 673					:usd,
 674					EMPromise.resolve(BigDecimal(1))
 675				)
 676				@bitcoin.stub(:save, EMPromise.resolve(nil)) do
 677					execute_command(blather: blather) do
 678						@bitcoin.write
 679					end
 680				end
 681				assert_mock blather
 682			end
 683			em :test_write
 684		end
 685
 686		class BCHTest < Minitest::Test
 687			Registration::Payment::BCH::BCH_SELL_PRICES = Minitest::Mock.new
 688			CustomerFinancials::REDIS = Minitest::Mock.new
 689
 690			def setup
 691				@customer = Minitest::Mock.new(
 692					customer(plan_name: "test_usd")
 693				)
 694				@customer.expect(
 695					:add_bch_address,
 696					EMPromise.resolve("testaddr")
 697				)
 698				@bch = Registration::Payment::BCH.new(
 699					@customer,
 700					"+15555550000"
 701				)
 702			end
 703
 704			def test_write
 705				CustomerFinancials::REDIS.expect(
 706					:smembers,
 707					EMPromise.resolve([]),
 708					["jmp_customer_bch_addresses-test"]
 709				)
 710				blather = Minitest::Mock.new
 711				Command::COMMAND_MANAGER.expect(
 712					:write,
 713					EMPromise.reject(SessionManager::Timeout.new),
 714					[Matching.new do |reply|
 715						assert_equal :canceled, reply.status
 716						assert_equal "1.000000", reply.form.field("amount").value
 717						assert_equal "testaddr", reply.form.field("bch_addresses").value
 718						true
 719					end]
 720				)
 721				Registration::Payment::BCH::BCH_SELL_PRICES.expect(
 722					:usd,
 723					EMPromise.resolve(BigDecimal(1))
 724				)
 725				@bch.stub(:save, EMPromise.resolve(nil)) do
 726					execute_command(blather: blather) do
 727						@bch.write
 728					end
 729				end
 730				assert_mock blather
 731			end
 732			em :test_write
 733		end
 734
 735		class CreditCardTest < Minitest::Test
 736			def setup
 737				@credit_card = Registration::Payment::CreditCard.new(
 738					customer,
 739					"+15555550000"
 740				)
 741			end
 742
 743			def test_for
 744				cust = Minitest::Mock.new(customer)
 745				cust.expect(
 746					:payment_methods,
 747					EMPromise.resolve(OpenStruct.new(default_payment_method: :test))
 748				)
 749				execute_command do
 750					Command.execution.customer_repo.expect(:find, cust, ["test"])
 751					assert_kind_of(
 752						Registration::Payment::CreditCard::Activate,
 753						Registration::Payment::CreditCard.for(
 754							cust,
 755							"+15555550000"
 756						).sync
 757					)
 758				end
 759			end
 760			em :test_for
 761
 762			def test_for_has_balance
 763				cust = Minitest::Mock.new(customer)
 764				cust.expect(:balance, 100)
 765				cust.expect(:payment_methods, EMPromise.resolve(nil))
 766				execute_command do
 767					Command.execution.customer_repo.expect(:find, cust, ["test"])
 768					assert_kind_of(
 769						Registration::BillPlan,
 770						Registration::Payment::CreditCard.for(
 771							cust,
 772							"+15555550000"
 773						).sync
 774					)
 775				end
 776			end
 777			em :test_for_has_balance
 778
 779			def test_write
 780				result = execute_command do
 781					Command::COMMAND_MANAGER.expect(
 782						:write,
 783						EMPromise.reject(:test_result),
 784						[Matching.new do |reply|
 785							assert_equal [:execute, :next, :prev], reply.allowed_actions
 786							assert_equal(
 787								"Add credit card, save, then next here to continue: " \
 788								"http://creditcard.example.com?&amount=1",
 789								reply.note.content
 790							)
 791						end]
 792					)
 793
 794					@credit_card.write.catch { |e| e }
 795				end
 796
 797				assert_equal :test_result, result
 798			end
 799			em :test_write
 800		end
 801
 802		class MailTest < Minitest::Test
 803			def setup
 804				@mail = Registration::Payment::Mail.new(
 805					customer(plan_name: "test_cad"),
 806					"+15555550000"
 807				)
 808			end
 809
 810			def test_write
 811				result = execute_command do
 812					Command::COMMAND_MANAGER.expect(
 813						:write,
 814						EMPromise.reject(:test_result),
 815						[Matching.new do |reply|
 816							assert_equal [:execute, :prev], reply.allowed_actions
 817							refute reply.form.instructions.empty?
 818							assert_equal(
 819								"A Mailing Address",
 820								reply.form.field("adr").value
 821							)
 822							assert_equal(
 823								"interac@example.com",
 824								reply.form.field("interac_email").value
 825							)
 826						end]
 827					)
 828
 829					@mail.write.catch { |e| e }
 830				end
 831
 832				assert_equal :test_result, result
 833			end
 834			em :test_write
 835		end
 836
 837		class ActivateTest < Minitest::Test
 838			Registration::Payment::CreditCard::Activate::Finish =
 839				Minitest::Mock.new
 840			Registration::Payment::CreditCard::Activate::CreditCardSale =
 841				Minitest::Mock.new
 842			Command::COMMAND_MANAGER = Minitest::Mock.new
 843
 844			def test_write
 845				customer = Minitest::Mock.new(
 846					customer(plan_name: "test_usd")
 847				)
 848				Registration::Payment::CreditCard::Activate::CreditCardSale.expect(
 849					:create,
 850					EMPromise.resolve(nil)
 851				) do |acustomer, amount:, payment_method:|
 852					assert_operator customer, :===, acustomer
 853					assert_equal CONFIG[:activation_amount], amount
 854					assert_equal :test_default_method, payment_method
 855				end
 856				customer.expect(
 857					:bill_plan,
 858					nil,
 859					note: "Bill +15555550000 for first month"
 860				)
 861				Registration::Payment::CreditCard::Activate::Finish.expect(
 862					:new,
 863					OpenStruct.new(write: nil),
 864					[customer, "+15555550000"]
 865				)
 866				execute_command do
 867					Registration::Payment::CreditCard::Activate.new(
 868						customer,
 869						:test_default_method,
 870						"+15555550000"
 871					).write
 872				end
 873				Registration::Payment::CreditCard::Activate::CreditCardSale.verify
 874				customer.verify
 875				Registration::Payment::CreditCard::Activate::Finish.verify
 876			end
 877			em :test_write
 878
 879			def test_write_declines
 880				customer = Minitest::Mock.new(
 881					customer(plan_name: "test_usd")
 882				)
 883				iq = Blather::Stanza::Iq::Command.new
 884				iq.from = "test@example.com"
 885				msg = Registration::Payment::CreditCard::Activate::DECLINE_MESSAGE
 886				Command::COMMAND_MANAGER.expect(
 887					:write,
 888					EMPromise.reject(:test_result),
 889					[Matching.new do |reply|
 890						assert_equal :error, reply.note_type
 891						assert_equal(
 892							"#{msg}: http://creditcard.example.com?&amount=1",
 893							reply.note.content
 894						)
 895					end]
 896				)
 897				result = execute_command do
 898					Registration::Payment::CreditCard::Activate::CreditCardSale.expect(
 899						:create,
 900						EMPromise.reject("declined")
 901					) do |acustomer, amount:, payment_method:|
 902						assert_operator customer, :===, acustomer
 903						assert_equal CONFIG[:activation_amount], amount
 904						assert_equal :test_default_method, payment_method
 905					end
 906
 907					Registration::Payment::CreditCard::Activate.new(
 908						customer,
 909						:test_default_method,
 910						"+15555550000"
 911					).write.catch { |e| e }
 912				end
 913				assert_equal :test_result, result
 914				Registration::Payment::CreditCard::Activate::CreditCardSale.verify
 915			end
 916			em :test_write_declines
 917		end
 918
 919		class InviteCodeTest < Minitest::Test
 920			Registration::Payment::InviteCode::DB =
 921				Minitest::Mock.new
 922			Registration::Payment::InviteCode::REDIS =
 923				Minitest::Mock.new
 924			Command::COMMAND_MANAGER = Minitest::Mock.new
 925			Registration::Payment::InviteCode::Finish =
 926				Minitest::Mock.new
 927			Registration::Payment::InviteCode::BillPlan =
 928				Minitest::Mock.new
 929
 930			def test_write
 931				customer = customer(plan_name: "test_usd")
 932				Registration::Payment::InviteCode::DB.expect(:transaction, true, [])
 933				Registration::Payment::InviteCode::Finish.expect(
 934					:new,
 935					OpenStruct.new(write: nil),
 936					[
 937						customer,
 938						"+15555550000"
 939					]
 940				)
 941				execute_command do
 942					Registration::Payment::InviteCode::REDIS.expect(
 943						:get,
 944						EMPromise.resolve(nil),
 945						["jmp_invite_tries-test"]
 946					)
 947					Registration::Payment::InviteCode::REDIS.expect(
 948						:hget,
 949						EMPromise.resolve(nil),
 950						["jmp_parent_codes", "abc"]
 951					)
 952					Command::COMMAND_MANAGER.expect(
 953						:write,
 954						EMPromise.resolve(
 955							Blather::Stanza::Iq::Command.new.tap { |iq|
 956								iq.form.fields = [{ var: "code", value: "abc" }]
 957							}
 958						),
 959						[Matching.new do |reply|
 960							assert_equal :form, reply.form.type
 961							assert_nil reply.form.instructions
 962						end]
 963					)
 964
 965					Registration::Payment::InviteCode.new(
 966						customer,
 967						"+15555550000"
 968					).write
 969				end
 970				assert_mock Command::COMMAND_MANAGER
 971				assert_mock Registration::Payment::InviteCode::DB
 972				assert_mock Registration::Payment::InviteCode::REDIS
 973				assert_mock Registration::Payment::InviteCode::Finish
 974			end
 975			em :test_write
 976
 977			def test_write_parent_code
 978				customer = customer(plan_name: "test_usd")
 979				Registration::Payment::InviteCode::BillPlan.expect(
 980					:new,
 981					OpenStruct.new(write: nil)
 982				) { |*| true }
 983				Registration::Payment::InviteCode::DB.expect(
 984					:query_one, {}, [String, "parent_customer"], default: {}
 985				)
 986				Registration::Payment::InviteCode::DB.expect(
 987					:query_one, { c: 0 }, [String, "parent_customer"], default: { c: 0 }
 988				)
 989				execute_command do
 990					Registration::Payment::InviteCode::REDIS.expect(
 991						:hget,
 992						EMPromise.resolve("parent_customer"),
 993						["jmp_parent_codes", "pabc"]
 994					)
 995					Registration::Payment::InviteCode::REDIS.expect(
 996						:get,
 997						EMPromise.resolve(nil),
 998						["jmp_customer_trust_level-parent_customer"]
 999					)
1000					CustomerPlan::DB.expect(
1001						:query,
1002						[{ "plan_name" => "test_usd" }],
1003						[String, ["parent_customer"]]
1004					)
1005					CustomerPlan::DB.expect(
1006						:exec_defer,
1007						EMPromise.resolve(nil),
1008						[String, ["test", "test_usd", "parent_customer"]]
1009					)
1010					Command.execution.customer_repo.expect(
1011						:find,
1012						customer.with_balance(10000),
1013						["test"]
1014					)
1015					Command::COMMAND_MANAGER.expect(
1016						:write,
1017						EMPromise.resolve(
1018							Blather::Stanza::Iq::Command.new.tap { |iq|
1019								iq.form.fields = [{ var: "code", value: "pabc" }]
1020							}
1021						),
1022						[Matching.new do |reply|
1023							assert_equal :form, reply.form.type
1024							assert_nil reply.form.instructions
1025						end]
1026					)
1027
1028					Registration::Payment::InviteCode.new(
1029						customer,
1030						"+15555550000"
1031					).write
1032				end
1033				assert_mock Command::COMMAND_MANAGER
1034				assert_mock Registration::Payment::InviteCode::DB
1035				assert_mock Registration::Payment::InviteCode::REDIS
1036				assert_mock Registration::Payment::InviteCode::BillPlan
1037			end
1038			em :test_write_parent_code
1039
1040			def test_write_bad_code
1041				result = execute_command do
1042					customer = customer(plan_name: "test_usd")
1043					Registration::Payment::InviteCode::REDIS.expect(
1044						:get,
1045						EMPromise.resolve(0),
1046						["jmp_invite_tries-test"]
1047					)
1048					Registration::Payment::InviteCode::REDIS.expect(
1049						:hget,
1050						EMPromise.resolve(nil),
1051						["jmp_parent_codes", "abc"]
1052					)
1053					Registration::Payment::InviteCode::DB.expect(
1054						:transaction,
1055						[]
1056					) { |&blk| blk.call }
1057					Registration::Payment::InviteCode::DB.expect(
1058						:exec,
1059						OpenStruct.new(cmd_tuples: 0),
1060						[String, ["test", "abc"]]
1061					)
1062					Registration::Payment::InviteCode::REDIS.expect(
1063						:incr,
1064						EMPromise.resolve(nil),
1065						["jmp_invite_tries-test"]
1066					)
1067					Registration::Payment::InviteCode::REDIS.expect(
1068						:expire,
1069						EMPromise.resolve(nil),
1070						["jmp_invite_tries-test", 60 * 60]
1071					)
1072					Registration::Payment::InviteCode::REDIS.expect(
1073						:hexists,
1074						EMPromise.resolve(0),
1075						["jmp_group_codes", "abc"]
1076					)
1077					Command::COMMAND_MANAGER.expect(
1078						:write,
1079						EMPromise.resolve(
1080							Blather::Stanza::Iq::Command.new.tap { |iq|
1081								iq.form.fields = [{ var: "code", value: "abc" }]
1082							}
1083						),
1084						[Matching.new do |reply|
1085							assert_equal :form, reply.form.type
1086							assert_nil reply.form.instructions
1087						end]
1088					)
1089					Command::COMMAND_MANAGER.expect(
1090						:write,
1091						EMPromise.reject(:test_result),
1092						[Matching.new do |reply|
1093							assert_equal :form, reply.form.type
1094							assert_equal(
1095								"Not a valid invite code: abc",
1096								reply.form.instructions
1097							)
1098						end]
1099					)
1100
1101					Registration::Payment::InviteCode.new(
1102						customer,
1103						"+15555550000"
1104					).write.catch { |e| e }
1105				end
1106				assert_equal :test_result, result
1107				assert_mock Command::COMMAND_MANAGER
1108				assert_mock Registration::Payment::InviteCode::DB
1109				assert_mock Registration::Payment::InviteCode::REDIS
1110			end
1111			em :test_write_bad_code
1112
1113			def test_write_group_code
1114				result = execute_command do
1115					customer = customer(plan_name: "test_usd")
1116					Registration::Payment::InviteCode::REDIS.expect(
1117						:get,
1118						EMPromise.resolve(0),
1119						["jmp_invite_tries-test"]
1120					)
1121					Registration::Payment::InviteCode::REDIS.expect(
1122						:hget,
1123						EMPromise.resolve(nil),
1124						["jmp_parent_codes", "abc"]
1125					)
1126					Registration::Payment::InviteCode::DB.expect(
1127						:transaction,
1128						[]
1129					) { |&blk| blk.call }
1130					Registration::Payment::InviteCode::DB.expect(
1131						:exec,
1132						OpenStruct.new(cmd_tuples: 0),
1133						[String, ["test", "abc"]]
1134					)
1135					Registration::Payment::InviteCode::REDIS.expect(
1136						:incr,
1137						EMPromise.resolve(nil),
1138						["jmp_invite_tries-test"]
1139					)
1140					Registration::Payment::InviteCode::REDIS.expect(
1141						:expire,
1142						EMPromise.resolve(nil),
1143						["jmp_invite_tries-test", 60 * 60]
1144					)
1145					Registration::Payment::InviteCode::REDIS.expect(
1146						:hexists,
1147						EMPromise.resolve(1),
1148						["jmp_group_codes", "abc"]
1149					)
1150					Command::COMMAND_MANAGER.expect(
1151						:write,
1152						EMPromise.resolve(
1153							Blather::Stanza::Iq::Command.new.tap { |iq|
1154								iq.form.fields = [{ var: "code", value: "abc" }]
1155							}
1156						),
1157						[Matching.new do |reply|
1158							assert_equal :form, reply.form.type
1159							assert_nil reply.form.instructions
1160						end]
1161					)
1162					Command::COMMAND_MANAGER.expect(
1163						:write,
1164						EMPromise.reject(:test_result),
1165						[Matching.new do |reply|
1166							assert_equal :form, reply.form.type
1167							assert_equal(
1168								"abc is a post-payment referral",
1169								reply.form.instructions
1170							)
1171						end]
1172					)
1173
1174					Registration::Payment::InviteCode.new(
1175						customer,
1176						"+15555550000"
1177					).write.catch { |e| e }
1178				end
1179				assert_equal :test_result, result
1180				assert_mock Command::COMMAND_MANAGER
1181				assert_mock Registration::Payment::InviteCode::DB
1182				assert_mock Registration::Payment::InviteCode::REDIS
1183			end
1184			em :test_write_group_code
1185
1186			def test_write_bad_code_over_limit
1187				result = execute_command do
1188					customer = customer(plan_name: "test_usd")
1189					Registration::Payment::InviteCode::REDIS.expect(
1190						:get,
1191						EMPromise.resolve(11),
1192						["jmp_invite_tries-test"]
1193					)
1194					Registration::Payment::InviteCode::REDIS.expect(
1195						:hget,
1196						EMPromise.resolve(nil),
1197						["jmp_parent_codes", "abc"]
1198					)
1199					Command::COMMAND_MANAGER.expect(
1200						:write,
1201						EMPromise.resolve(
1202							Blather::Stanza::Iq::Command.new.tap { |iq|
1203								iq.form.fields = [{ var: "code", value: "abc" }]
1204							}
1205						),
1206						[Matching.new do |reply|
1207							assert_equal :form, reply.form.type
1208							assert_nil reply.form.instructions
1209						end]
1210					)
1211					Command::COMMAND_MANAGER.expect(
1212						:write,
1213						EMPromise.reject(:test_result),
1214						[Matching.new do |reply|
1215							assert_equal :form, reply.form.type
1216							assert_equal "Too many wrong attempts", reply.form.instructions
1217						end]
1218					)
1219					Registration::Payment::InviteCode.new(
1220						customer,
1221						"+15555550000"
1222					).write.catch { |e| e }
1223				end
1224				assert_equal :test_result, result
1225				assert_mock Command::COMMAND_MANAGER
1226				assert_mock Registration::Payment::InviteCode::REDIS
1227			end
1228			em :test_write_bad_code_over_limit
1229		end
1230	end
1231
1232	class FinishTest < Minitest::Test
1233		Customer::BLATHER = Minitest::Mock.new
1234		Command::COMMAND_MANAGER = Minitest::Mock.new
1235		Registration::Finish::TEL_SELECTIONS = FakeTelSelections.new
1236		Registration::Finish::REDIS = Minitest::Mock.new
1237		Registration::Finish::DB = Minitest::Mock.new
1238		Bwmsgsv2Repo::REDIS = Minitest::Mock.new
1239		Registration::FinishOnboarding::DB = FakeDB.new
1240		Transaction::DB = Minitest::Mock.new
1241
1242		def setup
1243			@sgx = Minitest::Mock.new(mksgx)
1244			iq = Blather::Stanza::Iq::Command.new
1245			iq.from = "test\\40example.com@cheogram.com"
1246			@finish = Registration::Finish.new(
1247				customer(sgx: @sgx, plan_name: "test_usd"),
1248				TelSelections::ChooseTel::Tn.for_pending_value("+15555550000")
1249			)
1250		end
1251
1252		def test_write
1253			create_order = stub_request(
1254				:post,
1255				"https://dashboard.bandwidth.com/v1.0/accounts//orders"
1256			).to_return(status: 201, body: <<~RESPONSE)
1257				<OrderResponse>
1258					<Order>
1259						<id>test_order</id>
1260					</Order>
1261				</OrderResponse>
1262			RESPONSE
1263			stub_request(
1264				:get,
1265				"https://dashboard.bandwidth.com/v1.0/accounts//orders/test_order"
1266			).to_return(status: 201, body: <<~RESPONSE)
1267				<OrderResponse>
1268					<OrderStatus>COMPLETE</OrderStatus>
1269					<CompletedNumbers>
1270						<TelephoneNumber>
1271							<FullNumber>5555550000</FullNumber>
1272						</TelephoneNumber>
1273					</CompletedNumbers>
1274				</OrderResponse>
1275			RESPONSE
1276			stub_request(
1277				:post,
1278				"https://dashboard.bandwidth.com/v1.0/accounts//sites//sippeers//movetns"
1279			)
1280			Registration::Finish::REDIS.expect(
1281				:get,
1282				nil,
1283				["jmp_customer_pending_invite-test"]
1284			)
1285			Registration::Finish::REDIS.expect(
1286				:del,
1287				nil,
1288				["jmp_customer_pending_invite-test"]
1289			)
1290			Registration::Finish::REDIS.expect(
1291				:hget,
1292				nil,
1293				["jmp_group_codes", nil]
1294			)
1295			Bwmsgsv2Repo::REDIS.expect(
1296				:get,
1297				EMPromise.resolve(nil),
1298				["jmp_customer_backend_sgx-test"]
1299			)
1300			Bwmsgsv2Repo::REDIS.expect(
1301				:set,
1302				nil,
1303				[
1304					"catapult_fwd-+15555550000",
1305					"xmpp:test@example.net"
1306				]
1307			)
1308			Bwmsgsv2Repo::REDIS.expect(
1309				:set,
1310				nil,
1311				["catapult_fwd_timeout-customer_test@component", 25]
1312			)
1313			Customer::BLATHER.expect(
1314				:<<,
1315				nil,
1316				[Matching.new do |m|
1317					assert_equal :chat, m.type
1318					assert m.body =~ /^Welcome to JMP/
1319				end]
1320			)
1321			blather = Minitest::Mock.new
1322			blather.expect(
1323				:<<,
1324				nil,
1325				[Matching.new do |reply|
1326					assert_equal :completed, reply.status
1327					assert_equal :info, reply.note_type
1328					assert_equal(
1329						"Your JMP account has been activated as (555) 555-0000",
1330						reply.note.content
1331					)
1332				end]
1333			)
1334			execute_command(blather: blather) do
1335				@sgx.expect(
1336					:register!,
1337					EMPromise.resolve(@sgx.with(
1338						registered?: Blather::Stanza::Iq::IBR.new.tap do |ibr|
1339							ibr.phone = "+15555550000"
1340						end
1341					)),
1342					["+15555550000"]
1343				)
1344
1345				@finish.write
1346			end
1347			assert_requested create_order
1348			assert_mock @sgx
1349			assert_mock Registration::Finish::REDIS
1350			assert_mock Bwmsgsv2Repo::REDIS
1351			assert_mock Customer::BLATHER
1352			assert_mock blather
1353		end
1354		em :test_write
1355
1356		def test_write_with_pending_code
1357			create_order = stub_request(
1358				:post,
1359				"https://dashboard.bandwidth.com/v1.0/accounts//orders"
1360			).to_return(status: 201, body: <<~RESPONSE)
1361				<OrderResponse>
1362					<Order>
1363						<id>test_order</id>
1364					</Order>
1365				</OrderResponse>
1366			RESPONSE
1367			stub_request(
1368				:get,
1369				"https://dashboard.bandwidth.com/v1.0/accounts//orders/test_order"
1370			).to_return(status: 201, body: <<~RESPONSE)
1371				<OrderResponse>
1372					<OrderStatus>COMPLETE</OrderStatus>
1373					<CompletedNumbers>
1374						<TelephoneNumber>
1375							<FullNumber>5555550000</FullNumber>
1376						</TelephoneNumber>
1377					</CompletedNumbers>
1378				</OrderResponse>
1379			RESPONSE
1380			stub_request(
1381				:post,
1382				"https://dashboard.bandwidth.com/v1.0/accounts//sites//sippeers//movetns"
1383			)
1384			Registration::Finish::REDIS.expect(
1385				:get,
1386				EMPromise.resolve("123"),
1387				["jmp_customer_pending_invite-test"]
1388			)
1389			Registration::Finish::REDIS.expect(
1390				:del,
1391				nil,
1392				["jmp_customer_pending_invite-test"]
1393			)
1394			Registration::Finish::REDIS.expect(
1395				:hget,
1396				EMPromise.resolve("test-inviter"),
1397				["jmp_group_codes", "123"]
1398			)
1399			Registration::Finish::DB.expect(
1400				:exec,
1401				EMPromise.resolve(nil),
1402				[String, ["test-inviter", "test"]]
1403			)
1404			Transaction::DB.expect(:transaction, nil) do |&blk|
1405				blk.call
1406				true
1407			end
1408			Transaction::DB.expect(
1409				:exec,
1410				nil,
1411				[String, Matching.new { |params|
1412					assert_equal "test", params[0]
1413					assert params[1].start_with?("referral_")
1414					assert_equal 1, params[4]
1415					assert_equal "Referral Bonus", params[5]
1416				}]
1417			)
1418			Bwmsgsv2Repo::REDIS.expect(
1419				:get,
1420				EMPromise.resolve(nil),
1421				["jmp_customer_backend_sgx-test"]
1422			)
1423			Bwmsgsv2Repo::REDIS.expect(
1424				:set,
1425				nil,
1426				[
1427					"catapult_fwd-+15555550000",
1428					"xmpp:test@example.net"
1429				]
1430			)
1431			Bwmsgsv2Repo::REDIS.expect(
1432				:set,
1433				nil,
1434				["catapult_fwd_timeout-customer_test@component", 25]
1435			)
1436			Customer::BLATHER.expect(
1437				:<<,
1438				nil,
1439				[Matching.new do |m|
1440					assert_equal :chat, m.type
1441					assert m.body =~ /^Welcome to JMP/
1442				end]
1443			)
1444			blather = Minitest::Mock.new
1445			blather.expect(
1446				:<<,
1447				nil,
1448				[Matching.new do |reply|
1449					assert_equal :completed, reply.status
1450					assert_equal :info, reply.note_type
1451					assert_equal(
1452						"Your JMP account has been activated as (555) 555-0000",
1453						reply.note.content
1454					)
1455				end]
1456			)
1457			execute_command(blather: blather) do
1458				@sgx.expect(
1459					:register!,
1460					EMPromise.resolve(@sgx.with(
1461						registered?: Blather::Stanza::Iq::IBR.new.tap do |ibr|
1462							ibr.phone = "+15555550000"
1463						end
1464					)),
1465					["+15555550000"]
1466				)
1467
1468				@finish.write
1469			end
1470			assert_requested create_order
1471			assert_mock @sgx
1472			assert_mock Registration::Finish::REDIS
1473			assert_mock Bwmsgsv2Repo::REDIS
1474			assert_mock Customer::BLATHER
1475			assert_mock blather
1476			assert_mock Transaction::DB
1477		end
1478		em :test_write_with_pending_code
1479
1480		def test_write_onboarding
1481			create_order = stub_request(
1482				:post,
1483				"https://dashboard.bandwidth.com/v1.0/accounts//orders"
1484			).to_return(status: 201, body: <<~RESPONSE)
1485				<OrderResponse>
1486					<Order>
1487						<id>test_order</id>
1488					</Order>
1489				</OrderResponse>
1490			RESPONSE
1491			stub_request(
1492				:get,
1493				"https://dashboard.bandwidth.com/v1.0/accounts//orders/test_order"
1494			).to_return(status: 201, body: <<~RESPONSE)
1495				<OrderResponse>
1496					<OrderStatus>COMPLETE</OrderStatus>
1497					<CompletedNumbers>
1498						<TelephoneNumber>
1499							<FullNumber>5555550000</FullNumber>
1500						</TelephoneNumber>
1501					</CompletedNumbers>
1502				</OrderResponse>
1503			RESPONSE
1504			stub_request(
1505				:post,
1506				"https://dashboard.bandwidth.com/v1.0/accounts//sites//sippeers//movetns"
1507			)
1508			Registration::Finish::REDIS.expect(
1509				:get,
1510				nil,
1511				["jmp_customer_pending_invite-test"]
1512			)
1513			Registration::Finish::REDIS.expect(
1514				:del,
1515				nil,
1516				["jmp_customer_pending_invite-test"]
1517			)
1518			Registration::Finish::REDIS.expect(
1519				:hget,
1520				nil,
1521				["jmp_group_codes", nil]
1522			)
1523			Bwmsgsv2Repo::REDIS.expect(
1524				:get,
1525				EMPromise.resolve(nil),
1526				["jmp_customer_backend_sgx-test"]
1527			)
1528			Bwmsgsv2Repo::REDIS.expect(
1529				:set,
1530				nil,
1531				[
1532					"catapult_fwd-+15555550000",
1533					"xmpp:test\\40onboarding.example.com@proxy"
1534				]
1535			)
1536			Bwmsgsv2Repo::REDIS.expect(
1537				:set,
1538				nil,
1539				["catapult_fwd_timeout-customer_test@component", 25]
1540			)
1541			result = execute_command do
1542				@sgx.expect(
1543					:register!,
1544					EMPromise.resolve(@sgx.with(
1545						registered?: Blather::Stanza::Iq::IBR.new.tap do |ibr|
1546							ibr.phone = "+15555550000"
1547						end
1548					)),
1549					["+15555550000"]
1550				)
1551
1552				Command::COMMAND_MANAGER.expect(
1553					:write,
1554					EMPromise.reject(:test_result),
1555					[Matching.new do |iq|
1556						assert_equal :form, iq.form.type
1557						assert iq.form.field("subdomain")
1558					end]
1559				)
1560
1561				Registration::Finish.new(
1562					customer(
1563						sgx: @sgx,
1564						jid: Blather::JID.new("test\\40onboarding.example.com@proxy")
1565					),
1566					TelSelections::ChooseTel::Tn.for_pending_value("+15555550000")
1567				).write.catch { |e| e }
1568			end
1569			assert_equal :test_result, result
1570			assert_requested create_order
1571			assert_mock @sgx
1572			assert_mock Registration::Finish::REDIS
1573			assert_mock Bwmsgsv2Repo::REDIS
1574			assert_mock Command::COMMAND_MANAGER
1575		end
1576		em :test_write_onboarding
1577
1578		def test_write_local_inventory
1579			stub_request(
1580				:post,
1581				"https://dashboard.bandwidth.com/v1.0/accounts/moveto/moveTns"
1582			).with(
1583				body: {
1584					CustomerOrderId: "test",
1585					SourceAccountId: "bandwidth_account_id",
1586					SiteId: "test_site",
1587					SipPeerId: "test_peer",
1588					TelephoneNumbers: { TelephoneNumber: "5555550000" }
1589				}.to_xml(indent: 0, root: "MoveTnsOrder")
1590			).to_return(status: 200, body: "", headers: {})
1591
1592			Registration::Finish::REDIS.expect(
1593				:get,
1594				nil,
1595				["jmp_customer_pending_invite-test"]
1596			)
1597			Registration::Finish::REDIS.expect(
1598				:del,
1599				nil,
1600				["jmp_customer_pending_invite-test"]
1601			)
1602			Registration::Finish::REDIS.expect(
1603				:hget,
1604				nil,
1605				["jmp_group_codes", nil]
1606			)
1607			Registration::Finish::DB.expect(
1608				:exec_defer,
1609				EMPromise.resolve(OpenStruct.new(cmd_tuples: 1)),
1610				[String, ["+15555550000"]]
1611			)
1612			Bwmsgsv2Repo::REDIS.expect(
1613				:get,
1614				EMPromise.resolve(nil),
1615				["jmp_customer_backend_sgx-test"]
1616			)
1617			Bwmsgsv2Repo::REDIS.expect(
1618				:set,
1619				nil,
1620				[
1621					"catapult_fwd-+15555550000",
1622					"xmpp:test\\40onboarding.example.com@proxy"
1623				]
1624			)
1625			Bwmsgsv2Repo::REDIS.expect(
1626				:set,
1627				nil,
1628				["catapult_fwd_timeout-customer_test@component", 25]
1629			)
1630			result = execute_command do
1631				@sgx.expect(
1632					:register!,
1633					EMPromise.resolve(@sgx.with(
1634						registered?: Blather::Stanza::Iq::IBR.new.tap do |ibr|
1635							ibr.phone = "+15555550000"
1636						end
1637					)),
1638					["+15555550000"]
1639				)
1640
1641				Command::COMMAND_MANAGER.expect(
1642					:write,
1643					EMPromise.reject(:test_result),
1644					[Matching.new do |iq|
1645						assert_equal :form, iq.form.type
1646						assert iq.form.field("subdomain")
1647					end]
1648				)
1649
1650				Registration::Finish.new(
1651					customer(
1652						sgx: @sgx,
1653						jid: Blather::JID.new("test\\40onboarding.example.com@proxy")
1654					),
1655					TelSelections::ChooseTel::Tn::LocalInventory.new(
1656						TelSelections::ChooseTel::Tn.new("+15555550000"),
1657						"bandwidth_account_id"
1658					)
1659				).write.catch { |e| e }
1660			end
1661			assert_equal :test_result, result
1662			assert_mock @sgx
1663			assert_mock Registration::Finish::REDIS
1664			assert_mock Bwmsgsv2Repo::REDIS
1665			assert_mock Command::COMMAND_MANAGER
1666		end
1667		em :test_write_local_inventory
1668
1669		def test_write_tn_fail
1670			create_order = stub_request(
1671				:post,
1672				"https://dashboard.bandwidth.com/v1.0/accounts//orders"
1673			).to_return(status: 201, body: <<~RESPONSE)
1674				<OrderResponse>
1675					<Order>
1676						<id>test_order</id>
1677					</Order>
1678				</OrderResponse>
1679			RESPONSE
1680			stub_request(
1681				:get,
1682				"https://dashboard.bandwidth.com/v1.0/accounts//orders/test_order"
1683			).to_return(status: 201, body: <<~RESPONSE)
1684				<OrderResponse>
1685					<OrderStatus>FAILED</OrderStatus>
1686				</OrderResponse>
1687			RESPONSE
1688
1689			result = execute_command do
1690				Command::COMMAND_MANAGER.expect(
1691					:write,
1692					EMPromise.reject(:test_result),
1693					[Matching.new do |iq|
1694						assert_equal :form, iq.form.type
1695						assert_equal(
1696							"The JMP number (555) 555-0000 is no longer available.",
1697							iq.form.instructions
1698						)
1699					end]
1700				)
1701
1702				@finish.write.catch { |e| e }
1703			end
1704
1705			assert_equal :test_result, result
1706			assert_mock Command::COMMAND_MANAGER
1707			assert_instance_of(
1708				TelSelections::ChooseTel,
1709				Registration::Finish::TEL_SELECTIONS["test@example.com"]
1710			)
1711			assert_requested create_order
1712		end
1713		em :test_write_tn_fail
1714	end
1715
1716	class SnikketTest < Minitest::Test
1717		Command::COMMAND_MANAGER = Minitest::Mock.new
1718		Registration::FinishOnboarding::Snikket::IQ_MANAGER = Minitest::Mock.new
1719
1720		def setup
1721			@sgx = Minitest::Mock.new(mksgx)
1722			@snikket = Registration::FinishOnboarding::Snikket.new(
1723				customer(sgx: @sgx),
1724				"+15555550000",
1725				db: FakeDB.new
1726			)
1727		end
1728
1729		def test_write
1730			xmpp_uri = "xmpp:test.snikket.chat?register;preauth=NEWTOKEN"
1731
1732			subdomain_form = Blather::Stanza::Iq::Command.new
1733			subdomain_form.form.fields = [
1734				{ var: "subdomain", value: "test" }
1735			]
1736
1737			launched = Snikket::Launched.new
1738			launched << Niceogiri::XML::Node.new(
1739				:launched, launched.document, "xmpp:snikket.org/hosting/v1"
1740			).tap { |inner|
1741				inner << Niceogiri::XML::Node.new(
1742					:'instance-id', launched.document, "xmpp:snikket.org/hosting/v1"
1743				).tap { |id|
1744					id.content = "si-1234"
1745				}
1746				inner << Niceogiri::XML::Node.new(
1747					:bootstrap, launched.document, "xmpp:snikket.org/hosting/v1"
1748				).tap { |bootstrap|
1749					bootstrap << Niceogiri::XML::Node.new(
1750						:token, launched.document, "xmpp:snikket.org/hosting/v1"
1751					).tap { |token|
1752						token.content = "TOKEN"
1753					}
1754				}
1755			}
1756
1757			blather = Minitest::Mock.new
1758			blather.expect(
1759				:<<,
1760				nil,
1761				[Matching.new do |reply|
1762					assert_equal :completed, reply.status
1763					assert_equal(
1764						xmpp_uri,
1765						OOB.find_or_create(reply.command).url
1766					)
1767				end]
1768			)
1769
1770			execute_command(blather: blather) do
1771				Command::COMMAND_MANAGER.expect(
1772					:write,
1773					EMPromise.resolve(subdomain_form),
1774					[Matching.new do |iq|
1775						assert_equal :form, iq.form.type
1776						assert iq.form.field("subdomain")
1777					end]
1778				)
1779
1780				Registration::FinishOnboarding::Snikket::IQ_MANAGER.expect(
1781					:write,
1782					EMPromise.resolve(launched),
1783					[Matching.new do |iq|
1784						assert_equal :set, iq.type
1785						assert_equal CONFIG[:snikket_hosting_api], iq.to.to_s
1786						assert_equal(
1787							"test.snikket.chat",
1788							iq.xpath(
1789								"./ns:launch/ns:domain",
1790								ns: "xmpp:snikket.org/hosting/v1"
1791							).text
1792						)
1793					end]
1794				)
1795
1796				# Webmock doesn't support redirects properly, but they work live
1797				stub_request(
1798					:head, "https://test.snikket.chat/invites_bootstrap?token=TOKEN"
1799				).to_return(
1800					status: 200,
1801					headers: {
1802						"link" => "<#{xmpp_uri}>; rel=\"alternate\""
1803					}
1804				)
1805
1806				@snikket.write
1807			end
1808
1809			assert_mock Command::COMMAND_MANAGER
1810			assert_mock Registration::FinishOnboarding::Snikket::IQ_MANAGER
1811			assert_mock blather
1812		end
1813		em :test_write
1814
1815		def test_write_not_yet
1816			subdomain_form = Blather::Stanza::Iq::Command.new
1817			subdomain_form.form.fields = [
1818				{ var: "subdomain", value: "test" }
1819			]
1820
1821			launched = Snikket::Launched.new
1822			launched << Niceogiri::XML::Node.new(
1823				:launched, launched.document, "xmpp:snikket.org/hosting/v1"
1824			).tap { |inner|
1825				inner << Niceogiri::XML::Node.new(
1826					:'instance-id', launched.document, "xmpp:snikket.org/hosting/v1"
1827				).tap { |id|
1828					id.content = "si-1234"
1829				}
1830				inner << Niceogiri::XML::Node.new(
1831					:bootstrap, launched.document, "xmpp:snikket.org/hosting/v1"
1832				).tap { |bootstrap|
1833					bootstrap << Niceogiri::XML::Node.new(
1834						:token, launched.document, "xmpp:snikket.org/hosting/v1"
1835					).tap { |token|
1836						token.content = "TOKEN"
1837					}
1838				}
1839			}
1840
1841			result = execute_command do
1842				Command::COMMAND_MANAGER.expect(
1843					:write,
1844					EMPromise.resolve(subdomain_form),
1845					[Matching.new do |iq|
1846						assert_equal :form, iq.form.type
1847						assert iq.form.field("subdomain")
1848					end]
1849				)
1850
1851				Registration::FinishOnboarding::Snikket::IQ_MANAGER.expect(
1852					:write,
1853					EMPromise.resolve(launched),
1854					[Matching.new do |iq|
1855						assert_equal :set, iq.type
1856						assert_equal CONFIG[:snikket_hosting_api], iq.to.to_s
1857						assert_equal(
1858							"test.snikket.chat",
1859							iq.xpath(
1860								"./ns:launch/ns:domain",
1861								ns: "xmpp:snikket.org/hosting/v1"
1862							).text
1863						)
1864					end]
1865				)
1866
1867				stub_request(
1868					:head, "https://test.snikket.chat/invites_bootstrap?token=TOKEN"
1869				).to_timeout
1870
1871				Command::COMMAND_MANAGER.expect(
1872					:write,
1873					EMPromise.reject(:test_result),
1874					[Matching.new do |iq|
1875						assert_equal :result, iq.form.type
1876						assert iq.form.instructions =~ / test\.snikket\.chat /
1877						assert_equal "jid-single", iq.form.field("support").type
1878					end]
1879				)
1880
1881				@snikket.write.catch { |e| e }
1882			end
1883
1884			assert_equal :test_result, result
1885			assert_mock Command::COMMAND_MANAGER
1886			assert_mock Registration::FinishOnboarding::Snikket::IQ_MANAGER
1887		end
1888		em :test_write_not_yet
1889
1890		def test_write_already_taken
1891			subdomain_form = Blather::Stanza::Iq::Command.new
1892			subdomain_form.form.fields = [
1893				{ var: "subdomain", value: "test" }
1894			]
1895
1896			launched = Snikket::Launched.new.as_error(
1897				"internal-server-error",
1898				:wait,
1899				"This is an error"
1900			)
1901
1902			result = execute_command do
1903				Command::COMMAND_MANAGER.expect(
1904					:write,
1905					EMPromise.resolve(subdomain_form),
1906					[Matching.new do |iq|
1907						assert_equal :form, iq.form.type
1908						assert iq.form.field("subdomain")
1909					end]
1910				)
1911
1912				Registration::FinishOnboarding::Snikket::IQ_MANAGER.expect(
1913					:write,
1914					EMPromise.reject(launched),
1915					[Matching.new do |iq|
1916						assert_equal :set, iq.type
1917						assert_equal CONFIG[:snikket_hosting_api], iq.to.to_s
1918						assert_equal(
1919							"test.snikket.chat",
1920							iq.xpath(
1921								"./ns:launch/ns:domain",
1922								ns: "xmpp:snikket.org/hosting/v1"
1923							).text
1924						)
1925					end]
1926				)
1927
1928				stub_request(
1929					:head, "https://test.snikket.chat/invites_bootstrap?token=TOKEN"
1930				).to_timeout
1931
1932				Command::COMMAND_MANAGER.expect(
1933					:write,
1934					EMPromise.reject(:test_result),
1935					[Matching.new do |iq|
1936						assert iq.executing?
1937						assert_equal(
1938							"This is an error",
1939							iq.form.field("subdomain").desc
1940						)
1941					end]
1942				)
1943
1944				@snikket.write.catch { |e| e }
1945			end
1946
1947			assert_equal :test_result, result
1948			assert_mock Command::COMMAND_MANAGER
1949			assert_mock Registration::FinishOnboarding::Snikket::IQ_MANAGER
1950		end
1951		em :test_write_already_taken
1952	end
1953
1954	class SnikketCustomDomainTest < Minitest::Test
1955		def setup
1956			@snikket = Registration::FinishOnboarding::CustomDomain.new(
1957				customer,
1958				"+15555550000",
1959				db: FakeDB.new
1960			)
1961		end
1962
1963		def test_write_needs_dns
1964			domain_form = Blather::Stanza::Iq::Command.new
1965			domain_form.form.fields = [
1966				{ var: "domain", value: "snikket.example.com" }
1967			]
1968
1969			launched = Snikket::Launched.new
1970			launched << Niceogiri::XML::Node.new(
1971				:launched, launched.document, "xmpp:snikket.org/hosting/v1"
1972			).tap { |inner|
1973				inner << Niceogiri::XML::Node.new(
1974					:'instance-id', launched.document, "xmpp:snikket.org/hosting/v1"
1975				).tap { |id|
1976					id.content = "si-1234"
1977				}
1978				inner << Niceogiri::XML::Node.new(
1979					:status, launched.document, "xmpp:snikket.org/hosting/v1"
1980				).tap { |id|
1981					id.content = "needs_dns"
1982				}
1983				inner << Niceogiri::XML::Node.new(
1984					:records, launched.document, "xmpp:snikket.org/hosting/v1"
1985				).tap { |records|
1986					records << Niceogiri::XML::Node.new(
1987						:record, launched.document, "xmpp:snikket.org/hosting/v1"
1988					).tap { |record|
1989						record << Niceogiri::XML::Node.new(
1990							:name, launched.document, "xmpp:snikket.org/hosting/v1"
1991						).tap { |name| name.content = "snikket.example.com" }
1992						record << Niceogiri::XML::Node.new(
1993							:type, launched.document, "xmpp:snikket.org/hosting/v1"
1994						).tap { |type| type.content = "AAAA" }
1995						record << Niceogiri::XML::Node.new(
1996							:status, launched.document, "xmpp:snikket.org/hosting/v1"
1997						).tap { |type| type.content = "incorrect" }
1998						record << Niceogiri::XML::Node.new(
1999							:expected, launched.document, "xmpp:snikket.org/hosting/v1"
2000						).tap { |expected|
2001							expected << Niceogiri::XML::Node.new(
2002								:value, launched.document, "xmpp:snikket.org/hosting/v1"
2003							).tap { |value| value.content = "1::2" }
2004						}
2005						record << Niceogiri::XML::Node.new(
2006							:found, launched.document, "xmpp:snikket.org/hosting/v1"
2007						).tap { |found|
2008							found << Niceogiri::XML::Node.new(
2009								:value, launched.document, "xmpp:snikket.org/hosting/v1"
2010							).tap { |value| value.content = "0::0" }
2011						}
2012					}
2013				}
2014			}
2015
2016			result = execute_command do
2017				Command::COMMAND_MANAGER.expect(
2018					:write,
2019					EMPromise.resolve(domain_form),
2020					[Matching.new do |iq|
2021						assert_equal :form, iq.form.type
2022						assert iq.form.field("domain")
2023					end]
2024				)
2025
2026				Registration::FinishOnboarding::Snikket::IQ_MANAGER.expect(
2027					:write,
2028					EMPromise.resolve(launched),
2029					[Matching.new do |iq|
2030						assert_equal :set, iq.type
2031						assert_equal CONFIG[:snikket_hosting_api], iq.to.to_s
2032						assert_equal(
2033							"snikket.example.com",
2034							iq.xpath(
2035								"./ns:launch/ns:domain",
2036								ns: "xmpp:snikket.org/hosting/v1"
2037							).text
2038						)
2039					end]
2040				)
2041
2042				Command::COMMAND_MANAGER.expect(
2043					:write,
2044					EMPromise.reject(:test_result),
2045					[Matching.new do |iq|
2046						assert_equal :form, iq.form.type
2047						assert_equal(
2048							["snikket.example.com"],
2049							iq.form.xpath(
2050								"./ns:item/ns:field[@var='name']/ns:value",
2051								ns: "jabber:x:data"
2052							).map(&:content)
2053						)
2054						assert_equal(
2055							["1::2"],
2056							iq.form.xpath(
2057								"./ns:item/ns:field[@var='expected']/ns:value",
2058								ns: "jabber:x:data"
2059							).map(&:content)
2060						)
2061					end]
2062				)
2063
2064				@snikket.write.catch { |e| e }
2065			end
2066
2067			assert_equal :test_result, result
2068			assert_mock Command::COMMAND_MANAGER
2069			assert_mock Registration::FinishOnboarding::Snikket::IQ_MANAGER
2070		end
2071		em :test_write_needs_dns
2072	end
2073end