test_admin_command.rb

  1# frozen_string_literal: true
  2
  3require "test_helper"
  4require "admin_command"
  5require "admin_action"
  6
  7BackendSgx::IQ_MANAGER = Minitest::Mock.new
  8BackendSgx::REDIS = Minitest::Mock.new
  9AdminAction::LaunchSnikket::IQ_MANAGER = Minitest::Mock.new
 10Customer::BLATHER = Minitest::Mock.new
 11AdminActionRepo::REDIS = Minitest::Mock.new
 12TrivialBackendSgxRepo::REDIS = Minitest::Mock.new
 13BandwidthTnRepo::DB = Minitest::Mock.new
 14AdminAction::NumberChange::REDIS = Minitest::Mock.new
 15
 16class AdminCommandTest < Minitest::Test
 17	def assert_undoable_form(iq, note_type=nil, note_text=nil)
 18		assert_equal :form, iq.form.type
 19		[:execute, :next, :complete].each do |action|
 20			assert iq.allowed_actions.include?(action)
 21		end
 22		assert_equal iq.note_type, note_type if note_type
 23
 24		assert iq.note_text = note_text if note_text
 25	end
 26
 27	def admin_command(tel="+15556667777", registered: OpenStruct.new(phone: tel))
 28		sgx = Minitest::Mock.new(OpenStruct.new(
 29			registered?: registered
 30		))
 31		[
 32			sgx,
 33			AdminCommand.new(
 34				customer(sgx: sgx),
 35				CustomerRepo.new(db: FakeDB.new),
 36				AdminActionRepo.new,
 37				Snikket::Repo.new(db: FakeDB.new)
 38			)
 39		]
 40	end
 41
 42	def test_no_user
 43		q_form = Blather::Stanza::Iq::Command.new
 44		q_form.action = :complete
 45		q_form.form.fields = [
 46			{ var: "q", value: "testuser" }
 47		]
 48
 49		customer_repo = Minitest::Mock.new
 50
 51		result = execute_command {
 52			customer_repo.expect(
 53				:find_by_format,
 54				EMPromise.resolve(OpenStruct.new(
 55					customer_id: "testuser",
 56					billing_customer_id: "testuser",
 57					balance: 0.to_d,
 58					jid: Blather::JID.new("test@example.com"),
 59					tndetails: {}
 60				)),
 61				["testuser"]
 62			)
 63
 64			customer_repo.expect(
 65				:find_by_format,
 66				EMPromise.resolve(nil),
 67				[Blather::JID]
 68			)
 69
 70			customer_repo.expect(
 71				:find_by_format,
 72				EMPromise.resolve(nil),
 73				[ProxiedJID]
 74			)
 75
 76			TrivialBackendSgxRepo::REDIS.expect(
 77				:get,
 78				EMPromise.resolve(nil),
 79				["jmp_customer_backend_sgx-testuser"]
 80			)
 81
 82			TrustLevelRepo::REDIS.expect(
 83				:get,
 84				EMPromise.resolve("Customer"),
 85				["jmp_customer_trust_level-testuser"]
 86			)
 87
 88			TrustLevelRepo::DB.expect(
 89				:query_one,
 90				EMPromise.resolve({ settled_amount: 0 }),
 91				[String, "testuser"], default: {}
 92			)
 93
 94			Subaccount::DB.expect(
 95				:query_defer,
 96				EMPromise.resolve([]),
 97				[String, ["testuser"]]
 98			)
 99
100			Command::COMMAND_MANAGER.expect(
101				:write,
102				EMPromise.resolve(q_form),
103				[Matching.new do |iq|
104					assert_equal :form, iq.form.type
105					assert iq.form.field("q")
106				end]
107			)
108
109			AdminCommand.for(nil, customer_repo).start.catch { |e| e }
110		}
111
112		assert result.stanza.completed?
113		assert_mock customer_repo
114		assert_mock Command::COMMAND_MANAGER
115		assert_mock TrustLevelRepo::REDIS
116		assert_mock Subaccount::DB
117		assert_mock TrivialBackendSgxRepo::REDIS
118	end
119	em :test_no_user
120
121	def test_action_launch_snikket
122		sgx, admin = admin_command
123		domain_form = Blather::Stanza::Iq::Command.new
124		domain_form.form.fields = [
125			{ var: "domain", value: "test.snikket.chat" }
126		]
127
128		launched = Snikket::Launched.new
129		launched << Niceogiri::XML::Node.new(
130			:launched, launched.document, "xmpp:snikket.org/hosting/v1"
131		).tap { |inner|
132			inner << Niceogiri::XML::Node.new(
133				:'instance-id', launched.document, "xmpp:snikket.org/hosting/v1"
134			).tap { |id|
135				id.content = "si-1234"
136			}
137			inner << Niceogiri::XML::Node.new(
138				:bootstrap, launched.document, "xmpp:snikket.org/hosting/v1"
139			).tap { |bootstrap|
140				bootstrap << Niceogiri::XML::Node.new(
141					:token, launched.document, "xmpp:snikket.org/hosting/v1"
142				).tap { |token|
143					token.content = "TOKEN"
144				}
145			}
146		}
147
148		result = execute_command {
149			Command::COMMAND_MANAGER.expect(
150				:write,
151				EMPromise.resolve(domain_form),
152				[Matching.new do |iq|
153					assert_equal :form, iq.form.type
154					assert iq.form.field("domain")
155				end]
156			)
157			Command::COMMAND_MANAGER.expect(
158				:write,
159				EMPromise.reject(:test_result),
160				[Matching.new do |iq|
161					assert :result, iq.type
162					assert(
163						"https://test.snikket.chat/invites_bootstrap?token=TOKEN",
164						iq.form.field("bootstrap-uri").value
165					)
166				end]
167			)
168
169			AdminAction::LaunchSnikket::IQ_MANAGER.expect(
170				:write,
171				EMPromise.resolve(launched),
172				[Matching.new do |iq|
173					assert_equal :set, iq.type
174					assert_equal CONFIG[:snikket_hosting_api], iq.to.to_s
175					assert_equal(
176						"test.snikket.chat",
177						iq.xpath(
178							"./ns:launch/ns:domain",
179							ns: "xmpp:snikket.org/hosting/v1"
180						).text
181					)
182				end]
183			)
184
185			admin.action_launch_snikket.catch { |e| e }
186		}
187
188		assert_equal :test_result, result
189		assert_mock sgx
190		assert_mock AdminAction::LaunchSnikket::IQ_MANAGER
191		assert_mock Customer::BLATHER
192	end
193	em :test_action_launch_snikket
194
195	def test_action_cancel_account
196		req = stub_request(:post, "https://api.churnbuster.io/v1/cancellations")
197			.with(
198				body: {
199					customer: {
200						source: "braintree",
201						source_id: "test",
202						email: "test@smtp.cheogram.com",
203						properties: {}
204					},
205					subscription: {
206						source: "braintree",
207						source_id: "test"
208					}
209				}.to_json
210			)
211			.to_return(status: 200, body: "", headers: {})
212
213		sgx, admin = admin_command
214
215		Customer::BLATHER.expect(
216			:<<,
217			EMPromise.resolve(nil),
218			[
219				Matching.new do |m|
220					assert_equal "Your JMP account has been cancelled.", m.body
221					assert_equal "test@example.net", m.to.to_s
222					assert_equal "notify_from@component", m.from.to_s
223				end
224			]
225		)
226
227		Customer::BLATHER.expect(
228			:<<,
229			EMPromise.resolve(nil),
230			[
231				Matching.new do |iq|
232					assert iq.remove?
233					assert_equal "test@example.net", iq.to.to_s
234					assert_equal "component", iq.from.to_s
235				end
236			]
237		)
238
239		sgx.expect(:deregister!, EMPromise.resolve(nil))
240
241		stub_request(
242			:post,
243			"https://dashboard.bandwidth.com/v1.0/accounts//disconnects"
244		).with(
245			body: {
246				name: "test",
247				DisconnectTelephoneNumberOrderType: {
248					TelephoneNumberList: {
249						TelephoneNumber: "5556667777"
250					}
251				}
252			}.to_xml(indent: 0, root: "DisconnectTelephoneNumberOrder")
253		).to_return(status: 200, body: "")
254
255		admin.action_cancel_account.sync
256
257		assert_mock sgx
258		assert_mock BackendSgx::IQ_MANAGER
259		assert_mock Customer::BLATHER
260		assert_requested req
261	end
262	em :test_action_cancel_account
263
264	def test_action_cancel_account_keep_number
265		rate_center_response = {
266			"TelephoneNumberDetails": {
267				State: "NY",
268				RateCenter: "NWYRCYZN01"
269			}
270		}.to_xml(indent: 0, root: "TelephoneNumberResponse")
271
272		bandwidth_req = stub_request(
273			:get,
274			"https://dashboard.bandwidth.com/v1.0/tns/5566667777/ratecenter"
275		)
276			.with(
277				headers: {
278					"Accept" => "application/xml",
279					"Accept-Encoding" => "gzip, compressed",
280					"Authorization" => "Basic dGVzdF9id191c2VyOnRlc3RfYndfcGFzc3dvcmQ=",
281					"User-Agent" => "Ruby-Bandwidth-Iris"
282				},
283				body: ""
284			)
285			.to_return(status: 200, body: rate_center_response, headers: {})
286
287		churnbuster_req = stub_request(
288			:post,
289			"https://api.churnbuster.io/v1/cancellations"
290		)
291			.with(
292				body: {
293					customer: {
294						source: "braintree",
295						source_id: "test",
296						email: "test@smtp.cheogram.com",
297						properties: {}
298					},
299					subscription: {
300						source: "braintree",
301						source_id: "test"
302					}
303				}.to_json
304			)
305			.to_return(status: 200, body: "", headers: {})
306
307		sgx, admin = admin_command("+15566667777")
308
309		sql_params = ["+15566667777", "NY", "NWYRCYZN01", "test_bw_account"]
310
311		BandwidthTnRepo::DB.expect(
312			:exec,
313			EMPromise.resolve(nil),
314			[String, sql_params]
315		)
316
317		Customer::BLATHER.expect(
318			:<<,
319			EMPromise.resolve(nil),
320			[
321				Matching.new do |m|
322					assert_equal "Your JMP account has been cancelled.", m.body
323					assert_equal "test@example.net", m.to.to_s
324					assert_equal "notify_from@component", m.from.to_s
325				end
326			]
327		)
328
329		Customer::BLATHER.expect(
330			:<<,
331			EMPromise.resolve(nil),
332			[
333				Matching.new do |iq|
334					assert iq.remove?
335					assert_equal "test@example.net", iq.to.to_s
336					assert_equal "component", iq.from.to_s
337				end
338			]
339		)
340
341		sgx.expect(:deregister!, EMPromise.resolve(nil))
342
343		admin.action_cancel_account.sync
344
345		assert_mock sgx
346		assert_mock BackendSgx::IQ_MANAGER
347		assert_mock Customer::BLATHER
348		assert_mock BandwidthTnRepo::DB
349
350		assert_requested churnbuster_req
351		assert_requested bandwidth_req
352	end
353	em :test_action_cancel_account_keep_number
354
355	def test_change_num_default_sgx
356		# Same as default given by `sgx.registered?` returned by `admin_command`
357		old_tel = "+15556667777"
358		new_tel = "+12222222222"
359
360		admin_number_change_form = Blather::Stanza::Iq::Command.new
361		admin_number_change_form.form.fields = [
362			{ var: "new_tel", value: new_tel },
363			{ var: "should_delete", value: false }
364		]
365		admin_number_change_form.from = "test@example.com"
366
367		execute_command { |exe|
368			sgx, admin = admin_command
369
370			exe.customer_repo.expect(
371				:find_by_jid,
372				EMPromise.resolve(customer(sgx: sgx)),
373				[Matching.new do |jid|
374					assert jid.is_a? Blather::JID
375					assert_equal jid.stripped.to_s, "test@example.com"
376				end]
377			)
378
379			AdminAction::NumberChange::REDIS.expect(
380				:exists,
381				EMPromise.resolve(1),
382				["catapult_jid-#{old_tel}"]
383			)
384
385			AdminAction::NumberChange::REDIS.expect(
386				:get,
387				EMPromise.resolve(nil), # Default SGX creds
388				["jmp_customer_backend_sgx-test"]
389			)
390
391			AdminAction::NumberChange::REDIS.expect(
392				:rename,
393				EMPromise.resolve(nil), # Default SGX creds
394				["catapult_fwd-#{old_tel}", "catapult_fwd-#{new_tel}"]
395			)
396
397			BackendSgx::REDIS.expect(
398				:set,
399				EMPromise.resolve(nil), # Default SGX creds
400				["catapult_jid-#{new_tel}", "customer_test@component"]
401			)
402
403			expected_xadd_args = {
404				customer_id: "test",
405				old_tel: old_tel,
406				new_tel: new_tel,
407				should_delete: nil,
408				actor_id: "test",
409				class: "NumberChange",
410				direction: :forward
411			}
412
413			AdminActionRepo::REDIS.expect(
414				:xadd,
415				EMPromise.resolve(nil)
416			) do |admin_actions, star, **xadd_args|
417				assert_equal admin_actions, "admin_actions"
418				assert_equal star, "*"
419
420				xadd_args.each do |k, v|
421					assert_equal v, expected_xadd_args[k]
422				end
423			end
424
425			# Make sure the IBR record was sent off for
426			# the new number.
427			BackendSgx::IQ_MANAGER.expect(
428				:write,
429				EMPromise.resolve(nil),
430				[Matching.new do |iq|
431					assert_equal iq.nick, "test_bw_account"
432					assert_equal iq.username, "test_bw_user"
433					assert_equal iq.password, "test_bw_password"
434					assert_equal iq.phone, new_tel
435				end]
436			)
437
438			Command::COMMAND_MANAGER.expect(
439				:write,
440				EMPromise.resolve(admin_number_change_form),
441				[Matching.new do |iq|
442					assert_undoable_form(iq)
443					assert iq.form.field("new_tel")
444					assert iq.form.field("should_delete")
445				end]
446			)
447
448			admin.action_number_change.sync
449
450			assert_mock Command::COMMAND_MANAGER
451			assert_mock exe.customer_repo
452			assert_mock AdminAction::NumberChange::REDIS
453			assert_mock AdminActionRepo::REDIS
454			assert_mock BackendSgx::IQ_MANAGER
455		}
456	end
457	em :test_change_num_default_sgx
458end