test_registration.rb

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