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_jid: "customer_#{customer_id}@example.com"
 73	)
 74end
 75
 76def menu
 77	FormTemplate.render("admin_menu")
 78end
 79
 80class PortingStepTest < Minitest::Test
 81	Port = Struct.new(
 82		:order_id,
 83		:processing_status,
 84		:actual_foc_date,
 85		:last_modified_date,
 86		:customer_order_id,
 87		:billing_telephone_number
 88	)
 89
 90	def test_ignore_submitted_ports
 91		redis = Minitest::Mock.new
 92		redis.expect(:exists, EMPromise.resolve(0), ["jmp_port_freeze-01"])
 93
 94		step = PortingStepRepo.new(redis: redis).find(Port.new(
 95			"01",
 96			"SUBMITTED",
 97			nil,
 98			DateTime.now - 1 * MINS,
 99			"ignored",
100			"9998887777"
101		)).sync
102
103		assert_kind_of PortingStepRepo::Wait, step
104	end
105	em :test_ignore_submitted_ports
106
107	def test_ignore_recent_foc
108		redis = Minitest::Mock.new
109		redis.expect(:exists, EMPromise.resolve(0), ["jmp_port_freeze-01"])
110
111		step = PortingStepRepo.new(redis: redis).find(Port.new(
112			"01",
113			"FOC",
114			DateTime.now - 5 * MINS,
115			DateTime.now - 1 * MINS,
116			"ignored",
117			"9998887777"
118		)).sync
119
120		assert_kind_of PortingStepRepo::Wait, step
121	end
122	em :test_ignore_recent_foc
123
124	def test_warn_for_late_foc
125		redis = Minitest::Mock.new
126		redis.expect(:exists, EMPromise.resolve(0), ["jmp_port_freeze-01"])
127
128		step = PortingStepRepo.new(redis: redis).find(Port.new(
129			"01",
130			"FOC",
131			DateTime.now - 25 * MINS,
132			DateTime.now - 1 * MINS,
133			"ignored",
134			"9998887777"
135		)).sync
136
137		assert_kind_of PortingStepRepo::Alert, step
138		assert_equal :late_foc, step.key
139		assert_kind_of PortingStepRepo::Wait, step.real_step
140	end
141	em :test_warn_for_late_foc
142
143	def test_already_complete
144		redis = Minitest::Mock.new
145		redis.expect(:exists, EMPromise.resolve(0), ["jmp_port_freeze-01"])
146		redis.expect(:exists, 1, ["jmp_port_complete-01"])
147
148		step = PortingStepRepo.new(redis: redis).find(Port.new(
149			"01",
150			"COMPLETE",
151			DateTime.now - 25 * MINS,
152			DateTime.now - 1 * MINS,
153			"completed",
154			"9998887777"
155		)).sync
156
157		assert_kind_of PortingStepRepo::Done, step
158		assert_mock redis
159	end
160	em :test_already_complete
161
162	def test_change_number
163		redis = Minitest::Mock.new
164		redis.expect(:exists, EMPromise.resolve(0), ["jmp_port_freeze-01"])
165		redis.expect(:exists, "0", ["jmp_port_complete-01"])
166
167		notify = BlatherNotifyMock.new
168		notify.expect_execution(
169			"sgx", "customer info",
170			{ q: "starting" }, admin_info("starting", "+19998881111").form
171		)
172
173		step = PortingStepRepo.new(
174			redis: redis,
175			blather_notify: notify,
176			admin_server: "sgx"
177		).find(Port.new(
178			"01",
179			"COMPLETE",
180			DateTime.now - 25 * MINS,
181			DateTime.now - 1 * MINS,
182			"starting",
183			"9998887777"
184		)).sync
185
186		assert_kind_of PortingStepRepo::Complete::AdminCommand::WrongNumber, step
187		assert_mock redis
188		assert_mock notify
189	end
190	em :test_change_number
191
192	def test_first_reachability
193		redis = Minitest::Mock.new
194		redis.expect(:exists, EMPromise.resolve(0), ["jmp_port_freeze-01"])
195		redis.expect(:exists, "0", ["jmp_port_complete-01"])
196
197		notify = BlatherNotifyMock.new
198		notify.expect_execution(
199			"sgx", "customer info",
200			{ q: "starting" }, admin_info("starting", "+19998887777").form
201		)
202
203		notify.expect_execution(
204			"sgx", "reachability",
205			{ tel: "9998887777", type: "voice" },
206			FormTemplate.render("reachability_result", count: 0)
207		)
208
209		step = PortingStepRepo.new(
210			redis: redis,
211			blather_notify: notify,
212			admin_server: "sgx"
213		).find(Port.new(
214			"01",
215			"COMPLETE",
216			DateTime.now - 25 * MINS,
217			DateTime.now - 1 * MINS,
218			"starting",
219			"9998887777"
220		)).sync
221
222		assert_kind_of(
223			PortingStepRepo::Complete::AdminCommand::GoodNumber::
224				Reachability::RunTest,
225			step
226		)
227		assert_equal "voice", step.type
228		assert_mock redis
229		assert_mock notify
230	end
231	em :test_first_reachability
232
233	def test_reach_sms_reachability
234		redis = Minitest::Mock.new
235		redis.expect(:exists, EMPromise.resolve(0), ["jmp_port_freeze-01"])
236		redis.expect(:exists, "0", ["jmp_port_complete-01"])
237
238		notify = BlatherNotifyMock.new
239		notify.expect_execution(
240			"sgx", "customer info",
241			{ q: "starting" }, admin_info("starting", "+19998887777").form
242		)
243
244		notify.expect_execution(
245			"sgx", "reachability",
246			{ tel: "9998887777", type: "voice" },
247			FormTemplate.render("reachability_result", count: 1)
248		)
249
250		notify.expect_execution(
251			"sgx", "reachability",
252			{ tel: "9998887777", type: "sms" },
253			FormTemplate.render("reachability_result", count: 0)
254		)
255
256		step = PortingStepRepo.new(
257			redis: redis,
258			blather_notify: notify,
259			admin_server: "sgx"
260		).find(Port.new(
261			"01",
262			"COMPLETE",
263			DateTime.now - 25 * MINS,
264			DateTime.now - 1 * MINS,
265			"starting",
266			"9998887777"
267		)).sync
268
269		assert_kind_of(
270			PortingStepRepo::Complete::AdminCommand::GoodNumber::
271				Reachability::RunTest,
272			step
273		)
274		assert_equal "sms", step.type
275		assert_mock redis
276		assert_mock notify
277	end
278	em :test_reach_sms_reachability
279
280	def test_all_reachable
281		redis = Minitest::Mock.new
282		redis.expect(:exists, EMPromise.resolve(0), ["jmp_port_freeze-01"])
283		redis.expect(:exists, "0", ["jmp_port_complete-01"])
284
285		notify = BlatherNotifyMock.new
286		notify.expect_execution(
287			"sgx", "customer info",
288			{ q: "starting" }, admin_info("starting", "+19998887777").form
289		)
290
291		notify.expect_execution(
292			"sgx", "reachability",
293			{ tel: "9998887777", type: "voice" },
294			FormTemplate.render("reachability_result", count: 1)
295		)
296
297		notify.expect_execution(
298			"sgx", "reachability",
299			{ tel: "9998887777", type: "sms" },
300			FormTemplate.render("reachability_result", count: 1)
301		)
302
303		step = PortingStepRepo.new(
304			redis: redis,
305			blather_notify: notify,
306			admin_server: "sgx"
307		).find(Port.new(
308			"01",
309			"COMPLETE",
310			DateTime.now - 25 * MINS,
311			DateTime.now - 1 * MINS,
312			"starting",
313			"9998887777"
314		)).sync
315
316		assert_kind_of(
317			PortingStepRepo::Complete::AdminCommand::GoodNumber::FinishUp,
318			step
319		)
320		assert_mock redis
321		assert_mock notify
322	end
323	em :test_all_reachable
324
325	def test_not_done_in_time
326		redis = Minitest::Mock.new
327		redis.expect(:exists, EMPromise.resolve(0), ["jmp_port_freeze-01"])
328		redis.expect(:exists, "0", ["jmp_port_complete-01"])
329
330		notify = BlatherNotifyMock.new
331		notify.expect_execution(
332			"sgx", "customer info",
333			{ q: "starting" }, admin_info("starting", "+19998887777").form
334		)
335
336		notify.expect_execution(
337			"sgx", "reachability",
338			{ tel: "9998887777", type: "voice" },
339			FormTemplate.render("reachability_result", count: 0)
340		)
341
342		step = PortingStepRepo.new(
343			redis: redis,
344			blather_notify: notify,
345			admin_server: "sgx"
346		).find(Port.new(
347			"01",
348			"COMPLETE",
349			DateTime.now - 55 * MINS,
350			DateTime.now - 50 * MINS,
351			"starting",
352			"9998887777"
353		)).sync
354
355		assert_kind_of PortingStepRepo::Alert, step
356		assert_equal :late_finish, step.key
357		assert_kind_of(
358			PortingStepRepo::Complete::AdminCommand::GoodNumber::
359				Reachability::RunTest,
360			step.real_step
361		)
362		assert_mock redis
363		assert_mock notify
364	end
365	em :test_not_done_in_time
366
367	def test_ignore_frozen_ports
368		# This tests that we ignore ports in various states
369		[
370			Port.new(
371				"01",
372				"SUBMITTED",
373				nil,
374				DateTime.now - 1 * MINS,
375				"ignored",
376				"9998887777"
377			),
378			Port.new(
379				"01",
380				"FOC",
381				DateTime.now - 300 * MINS,
382				DateTime.now - 300 * MINS,
383				"ignored",
384				"9998887777"
385			),
386			Port.new(
387				"01",
388				"COMPLETED",
389				DateTime.now - 10 * MINS,
390				DateTime.now - 10 * MINS,
391				"ignored",
392				"9998887777"
393			),
394			Port.new(
395				"01",
396				"COMPLETED",
397				DateTime.now - 300 * MINS,
398				DateTime.now - 300 * MINS,
399				"ignored",
400				"9998887777"
401			)
402		].each do |port|
403			redis = Minitest::Mock.new
404			redis.expect(:exists, EMPromise.resolve(1), ["jmp_port_freeze-01"])
405
406			step = PortingStepRepo.new(redis: redis).find(port).sync
407			assert_kind_of PortingStepRepo::Frozen, step
408		end
409	end
410	em :test_ignore_frozen_ports
411end