1# frozen_string_literal: true
  2
  3require "date"
  4require "ostruct"
  5require "test_helper"
  6
  7require "customer_info"
  8require "form_template"
  9require "form_to_h"
 10require "porting_step"
 11
 12MINS = 1.0 / (24 * 60)
 13
 14class BlatherNotifyMock < Minitest::Mock
 15	def initialize
 16		super
 17		@exes = []
 18	end
 19
 20	def expect_execution(server, node, *args)
 21		exe = Execution.new(args)
 22		expect(
 23			:command_execution,
 24			exe,
 25			[server, node]
 26		)
 27		@exes << exe
 28	end
 29
 30	def verify
 31		super
 32		@exes.each(&:verify)
 33	end
 34
 35	class Execution < Minitest::Mock
 36		def initialize(args)
 37			super()
 38			args.each_slice(2) do |(submission, result)|
 39				expect(
 40					:fetch_and_submit,
 41					EMPromise.resolve(to_response(result)),
 42					**submission
 43				)
 44			end
 45		end
 46
 47		using FormToH
 48
 49		def to_response(form)
 50			OpenStruct.new(form.to_h)
 51		end
 52	end
 53end
 54
 55def info(tel)
 56	CustomerInfo.new(
 57		plan_info: PlanInfo::NoPlan.new,
 58		tel: tel,
 59		balance: 0.to_d,
 60		cnam: nil
 61	)
 62end
 63
 64def admin_info(customer_id, tel)
 65	AdminInfo.new(
 66		jid: Blather::JID.new("#{customer_id}@example.com"),
 67		customer_id: customer_id,
 68		fwd: nil,
 69		info: info(tel),
 70		call_info: "",
 71		trust_level: "",
 72		backend: BackendSgx.new(
 73			jid: Blather::JID.new("testroute"),
 74			from_jid: Blather::JID.new("customer_#{customer_id}@example.com"),
 75			creds: {},
 76			transcription_enabled: false,
 77			registered?: false,
 78			fwd: nil,
 79			ogm_url: nil
 80		)
 81	)
 82end
 83
 84def menu
 85	FormTemplate.render("admin_menu")
 86end
 87
 88class PortingStepTest < Minitest::Test
 89	Port = Struct.new(
 90		:order_id,
 91		:processing_status,
 92		:actual_foc_date,
 93		:last_modified_date,
 94		:customer_order_id,
 95		:billing_telephone_number
 96	)
 97
 98	def test_ignore_submitted_ports
 99		redis = Minitest::Mock.new
100		redis.expect(:exists, EMPromise.resolve(0), ["jmp_port_freeze-01"])
101
102		step = PortingStepRepo.new(redis: redis).find(Port.new(
103			"01",
104			"SUBMITTED",
105			nil,
106			DateTime.now - 1 * MINS,
107			"ignored",
108			"9998887777"
109		)).sync
110
111		assert_kind_of PortingStepRepo::Wait, step
112	end
113	em :test_ignore_submitted_ports
114
115	def test_ignore_recent_foc
116		redis = Minitest::Mock.new
117		redis.expect(:exists, EMPromise.resolve(0), ["jmp_port_freeze-01"])
118
119		step = PortingStepRepo.new(redis: redis).find(Port.new(
120			"01",
121			"FOC",
122			DateTime.now - 5 * MINS,
123			DateTime.now - 1 * MINS,
124			"ignored",
125			"9998887777"
126		)).sync
127
128		assert_kind_of PortingStepRepo::Wait, step
129	end
130	em :test_ignore_recent_foc
131
132	def test_warn_for_late_foc
133		redis = Minitest::Mock.new
134		redis.expect(:exists, EMPromise.resolve(0), ["jmp_port_freeze-01"])
135
136		step = PortingStepRepo.new(redis: redis).find(Port.new(
137			"01",
138			"FOC",
139			DateTime.now - 25 * MINS,
140			DateTime.now - 1 * MINS,
141			"ignored",
142			"9998887777"
143		)).sync
144
145		assert_kind_of PortingStepRepo::Alert, step
146		assert_equal :late_foc, step.key
147		assert_kind_of PortingStepRepo::Wait, step.real_step
148	end
149	em :test_warn_for_late_foc
150
151	def test_already_complete
152		redis = Minitest::Mock.new
153		redis.expect(:exists, EMPromise.resolve(0), ["jmp_port_freeze-01"])
154		redis.expect(:exists, 1, ["jmp_port_complete-01"])
155
156		step = PortingStepRepo.new(redis: redis).find(Port.new(
157			"01",
158			"COMPLETE",
159			DateTime.now - 25 * MINS,
160			DateTime.now - 1 * MINS,
161			"completed",
162			"9998887777"
163		)).sync
164
165		assert_kind_of PortingStepRepo::Done, step
166		assert_mock redis
167	end
168	em :test_already_complete
169
170	def test_change_number
171		redis = Minitest::Mock.new
172		redis.expect(:exists, EMPromise.resolve(0), ["jmp_port_freeze-01"])
173		redis.expect(:exists, "0", ["jmp_port_complete-01"])
174
175		notify = BlatherNotifyMock.new
176		notify.expect_execution(
177			"sgx", "customer info",
178			{ q: "starting" }, admin_info("starting", "+19998881111").form
179		)
180
181		step = PortingStepRepo.new(
182			redis: redis,
183			blather_notify: notify,
184			admin_server: "sgx"
185		).find(Port.new(
186			"01",
187			"COMPLETE",
188			DateTime.now - 25 * MINS,
189			DateTime.now - 1 * MINS,
190			"starting",
191			"9998887777"
192		)).sync
193
194		assert_kind_of PortingStepRepo::Complete::AdminCommand::WrongNumber, step
195		assert_mock redis
196		assert_mock notify
197	end
198	em :test_change_number
199
200	def test_first_reachability
201		redis = Minitest::Mock.new
202		redis.expect(:exists, EMPromise.resolve(0), ["jmp_port_freeze-01"])
203		redis.expect(:exists, "0", ["jmp_port_complete-01"])
204
205		notify = BlatherNotifyMock.new
206		notify.expect_execution(
207			"sgx", "customer info",
208			{ q: "starting" }, admin_info("starting", "+19998887777").form
209		)
210
211		notify.expect_execution(
212			"sgx", "reachability",
213			{ tel: "9998887777", type: "voice" },
214			FormTemplate.render("reachability_result", count: 0)
215		)
216
217		step = PortingStepRepo.new(
218			redis: redis,
219			blather_notify: notify,
220			admin_server: "sgx"
221		).find(Port.new(
222			"01",
223			"COMPLETE",
224			DateTime.now - 25 * MINS,
225			DateTime.now - 1 * MINS,
226			"starting",
227			"9998887777"
228		)).sync
229
230		assert_kind_of(
231			PortingStepRepo::Complete::AdminCommand::GoodNumber::
232				Reachability::RunTest,
233			step
234		)
235		assert_equal "voice", step.type
236		assert_mock redis
237		assert_mock notify
238	end
239	em :test_first_reachability
240
241	def test_reach_sms_reachability
242		redis = Minitest::Mock.new
243		redis.expect(:exists, EMPromise.resolve(0), ["jmp_port_freeze-01"])
244		redis.expect(:exists, "0", ["jmp_port_complete-01"])
245
246		notify = BlatherNotifyMock.new
247		notify.expect_execution(
248			"sgx", "customer info",
249			{ q: "starting" }, admin_info("starting", "+19998887777").form
250		)
251
252		notify.expect_execution(
253			"sgx", "reachability",
254			{ tel: "9998887777", type: "voice" },
255			FormTemplate.render("reachability_result", count: 1)
256		)
257
258		notify.expect_execution(
259			"sgx", "reachability",
260			{ tel: "9998887777", type: "sms" },
261			FormTemplate.render("reachability_result", count: 0)
262		)
263
264		step = PortingStepRepo.new(
265			redis: redis,
266			blather_notify: notify,
267			admin_server: "sgx"
268		).find(Port.new(
269			"01",
270			"COMPLETE",
271			DateTime.now - 25 * MINS,
272			DateTime.now - 1 * MINS,
273			"starting",
274			"9998887777"
275		)).sync
276
277		assert_kind_of(
278			PortingStepRepo::Complete::AdminCommand::GoodNumber::
279				Reachability::RunTest,
280			step
281		)
282		assert_equal "sms", step.type
283		assert_mock redis
284		assert_mock notify
285	end
286	em :test_reach_sms_reachability
287
288	def test_all_reachable
289		redis = Minitest::Mock.new
290		redis.expect(:exists, EMPromise.resolve(0), ["jmp_port_freeze-01"])
291		redis.expect(:exists, "0", ["jmp_port_complete-01"])
292
293		notify = BlatherNotifyMock.new
294		notify.expect_execution(
295			"sgx", "customer info",
296			{ q: "starting" }, admin_info("starting", "+19998887777").form
297		)
298
299		notify.expect_execution(
300			"sgx", "reachability",
301			{ tel: "9998887777", type: "voice" },
302			FormTemplate.render("reachability_result", count: 1)
303		)
304
305		notify.expect_execution(
306			"sgx", "reachability",
307			{ tel: "9998887777", type: "sms" },
308			FormTemplate.render("reachability_result", count: 1)
309		)
310
311		step = PortingStepRepo.new(
312			redis: redis,
313			blather_notify: notify,
314			admin_server: "sgx"
315		).find(Port.new(
316			"01",
317			"COMPLETE",
318			DateTime.now - 25 * MINS,
319			DateTime.now - 1 * MINS,
320			"starting",
321			"9998887777"
322		)).sync
323
324		assert_kind_of(
325			PortingStepRepo::Complete::AdminCommand::GoodNumber::FinishUp,
326			step
327		)
328		assert_mock redis
329		assert_mock notify
330	end
331	em :test_all_reachable
332
333	def test_not_done_in_time
334		redis = Minitest::Mock.new
335		redis.expect(:exists, EMPromise.resolve(0), ["jmp_port_freeze-01"])
336		redis.expect(:exists, "0", ["jmp_port_complete-01"])
337
338		notify = BlatherNotifyMock.new
339		notify.expect_execution(
340			"sgx", "customer info",
341			{ q: "starting" }, admin_info("starting", "+19998887777").form
342		)
343
344		notify.expect_execution(
345			"sgx", "reachability",
346			{ tel: "9998887777", type: "voice" },
347			FormTemplate.render("reachability_result", count: 0)
348		)
349
350		step = PortingStepRepo.new(
351			redis: redis,
352			blather_notify: notify,
353			admin_server: "sgx"
354		).find(Port.new(
355			"01",
356			"COMPLETE",
357			DateTime.now - 55 * MINS,
358			DateTime.now - 50 * MINS,
359			"starting",
360			"9998887777"
361		)).sync
362
363		assert_kind_of PortingStepRepo::Alert, step
364		assert_equal :late_finish, step.key
365		assert_kind_of(
366			PortingStepRepo::Complete::AdminCommand::GoodNumber::
367				Reachability::RunTest,
368			step.real_step
369		)
370		assert_mock redis
371		assert_mock notify
372	end
373	em :test_not_done_in_time
374
375	def test_ignore_frozen_ports
376		# This tests that we ignore ports in various states
377		[
378			Port.new(
379				"01",
380				"SUBMITTED",
381				nil,
382				DateTime.now - 1 * MINS,
383				"ignored",
384				"9998887777"
385			),
386			Port.new(
387				"01",
388				"FOC",
389				DateTime.now - 300 * MINS,
390				DateTime.now - 300 * MINS,
391				"ignored",
392				"9998887777"
393			),
394			Port.new(
395				"01",
396				"COMPLETED",
397				DateTime.now - 10 * MINS,
398				DateTime.now - 10 * MINS,
399				"ignored",
400				"9998887777"
401			),
402			Port.new(
403				"01",
404				"COMPLETED",
405				DateTime.now - 300 * MINS,
406				DateTime.now - 300 * MINS,
407				"ignored",
408				"9998887777"
409			)
410		].each do |port|
411			redis = Minitest::Mock.new
412			redis.expect(:exists, EMPromise.resolve(1), ["jmp_port_freeze-01"])
413
414			step = PortingStepRepo.new(redis: redis).find(port).sync
415			assert_kind_of PortingStepRepo::Frozen, step
416		end
417	end
418	em :test_ignore_frozen_ports
419end