test_registration.rb

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