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