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