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