8 #include "proc-service.h"
10 // Tests of process-service related functionality.
12 // These tests work mostly by completely mocking out the base_process_service class. The mock
13 // implementations can be found in test-baseproc.cc.
15 extern eventloop_t event_loop;
17 constexpr static auto REG = dependency_type::REGULAR;
18 constexpr static auto WAITS = dependency_type::WAITS_FOR;
20 // Friend interface to access base_process_service private/protected members.
21 class base_process_service_test
24 static void exec_succeeded(base_process_service *bsp)
26 bsp->waiting_for_execstat = false;
27 bsp->exec_succeeded();
30 static void exec_failed(base_process_service *bsp, int errcode)
33 err.stage = exec_stage::DO_EXEC;
34 err.st_errno = errcode;
35 bsp->waiting_for_execstat = false;
36 bsp->exec_failed(err);
39 static void handle_exit(base_process_service *bsp, int exit_status)
42 bsp->handle_exit_status(bp_sys::exit_status(true, false, exit_status));
45 static void handle_signal_exit(base_process_service *bsp, int signo)
48 bsp->handle_exit_status(bp_sys::exit_status(false, true, signo));
51 static int get_notification_fd(base_process_service *bsp)
53 return bsp->notification_fd;
59 extern int last_sig_sent;
60 extern pid_t last_forked_pid;
63 static void init_service_defaults(base_process_service &ps)
65 ps.set_restart_interval(time_val(10,0), 3);
66 ps.set_restart_delay(time_val(0, 200000000)); // 200 milliseconds
67 ps.set_stop_timeout(time_val(10,0));
70 // Regular service start
71 void test_proc_service_start()
77 string command = "test-command";
78 list<pair<unsigned,unsigned>> command_offsets;
79 command_offsets.emplace_back(0, command.length());
80 std::list<prelim_dep> depends;
82 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
83 init_service_defaults(p);
87 sset.process_queues();
89 assert(p.get_state() == service_state_t::STARTING);
91 base_process_service_test::exec_succeeded(&p);
92 sset.process_queues();
94 assert(p.get_state() == service_state_t::STARTED);
95 assert(event_loop.active_timers.size() == 0);
97 sset.remove_service(&p);
100 // Test start with readiness notification
101 void test_proc_notify_start()
107 string command = "test-command";
108 list<pair<unsigned,unsigned>> command_offsets;
109 command_offsets.emplace_back(0, command.length());
110 std::list<prelim_dep> depends;
112 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
113 init_service_defaults(p);
114 p.set_notification_fd(3);
115 sset.add_service(&p);
118 sset.process_queues();
120 assert(p.get_state() == service_state_t::STARTING);
122 base_process_service_test::exec_succeeded(&p);
123 sset.process_queues();
125 assert(p.get_state() == service_state_t::STARTING);
127 int nfd = base_process_service_test::get_notification_fd(&p);
130 char notifystr[] = "ok started\n";
131 std::vector<char> rnotifystr;
132 rnotifystr.insert(rnotifystr.end(), notifystr, notifystr + sizeof(notifystr));
133 bp_sys::supply_read_data(nfd, std::move(rnotifystr));
135 event_loop.regd_fd_watchers[nfd]->fd_event(event_loop, nfd, dasynq::IN_EVENTS);
137 assert(p.get_state() == service_state_t::STARTED);
138 assert(event_loop.active_timers.size() == 0);
140 sset.remove_service(&p);
143 // Unexpected termination
144 void test_proc_unexpected_term()
150 string command = "test-command";
151 list<pair<unsigned,unsigned>> command_offsets;
152 command_offsets.emplace_back(0, command.length());
153 std::list<prelim_dep> depends;
155 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
156 init_service_defaults(p);
157 sset.add_service(&p);
160 sset.process_queues();
162 base_process_service_test::exec_succeeded(&p);
163 sset.process_queues();
165 assert(p.get_state() == service_state_t::STARTED);
167 base_process_service_test::handle_exit(&p, 0);
169 assert(p.get_state() == service_state_t::STOPPED);
170 assert(p.get_stop_reason() == stopped_reason_t::TERMINATED);
171 assert(event_loop.active_timers.size() == 0);
173 sset.remove_service(&p);
176 // Unexpected termination with restart
177 void test_proc_term_restart()
183 string command = "test-command";
184 list<pair<unsigned,unsigned>> command_offsets;
185 command_offsets.emplace_back(0, command.length());
186 std::list<prelim_dep> depends;
188 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
189 init_service_defaults(p);
190 p.set_auto_restart(true);
191 sset.add_service(&p);
194 sset.process_queues();
196 base_process_service_test::exec_succeeded(&p);
197 sset.process_queues();
199 assert(p.get_state() == service_state_t::STARTED);
200 assert(event_loop.active_timers.size() == 0);
202 base_process_service_test::handle_exit(&p, 0);
203 sset.process_queues();
205 // Starting, restart timer should be armed:
206 assert(p.get_state() == service_state_t::STARTING);
207 assert(event_loop.active_timers.size() == 1);
209 event_loop.advance_time(time_val(0, 200000000));
210 assert(event_loop.active_timers.size() == 0);
212 sset.process_queues();
213 base_process_service_test::exec_succeeded(&p);
214 sset.process_queues();
216 assert(p.get_state() == service_state_t::STARTED);
217 assert(event_loop.active_timers.size() == 0);
219 sset.remove_service(&p);
222 void test_proc_term_restart2()
228 string command = "test-command";
229 list<pair<unsigned,unsigned>> command_offsets;
230 command_offsets.emplace_back(0, command.length());
231 std::list<prelim_dep> depends;
233 service_record b {&sset, "boot"};
234 sset.add_service(&b);
236 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
237 init_service_defaults(p);
238 p.set_auto_restart(true);
239 sset.add_service(&p);
241 b.add_dep(&p, WAITS);
244 sset.process_queues();
246 assert(p.get_state() == service_state_t::STARTING);
248 base_process_service_test::exec_succeeded(&p);
249 sset.process_queues();
251 assert(p.get_state() == service_state_t::STARTED);
252 assert(event_loop.active_timers.size() == 0);
254 // simulate process terminating, should then be restarted:
255 base_process_service_test::handle_exit(&p, 0);
256 sset.process_queues();
258 // Starting, restart timer should be armed:
259 assert(p.get_state() == service_state_t::STARTING);
260 assert(event_loop.active_timers.size() == 1);
262 event_loop.advance_time(time_val(0, 200000000));
263 assert(event_loop.active_timers.size() == 0);
265 sset.process_queues();
266 base_process_service_test::exec_succeeded(&p);
267 sset.process_queues();
269 assert(p.get_state() == service_state_t::STARTED);
270 assert(event_loop.active_timers.size() == 0);
272 assert(sset.count_active_services() == 2);
274 // Request stop, this time it should not restart:
276 sset.process_queues();
277 base_process_service_test::handle_exit(&p, 0);
278 sset.process_queues();
280 assert(p.get_state() == service_state_t::STOPPED);
281 assert(event_loop.active_timers.size() == 0);
282 assert(sset.count_active_services() == 1);
284 // simulate terminate dinit
285 sset.stop_all_services();
287 //base_process_service_test::handle_exit(&p, 0);
288 sset.process_queues();
290 assert(p.get_state() == service_state_t::STOPPED);
291 assert(event_loop.active_timers.size() == 0);
292 assert(sset.count_active_services() == 0);
294 sset.remove_service(&p);
295 sset.remove_service(&b);
298 // Termination via stop request
299 void test_term_via_stop()
305 string command = "test-command";
306 list<pair<unsigned,unsigned>> command_offsets;
307 command_offsets.emplace_back(0, command.length());
308 std::list<prelim_dep> depends;
310 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
311 init_service_defaults(p);
312 sset.add_service(&p);
315 sset.process_queues();
317 base_process_service_test::exec_succeeded(&p);
318 sset.process_queues();
320 assert(p.get_state() == service_state_t::STARTED);
321 assert(event_loop.active_timers.size() == 0);
324 sset.process_queues();
326 assert(p.get_state() == service_state_t::STOPPING);
327 assert(event_loop.active_timers.size() == 1);
329 base_process_service_test::handle_exit(&p, 0);
330 sset.process_queues();
332 assert(p.get_state() == service_state_t::STOPPED);
333 assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
334 assert(event_loop.active_timers.size() == 0);
336 sset.remove_service(&p);
339 // Termination via stop request, ensure reason is reset:
340 void test_term_via_stop2()
346 string command = "test-command";
347 list<pair<unsigned,unsigned>> command_offsets;
348 command_offsets.emplace_back(0, command.length());
349 std::list<prelim_dep> depends;
351 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
352 init_service_defaults(p);
353 sset.add_service(&p);
356 sset.process_queues();
358 // first set it up with failure reason:
360 base_process_service_test::exec_failed(&p, ENOENT);
361 sset.process_queues();
363 assert(p.get_state() == service_state_t::STOPPED);
364 assert(p.get_stop_reason() == stopped_reason_t::EXECFAILED);
366 // now restart clean:
369 sset.process_queues();
371 base_process_service_test::exec_succeeded(&p);
372 sset.process_queues();
374 assert(p.get_state() == service_state_t::STARTED);
375 assert(event_loop.active_timers.size() == 0);
378 sset.process_queues();
379 assert(p.get_state() == service_state_t::STOPPING);
381 base_process_service_test::handle_exit(&p, 0);
382 sset.process_queues();
383 assert(p.get_state() == service_state_t::STOPPED);
384 assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
385 assert(event_loop.active_timers.size() == 0);
387 sset.remove_service(&p);
390 // Time-out during start
391 void test_proc_start_timeout()
397 string command = "test-command";
398 list<pair<unsigned,unsigned>> command_offsets;
399 command_offsets.emplace_back(0, command.length());
400 std::list<prelim_dep> depends;
402 scripted_service p {&sset, "testproc", std::move(command), command_offsets, depends};
403 init_service_defaults(p);
404 p.set_start_timeout(time_val(10,0));
405 sset.add_service(&p);
408 sset.process_queues();
410 assert(p.get_state() == service_state_t::STARTING);
412 event_loop.advance_time(time_val(10,0));
413 sset.process_queues();
415 assert(p.get_state() == service_state_t::STOPPING);
417 base_process_service_test::handle_signal_exit(&p, SIGTERM);
418 sset.process_queues();
420 // We set no stop script, so state should now be STOPPED with no timer set
421 assert(p.get_state() == service_state_t::STOPPED);
422 assert(p.get_stop_reason() == stopped_reason_t::TIMEDOUT);
423 assert(event_loop.active_timers.size() == 0);
425 sset.remove_service(&p);
428 // Test that a timeout doesn't stop a "waits for" dependent to fail to start
429 void test_proc_start_timeout2()
435 string command = "test-command";
436 list<pair<unsigned,unsigned>> command_offsets;
437 command_offsets.emplace_back(0, command.length());
438 std::list<prelim_dep> depends;
440 scripted_service p {&sset, "testproc", std::move(command), command_offsets, depends};
441 p.set_start_timeout(time_val {1,0});
442 init_service_defaults(p);
443 sset.add_service(&p);
445 service_record ts {&sset, "test-service-1", service_type_t::INTERNAL,
446 {{&p, dependency_type::WAITS_FOR}} };
449 sset.process_queues();
451 assert(p.get_state() == service_state_t::STARTING);
452 assert(ts.get_state() == service_state_t::STARTING);
454 event_loop.advance_time(time_val {1,0}); // start timer should expire
455 sset.process_queues();
457 assert(p.get_state() == service_state_t::STOPPING);
459 base_process_service_test::handle_exit(&p, 0);
460 sset.process_queues();
462 assert(p.get_state() == service_state_t::STOPPED);
463 assert(p.get_stop_reason() == stopped_reason_t::TIMEDOUT);
464 assert(ts.get_state() == service_state_t::STARTED);
465 assert(event_loop.active_timers.size() == 0);
467 sset.remove_service(&p);
470 // Test exec() failure for process service start.
471 void test_proc_start_execfail()
477 string command = "test-command";
478 list<pair<unsigned,unsigned>> command_offsets;
479 command_offsets.emplace_back(0, command.length());
480 std::list<prelim_dep> depends;
482 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
483 init_service_defaults(p);
484 sset.add_service(&p);
487 sset.process_queues();
489 assert(p.get_state() == service_state_t::STARTING);
491 base_process_service_test::exec_failed(&p, ENOENT);
492 sset.process_queues();
494 assert(p.get_state() == service_state_t::STOPPED);
495 assert(p.get_stop_reason() == stopped_reason_t::EXECFAILED);
496 assert(event_loop.active_timers.size() == 0);
498 sset.remove_service(&p);
501 // Test no ready notification before process terminates
502 void test_proc_notify_fail()
508 string command = "test-command";
509 list<pair<unsigned,unsigned>> command_offsets;
510 command_offsets.emplace_back(0, command.length());
511 std::list<prelim_dep> depends;
513 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
514 init_service_defaults(p);
515 p.set_notification_fd(3);
516 sset.add_service(&p);
519 sset.process_queues();
521 assert(p.get_state() == service_state_t::STARTING);
523 base_process_service_test::exec_succeeded(&p);
524 sset.process_queues();
526 assert(p.get_state() == service_state_t::STARTING);
528 int nfd = base_process_service_test::get_notification_fd(&p);
531 // Signal EOF on notify fd:
532 event_loop.regd_fd_watchers[nfd]->fd_event(event_loop, nfd, dasynq::IN_EVENTS);
534 assert(p.get_state() == service_state_t::STOPPING);
536 base_process_service_test::handle_exit(&p, 0);
537 sset.process_queues();
539 assert(p.get_state() == service_state_t::STOPPED);
540 assert(event_loop.active_timers.size() == 0);
542 sset.remove_service(&p);
546 void test_proc_stop_timeout()
552 string command = "test-command";
553 list<pair<unsigned,unsigned>> command_offsets;
554 command_offsets.emplace_back(0, command.length());
555 std::list<prelim_dep> depends;
557 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
558 init_service_defaults(p);
559 p.set_stop_timeout(time_val {10, 0});
560 sset.add_service(&p);
563 sset.process_queues();
565 assert(p.get_state() == service_state_t::STARTING);
567 base_process_service_test::exec_succeeded(&p);
568 sset.process_queues();
570 assert(p.get_state() == service_state_t::STARTED);
573 sset.process_queues();
575 assert(p.get_state() == service_state_t::STOPPING);
576 assert(bp_sys::last_sig_sent == SIGTERM);
578 event_loop.advance_time(time_val {10, 0}); // expire stop timer
579 sset.process_queues();
581 // kill signal (SIGKILL) should have been sent; process not dead until it's dead, however
582 assert(p.get_state() == service_state_t::STOPPING);
583 assert(bp_sys::last_sig_sent == SIGKILL);
585 base_process_service_test::handle_exit(&p, 0);
586 sset.process_queues();
588 assert(p.get_state() == service_state_t::STOPPED);
589 assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
591 assert(event_loop.active_timers.size() == 0);
593 sset.remove_service(&p);
597 void test_proc_smooth_recovery1()
603 string command = "test-command";
604 list<pair<unsigned,unsigned>> command_offsets;
605 command_offsets.emplace_back(0, command.length());
606 std::list<prelim_dep> depends;
608 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
609 init_service_defaults(p);
610 p.set_smooth_recovery(true);
611 p.set_restart_delay(time_val {0, 1000});
612 sset.add_service(&p);
615 sset.process_queues();
617 base_process_service_test::exec_succeeded(&p);
618 sset.process_queues();
620 pid_t first_instance = bp_sys::last_forked_pid;
622 assert(p.get_state() == service_state_t::STARTED);
624 base_process_service_test::handle_exit(&p, 0);
625 sset.process_queues();
627 // since time hasn't been changed, we expect that the process has not yet been re-launched:
628 assert(first_instance == bp_sys::last_forked_pid);
629 assert(p.get_state() == service_state_t::STARTED);
631 event_loop.advance_time(time_val {0, 1000});
632 sset.process_queues();
634 // Now a new process should've been launched:
635 assert(first_instance + 1 == bp_sys::last_forked_pid);
636 assert(p.get_state() == service_state_t::STARTED);
638 assert(event_loop.active_timers.size() == 0);
640 sset.remove_service(&p);
643 // Smooth recovery without restart delay
644 void test_proc_smooth_recovery2()
650 string command = "test-command";
651 list<pair<unsigned,unsigned>> command_offsets;
652 command_offsets.emplace_back(0, command.length());
653 std::list<prelim_dep> depends;
655 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
656 init_service_defaults(p);
657 p.set_smooth_recovery(true);
658 p.set_restart_delay(time_val(0, 0));
659 sset.add_service(&p);
662 sset.process_queues();
664 base_process_service_test::exec_succeeded(&p);
665 sset.process_queues();
667 pid_t first_instance = bp_sys::last_forked_pid;
669 assert(p.get_state() == service_state_t::STARTED);
670 assert(event_loop.active_timers.size() == 0);
672 base_process_service_test::handle_exit(&p, 0);
673 sset.process_queues();
675 // no restart delay, process should restart immediately:
676 assert(first_instance + 1 == bp_sys::last_forked_pid);
677 assert(p.get_state() == service_state_t::STARTED);
678 assert(event_loop.active_timers.size() == 0);
680 sset.remove_service(&p);
684 void test_scripted_stop_timeout()
690 string command = "test-command";
691 string stopcommand = "stop-command";
692 list<pair<unsigned,unsigned>> command_offsets;
693 command_offsets.emplace_back(0, command.length());
694 std::list<prelim_dep> depends;
696 scripted_service p {&sset, "testscripted", std::move(command), command_offsets, depends};
697 init_service_defaults(p);
698 p.set_stop_command(stopcommand, command_offsets);
699 p.set_stop_timeout(time_val {10, 0});
700 sset.add_service(&p);
703 sset.process_queues();
705 assert(p.get_state() == service_state_t::STARTING);
707 base_process_service_test::exec_succeeded(&p);
708 sset.process_queues();
709 base_process_service_test::handle_exit(&p, 0);
710 sset.process_queues();
712 assert(p.get_state() == service_state_t::STARTED);
715 sset.process_queues();
717 assert(p.get_state() == service_state_t::STOPPING);
719 base_process_service_test::exec_succeeded(&p);
720 sset.process_queues();
722 // should still be stopping:
723 assert(p.get_state() == service_state_t::STOPPING);
725 event_loop.advance_time(time_val {10, 0}); // expire stop timer
726 sset.process_queues();
728 // kill signal (SIGKILL) should have been sent; process not dead until it's dead, however
729 assert(p.get_state() == service_state_t::STOPPING);
730 assert(bp_sys::last_sig_sent == SIGKILL);
732 base_process_service_test::handle_exit(&p, SIGKILL);
733 sset.process_queues();
735 assert(p.get_state() == service_state_t::STOPPED);
736 assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
738 assert(event_loop.active_timers.size() == 0);
740 sset.remove_service(&p);
743 void test_scripted_start_fail()
749 string command = "test-command";
750 string stopcommand = "stop-command";
751 list<pair<unsigned,unsigned>> command_offsets;
752 command_offsets.emplace_back(0, command.length());
753 std::list<prelim_dep> depends;
755 scripted_service p {&sset, "testscripted", std::move(command), command_offsets, depends};
756 init_service_defaults(p);
757 p.set_stop_command(stopcommand, command_offsets);
758 sset.add_service(&p);
760 service_record *s2 = new service_record(&sset, "test-service-2", service_type_t::INTERNAL, {{&p, REG}});
761 service_record *s3 = new service_record(&sset, "test-service-3",
762 service_type_t::INTERNAL, {{&p, REG}, {s2, REG}});
763 sset.add_service(s2);
764 sset.add_service(s3);
767 sset.process_queues();
769 assert(p.get_state() == service_state_t::STARTING);
771 base_process_service_test::exec_succeeded(&p);
772 sset.process_queues();
773 base_process_service_test::handle_exit(&p, 0x1); // exit fail
774 sset.process_queues();
777 assert(p.get_state() == service_state_t::STOPPED);
778 assert(s2->get_state() == service_state_t::STOPPED);
779 assert(s3->get_state() == service_state_t::STOPPED);
780 assert(p.get_stop_reason() == stopped_reason_t::FAILED);
781 assert(s2->get_stop_reason() == stopped_reason_t::DEPFAILED);
782 assert(s3->get_stop_reason() == stopped_reason_t::DEPFAILED);
784 event_loop.active_timers.clear();
785 sset.remove_service(&p);
787 assert(sset.count_active_services() == 0);
790 void test_scripted_stop_fail()
796 string command = "test-command";
797 string stopcommand = "stop-command";
798 list<pair<unsigned,unsigned>> command_offsets;
799 command_offsets.emplace_back(0, command.length());
800 std::list<prelim_dep> depends;
802 scripted_service p {&sset, "testscripted", std::move(command), command_offsets, depends};
803 init_service_defaults(p);
804 p.set_stop_command(stopcommand, command_offsets);
805 sset.add_service(&p);
807 service_record *s2 = new service_record(&sset, "test-service-2", service_type_t::INTERNAL, {});
808 service_record *s3 = new service_record(&sset, "test-service-3", service_type_t::INTERNAL,
809 {{s2, REG}, {&p, REG}});
810 service_record *s4 = new service_record(&sset, "test-service-4", service_type_t::INTERNAL,
811 {{&p, REG}, {s3, REG}});
812 sset.add_service(s2);
813 sset.add_service(s3);
814 sset.add_service(s4);
817 sset.process_queues();
819 base_process_service_test::exec_succeeded(&p);
820 sset.process_queues();
821 base_process_service_test::handle_exit(&p, 0x0); // success
822 sset.process_queues();
824 assert(p.get_state() == service_state_t::STARTED);
825 assert(s2->get_state() == service_state_t::STARTED);
826 assert(s3->get_state() == service_state_t::STARTED);
827 assert(s4->get_state() == service_state_t::STARTED);
829 pid_t last_forked = bp_sys::last_forked_pid;
832 sset.process_queues();
834 base_process_service_test::exec_succeeded(&p);
835 sset.process_queues();
836 base_process_service_test::handle_exit(&p, 0x1); // failure
837 sset.process_queues();
839 // The stop command should be executed once:
840 assert((bp_sys::last_forked_pid - last_forked) == 1);
842 assert(p.get_state() == service_state_t::STOPPED);
843 assert(s2->get_state() == service_state_t::STOPPED);
844 assert(s3->get_state() == service_state_t::STOPPED);
845 assert(s4->get_state() == service_state_t::STOPPED);
847 event_loop.active_timers.clear();
848 sset.remove_service(&p);
851 void test_scripted_start_skip()
857 string command = "test-command";
858 list<pair<unsigned,unsigned>> command_offsets;
859 command_offsets.emplace_back(0, command.length());
860 std::list<prelim_dep> depends;
862 scripted_service p {&sset, "testscripted", std::move(command), command_offsets, depends};
863 init_service_defaults(p);
864 service_flags_t sflags;
865 sflags.skippable = true;
867 sset.add_service(&p);
869 service_record *s2 = new service_record(&sset, "test-service-2", service_type_t::INTERNAL, {{&p, REG}});
870 sset.add_service(s2);
873 sset.process_queues();
874 assert(p.get_state() == service_state_t::STARTING);
876 base_process_service_test::exec_succeeded(&p);
877 sset.process_queues();
878 assert(p.get_state() == service_state_t::STARTING);
880 base_process_service_test::handle_signal_exit(&p, SIGINT); // interrupted
881 sset.process_queues();
883 assert(p.get_state() == service_state_t::STARTED);
884 assert(s2->get_state() == service_state_t::STARTED);
885 assert(p.was_start_skipped());
886 assert(! s2->was_start_skipped());
887 assert(sset.count_active_services() == 2);
890 sset.process_queues();
892 assert(p.get_state() == service_state_t::STOPPED);
893 assert(s2->get_state() == service_state_t::STOPPED);
894 assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
895 assert(s2->get_stop_reason() == stopped_reason_t::NORMAL);
896 assert(sset.count_active_services() == 0);
898 event_loop.active_timers.clear();
899 sset.remove_service(&p);
902 // Test interrupting start of a service marked skippable
903 void test_scripted_start_skip2()
909 string command = "test-command";
910 list<pair<unsigned,unsigned>> command_offsets;
911 command_offsets.emplace_back(0, command.length());
912 std::list<prelim_dep> depends;
914 scripted_service p {&sset, "testscripted", std::move(command), command_offsets, depends};
915 init_service_defaults(p);
916 service_flags_t sflags;
917 sflags.skippable = true;
918 sflags.start_interruptible = true;
920 sset.add_service(&p);
922 service_record *s2 = new service_record(&sset, "test-service-2", service_type_t::INTERNAL, {{&p, REG}});
923 sset.add_service(s2);
926 sset.process_queues();
927 assert(p.get_state() == service_state_t::STARTING);
929 base_process_service_test::exec_succeeded(&p);
930 sset.process_queues();
931 assert(p.get_state() == service_state_t::STARTING);
933 s2->stop(true); // abort startup; p should be cancelled
934 sset.process_queues();
936 assert(p.get_state() == service_state_t::STOPPING);
938 base_process_service_test::handle_signal_exit(&p, SIGINT); // interrupted
939 sset.process_queues();
941 assert(p.get_state() == service_state_t::STOPPED);
942 assert(s2->get_state() == service_state_t::STOPPED);
943 assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
944 assert(s2->get_stop_reason() == stopped_reason_t::NORMAL);
945 assert(sset.count_active_services() == 0);
947 event_loop.active_timers.clear();
948 sset.remove_service(&p);
951 // Test that starting a service with a waits-for dependency on another - currently stopping - service,
952 // causes that service to re-start.
953 void test_waitsfor_restart()
959 string command = "test-command";
960 list<pair<unsigned,unsigned>> command_offsets;
961 command_offsets.emplace_back(0, command.length());
962 std::list<prelim_dep> depends;
964 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
965 init_service_defaults(p);
966 sset.add_service(&p);
968 service_record tp {&sset, "test-service", service_type_t::INTERNAL, {{&p, WAITS}}};
969 sset.add_service(&tp);
974 sset.process_queues();
976 assert(p.get_state() == service_state_t::STARTING);
978 base_process_service_test::exec_succeeded(&p);
979 sset.process_queues();
981 assert(p.get_state() == service_state_t::STARTED);
982 assert(event_loop.active_timers.size() == 0);
987 sset.process_queues();
989 assert(p.get_state() == service_state_t::STOPPING);
991 // start tp (which waits-for p):
994 sset.process_queues();
996 assert(tp.get_state() == service_state_t::STARTING);
997 assert(p.get_state() == service_state_t::STOPPING);
999 // p terminates (finishes stopping). Then it should re-start...
1000 base_process_service_test::handle_signal_exit(&p, SIGTERM);
1001 sset.process_queues();
1003 assert(tp.get_state() == service_state_t::STARTING);
1004 assert(p.get_state() == service_state_t::STARTING);
1006 base_process_service_test::exec_succeeded(&p);
1007 sset.process_queues();
1009 assert(tp.get_state() == service_state_t::STARTED);
1010 assert(p.get_state() == service_state_t::STARTED);
1012 sset.remove_service(&tp);
1013 sset.remove_service(&p);
1017 #define RUN_TEST(name, spacing) \
1018 std::cout << #name "..." spacing << std::flush; \
1020 std::cout << "PASSED" << std::endl;
1022 int main(int argc, char **argv)
1024 RUN_TEST(test_proc_service_start, " ");
1025 RUN_TEST(test_proc_notify_start, " ");
1026 RUN_TEST(test_proc_unexpected_term, " ");
1027 RUN_TEST(test_proc_term_restart, " ");
1028 RUN_TEST(test_proc_term_restart2, " ");
1029 RUN_TEST(test_term_via_stop, " ");
1030 RUN_TEST(test_term_via_stop2, " ");
1031 RUN_TEST(test_proc_start_timeout, " ");
1032 RUN_TEST(test_proc_start_timeout2, " ");
1033 RUN_TEST(test_proc_start_execfail, " ");
1034 RUN_TEST(test_proc_notify_fail, " ");
1035 RUN_TEST(test_proc_stop_timeout, " ");
1036 RUN_TEST(test_proc_smooth_recovery1, "");
1037 RUN_TEST(test_proc_smooth_recovery2, "");
1038 RUN_TEST(test_scripted_stop_timeout, "");
1039 RUN_TEST(test_scripted_start_fail, " ");
1040 RUN_TEST(test_scripted_stop_fail, " ");
1041 RUN_TEST(test_scripted_start_skip, " ");
1042 RUN_TEST(test_scripted_start_skip2, " ");
1043 RUN_TEST(test_waitsfor_restart, " ");