test_porting_step.rb

  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_repo"
 11require "port_repo"
 12
 13MINS = 1.0 / (24 * 60)
 14
 15class BlatherNotifyMock < Minitest::Mock
 16	def initialize
 17		super
 18		@exes = []
 19	end
 20
 21	def expect_execution(server, node, *args)
 22		exe = Execution.new(args)
 23		expect(
 24			:command_execution,
 25			exe,
 26			[server, node]
 27		)
 28		@exes << exe
 29	end
 30
 31	def verify
 32		super
 33		@exes.each(&:verify)
 34	end
 35
 36	class Execution < Minitest::Mock
 37		def initialize(args)
 38			super()
 39			args.each_slice(2) do |(submission, result)|
 40				expect(
 41					:fetch_and_submit,
 42					to_promise(result),
 43					**submission
 44				)
 45			end
 46		end
 47
 48		using FormToH
 49
 50		def to_promise(result)
 51			if result.is_a?(Exception)
 52				EMPromise.reject(result)
 53			else
 54				EMPromise.resolve(to_response(result))
 55			end
 56		end
 57
 58		def to_response(form)
 59			OpenStruct.new(form.to_h)
 60		end
 61	end
 62end
 63
 64def info(tel)
 65	CustomerInfo.new(
 66		plan_info: PlanInfo::NoPlan.new,
 67		tel: tel,
 68		balance: 0.to_d,
 69		cnam: nil
 70	)
 71end
 72
 73def admin_info(customer_id, tel)
 74	AdminInfo.new(
 75		jid: Blather::JID.new("#{customer_id}@example.com"),
 76		customer_id: customer_id,
 77		fwd: nil,
 78		info: info(tel),
 79		call_info: "",
 80		trust_level: "",
 81		backend: BackendSgx.new(
 82			jid: Blather::JID.new("testroute"),
 83			from_jid: Blather::JID.new("customer_#{customer_id}@example.com"),
 84			creds: {},
 85			transcription_enabled: false,
 86			registered?: false,
 87			fwd: nil,
 88			ogm_url: nil
 89		)
 90	)
 91end
 92
 93def menu
 94	FormTemplate.render("admin_menu")
 95end
 96
 97class PortingStepTest < Minitest::Test
 98	Port = Struct.new(
 99		:id,
100		:processing_status,
101		:actual_foc_date,
102		:updated_at,
103		:customer_id,
104		:tel,
105		:backend_sgx
106	)
107
108	def test_ignore_submitted_ports
109		redis = Minitest::Mock.new
110		redis.expect(:exists, EMPromise.resolve(0), ["jmp_port_freeze-01"])
111
112		step = PortingStepRepo.new(redis: redis).find(Port.new(
113			"01",
114			"SUBMITTED",
115			nil,
116			DateTime.now - 1 * MINS,
117			"ignored",
118			"9998887777",
119			Blather::JID.new("testroute")
120		)).sync
121
122		assert_kind_of PortingStepRepo::Wait, step
123	end
124	em :test_ignore_submitted_ports
125
126	def test_ignore_recent_foc
127		redis = Minitest::Mock.new
128		redis.expect(:exists, EMPromise.resolve(0), ["jmp_port_freeze-01"])
129
130		step = PortingStepRepo.new(redis: redis).find(Port.new(
131			"01",
132			"FOC",
133			DateTime.now - 5 * MINS,
134			DateTime.now - 1 * MINS,
135			"ignored",
136			"9998887777",
137			Blather::JID.new("testroute")
138		)).sync
139
140		assert_kind_of PortingStepRepo::Wait, step
141	end
142	em :test_ignore_recent_foc
143
144	def test_warn_for_late_foc
145		redis = Minitest::Mock.new
146		redis.expect(:exists, EMPromise.resolve(0), ["jmp_port_freeze-01"])
147
148		step = PortingStepRepo.new(redis: redis).find(Port.new(
149			"01",
150			"FOC",
151			DateTime.now - 25 * MINS,
152			DateTime.now - 1 * MINS,
153			"ignored",
154			"9998887777",
155			Blather::JID.new("testroute")
156		)).sync
157
158		assert_kind_of PortingStepRepo::Alert, step
159		assert_equal :late_foc, step.key
160		assert_kind_of PortingStepRepo::Wait, step.real_step
161	end
162	em :test_warn_for_late_foc
163
164	def test_already_complete
165		redis = Minitest::Mock.new
166		redis.expect(:exists, EMPromise.resolve(0), ["jmp_port_freeze-01"])
167		redis.expect(:exists, 1, ["jmp_port_complete-01"])
168
169		step = PortingStepRepo.new(redis: redis).find(Port.new(
170			"01",
171			"COMPLETE",
172			DateTime.now - 25 * MINS,
173			DateTime.now - 1 * MINS,
174			"completed",
175			"9998887777",
176			Blather::JID.new("testroute")
177		)).sync
178
179		assert_kind_of PortingStepRepo::Done, step
180		assert_mock redis
181	end
182	em :test_already_complete
183
184	def test_change_number
185		redis = Minitest::Mock.new
186		redis.expect(:exists, EMPromise.resolve(0), ["jmp_port_freeze-01"])
187		redis.expect(:exists, "0", ["jmp_port_complete-01"])
188
189		notify = BlatherNotifyMock.new
190		notify.expect_execution(
191			"sgx", "customer info",
192			{ q: "starting" }, admin_info("starting", "+19998881111").form
193		)
194
195		step = PortingStepRepo.new(
196			redis: redis,
197			blather_notify: notify,
198			admin_server: "sgx"
199		).find(Port.new(
200			"01",
201			"COMPLETE",
202			DateTime.now - 25 * MINS,
203			DateTime.now - 1 * MINS,
204			"starting",
205			"9998887777",
206			Blather::JID.new("testroute")
207		)).sync
208
209		assert_kind_of PortingStepRepo::Complete::AdminCommand::WrongNumber, step
210		assert_equal Blather::JID.new("testroute"), step.new_backend
211		assert_mock redis
212		assert_mock notify
213	end
214	em :test_change_number
215
216	def test_unknown_customer
217		redis = Minitest::Mock.new
218		redis.expect(:exists, EMPromise.resolve(0), ["jmp_port_freeze-01"])
219		redis.expect(:exists, "0", ["jmp_port_complete-01"])
220
221		notify = BlatherNotifyMock.new
222		notify.expect_execution(
223			"sgx", "customer info",
224			{ q: "unknown_customer" }, admin_info("unknown_customer", nil).form
225		)
226
227		step = PortingStepRepo.new(
228			redis: redis,
229			blather_notify: notify,
230			admin_server: "sgx"
231		).find(Port.new(
232			"01",
233			"COMPLETE",
234			DateTime.now - 25 * MINS,
235			DateTime.now - 1 * MINS,
236			"unknown_customer",
237			"9998887777",
238			Blather::JID.new("testroute")
239		)).sync
240
241		assert_kind_of PortingStepRepo::Alert, step
242		assert_equal :port_for_unknown_customer, step.key
243		assert_kind_of PortingStepRepo::Complete::NoCustomer, step.real_step
244		assert_mock redis
245		assert_mock notify
246	end
247	em :test_unknown_customer
248
249	def test_first_reachability
250		redis = Minitest::Mock.new
251		redis.expect(:exists, EMPromise.resolve(0), ["jmp_port_freeze-01"])
252		redis.expect(:exists, "0", ["jmp_port_complete-01"])
253
254		notify = BlatherNotifyMock.new
255		notify.expect_execution(
256			"sgx", "customer info",
257			{ q: "starting" }, admin_info("starting", "+19998887777").form
258		)
259
260		notify.expect_execution(
261			"sgx", "reachability",
262			{ tel: "9998887777", type: "voice" },
263			FormTemplate.render("reachability_result", count: 0)
264		)
265
266		step = PortingStepRepo.new(
267			redis: redis,
268			blather_notify: notify,
269			admin_server: "sgx"
270		).find(Port.new(
271			"01",
272			"COMPLETE",
273			DateTime.now - 25 * MINS,
274			DateTime.now - 1 * MINS,
275			"starting",
276			"9998887777",
277			Blather::JID.new("testroute")
278		)).sync
279
280		assert_kind_of(
281			PortingStepRepo::Complete::AdminCommand::GoodNumber::
282				Reachability::RunTest,
283			step
284		)
285		assert_equal "voice", step.type
286		assert_mock redis
287		assert_mock notify
288	end
289	em :test_first_reachability
290
291	def test_reach_sms_reachability
292		redis = Minitest::Mock.new
293		redis.expect(:exists, EMPromise.resolve(0), ["jmp_port_freeze-01"])
294		redis.expect(:exists, "0", ["jmp_port_complete-01"])
295
296		notify = BlatherNotifyMock.new
297		notify.expect_execution(
298			"sgx", "customer info",
299			{ q: "starting" }, admin_info("starting", "+19998887777").form
300		)
301
302		notify.expect_execution(
303			"sgx", "reachability",
304			{ tel: "9998887777", type: "voice" },
305			FormTemplate.render("reachability_result", count: 1)
306		)
307
308		notify.expect_execution(
309			"sgx", "reachability",
310			{ tel: "9998887777", type: "sms" },
311			FormTemplate.render("reachability_result", count: 0)
312		)
313
314		step = PortingStepRepo.new(
315			redis: redis,
316			blather_notify: notify,
317			admin_server: "sgx"
318		).find(Port.new(
319			"01",
320			"COMPLETE",
321			DateTime.now - 25 * MINS,
322			DateTime.now - 1 * MINS,
323			"starting",
324			"9998887777",
325			Blather::JID.new("testroute")
326		)).sync
327
328		assert_kind_of(
329			PortingStepRepo::Complete::AdminCommand::GoodNumber::
330				Reachability::RunTest,
331			step
332		)
333		assert_equal "sms", step.type
334		assert_mock redis
335		assert_mock notify
336	end
337	em :test_reach_sms_reachability
338
339	def test_all_reachable
340		redis = Minitest::Mock.new
341		redis.expect(:exists, EMPromise.resolve(0), ["jmp_port_freeze-01"])
342		redis.expect(:exists, "0", ["jmp_port_complete-01"])
343
344		notify = BlatherNotifyMock.new
345		notify.expect_execution(
346			"sgx", "customer info",
347			{ q: "starting" }, admin_info("starting", "+19998887777").form
348		)
349
350		notify.expect_execution(
351			"sgx", "reachability",
352			{ tel: "9998887777", type: "voice" },
353			FormTemplate.render("reachability_result", count: 1)
354		)
355
356		notify.expect_execution(
357			"sgx", "reachability",
358			{ tel: "9998887777", type: "sms" },
359			FormTemplate.render("reachability_result", count: 1)
360		)
361
362		step = PortingStepRepo.new(
363			redis: redis,
364			blather_notify: notify,
365			admin_server: "sgx"
366		).find(Port.new(
367			"01",
368			"COMPLETE",
369			DateTime.now - 25 * MINS,
370			DateTime.now - 1 * MINS,
371			"starting",
372			"9998887777",
373			Blather::JID.new("testroute")
374		)).sync
375
376		assert_kind_of(
377			PortingStepRepo::Complete::AdminCommand::GoodNumber::FinishUp,
378			step
379		)
380		assert_mock redis
381		assert_mock notify
382	end
383	em :test_all_reachable
384
385	def test_not_done_in_time
386		redis = Minitest::Mock.new
387		redis.expect(:exists, EMPromise.resolve(0), ["jmp_port_freeze-01"])
388		redis.expect(:exists, "0", ["jmp_port_complete-01"])
389
390		notify = BlatherNotifyMock.new
391		notify.expect_execution(
392			"sgx", "customer info",
393			{ q: "starting" }, admin_info("starting", "+19998887777").form
394		)
395
396		notify.expect_execution(
397			"sgx", "reachability",
398			{ tel: "9998887777", type: "voice" },
399			FormTemplate.render("reachability_result", count: 0)
400		)
401
402		step = PortingStepRepo.new(
403			redis: redis,
404			blather_notify: notify,
405			admin_server: "sgx"
406		).find(Port.new(
407			"01",
408			"COMPLETE",
409			DateTime.now - 55 * MINS,
410			DateTime.now - 50 * MINS,
411			"starting",
412			"9998887777",
413			Blather::JID.new("testroute")
414		)).sync
415
416		assert_kind_of PortingStepRepo::Alert, step
417		assert_equal :late_finish, step.key
418		assert_kind_of(
419			PortingStepRepo::Complete::AdminCommand::GoodNumber::
420				Reachability::RunTest,
421			step.real_step
422		)
423		assert_mock redis
424		assert_mock notify
425	end
426	em :test_not_done_in_time
427
428	def test_ignore_frozen_ports
429		# This tests that we ignore ports in various states
430		[
431			Port.new(
432				"01",
433				"SUBMITTED",
434				nil,
435				DateTime.now - 1 * MINS,
436				"ignored",
437				"9998887777",
438				Blather::JID.new("testroute")
439			),
440			Port.new(
441				"01",
442				"FOC",
443				DateTime.now - 300 * MINS,
444				DateTime.now - 300 * MINS,
445				"ignored",
446				"9998887777",
447				Blather::JID.new("testroute")
448			),
449			Port.new(
450				"01",
451				"COMPLETED",
452				DateTime.now - 10 * MINS,
453				DateTime.now - 10 * MINS,
454				"ignored",
455				"9998887777",
456				Blather::JID.new("testroute")
457			),
458			Port.new(
459				"01",
460				"COMPLETED",
461				DateTime.now - 300 * MINS,
462				DateTime.now - 300 * MINS,
463				"ignored",
464				"9998887777",
465				Blather::JID.new("testroute")
466			)
467		].each do |port|
468			redis = Minitest::Mock.new
469			redis.expect(:exists, EMPromise.resolve(1), ["jmp_port_freeze-01"])
470
471			step = PortingStepRepo.new(redis: redis).find(port).sync
472			assert_kind_of PortingStepRepo::Frozen, step
473		end
474	end
475	em :test_ignore_frozen_ports
476
477	def test_reachability_error_during_find
478		redis = Minitest::Mock.new
479		redis.expect(:exists, EMPromise.resolve(0), ["jmp_port_freeze-01"])
480		redis.expect(:exists, "0", ["jmp_port_complete-01"])
481
482		notify = BlatherNotifyMock.new
483		notify.expect_execution(
484			"sgx", "customer info",
485			{ q: "starting" }, admin_info("starting", "+19998887777").form
486		)
487
488		notify.expect_execution(
489			"sgx", "reachability",
490			{ tel: "9998887777", type: "voice" },
491			RuntimeError.new("Sender not in whitelist")
492		)
493
494		step = PortingStepRepo.new(
495			redis: redis,
496			blather_notify: notify,
497			admin_server: "sgx"
498		).find(Port.new(
499			"01",
500			"COMPLETE",
501			DateTime.now - 25 * MINS,
502			DateTime.now - 1 * MINS,
503			"starting",
504			"9998887777",
505			Blather::JID.new("testroute")
506		)).sync
507
508		assert_kind_of PortingStepRepo::Alert, step
509		assert_equal :reachability_failure, step.key
510		assert_nil step.real_step
511		assert_mock redis
512		assert_mock notify
513	end
514	em :test_reachability_error_during_find
515
516	def test_reachability_error_during_run_test
517		redis = Minitest::Mock.new
518		redis.expect(:exists, EMPromise.resolve(0), ["jmp_port_freeze-01"])
519		redis.expect(:exists, "0", ["jmp_port_complete-01"])
520
521		notify = BlatherNotifyMock.new
522		notify.expect_execution(
523			"sgx", "customer info",
524			{ q: "starting" }, admin_info("starting", "+19998887777").form
525		)
526
527		notify.expect_execution(
528			"sgx", "reachability",
529			{ tel: "9998887777", type: "voice" },
530			FormTemplate.render("reachability_result", count: 0)
531		)
532
533		notify.expect_execution(
534			"sgx", "reachability",
535			{ tel: "9998887777", type: "voice", reachability_tel: "+15551234567" },
536			RuntimeError.new("Sender not in whitelist")
537		)
538
539		output_mock = Minitest::Mock.new
540		output_mock.expect(
541			:warn,
542			EMPromise.resolve(nil),
543			[
544				"01",
545				:reachability_failure,
546				Matching.new { |m| m =~ /Error checking.*reachability/ }
547			]
548		)
549		output = MockOutputs.new(output_mock)
550
551		port = Port.new(
552			"01",
553			"COMPLETE",
554			DateTime.now - 25 * MINS,
555			DateTime.now - 1 * MINS,
556			"starting",
557			"9998887777",
558			Blather::JID.new("testroute")
559		)
560
561		step = PortingStepRepo.new(
562			redis: redis,
563			blather_notify: notify,
564			admin_server: "sgx",
565			output: output,
566			testing_tel: "+15551234567"
567		).find(port).sync
568
569		assert_kind_of(
570			PortingStepRepo::Complete::AdminCommand::GoodNumber::
571				Reachability::RunTest,
572			step
573		)
574
575		step.perform_next_step.sync
576
577		assert_mock redis
578		assert_mock notify
579		assert_mock output_mock
580	end
581	em :test_reachability_error_during_run_test
582end