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