9 #include "proc-service.h"
11 // Tests of process-service related functionality.
13 // These tests work mostly by completely mocking out the base_process_service class. The mock
14 // implementations can be found in test-baseproc.cc.
16 extern eventloop_t event_loop;
18 constexpr static auto REG = dependency_type::REGULAR;
19 constexpr static auto WAITS = dependency_type::WAITS_FOR;
21 // Friend interface to access base_process_service private/protected members.
22 class base_process_service_test
25 static void exec_succeeded(base_process_service *bsp)
27 bsp->waiting_for_execstat = false;
28 bsp->exec_succeeded();
31 static void exec_failed(base_process_service *bsp, int errcode)
34 err.stage = exec_stage::DO_EXEC;
35 err.st_errno = errcode;
36 bsp->waiting_for_execstat = false;
37 bsp->exec_failed(err);
40 static void handle_exit(base_process_service *bsp, int exit_status)
43 bsp->handle_exit_status(bp_sys::exit_status(true, false, exit_status));
46 static void handle_signal_exit(base_process_service *bsp, int signo)
49 bsp->handle_exit_status(bp_sys::exit_status(false, true, signo));
52 static int get_notification_fd(base_process_service *bsp)
54 return bsp->notification_fd;
60 extern int last_sig_sent;
61 extern pid_t last_forked_pid;
64 static void init_service_defaults(base_process_service &ps)
66 ps.set_restart_interval(time_val(10,0), 3);
67 ps.set_restart_delay(time_val(0, 200000000)); // 200 milliseconds
68 ps.set_stop_timeout(time_val(10,0));
71 // Regular service start
72 void test_proc_service_start()
78 string command = "test-command";
79 list<pair<unsigned,unsigned>> command_offsets;
80 command_offsets.emplace_back(0, command.length());
81 std::list<prelim_dep> depends;
83 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
84 init_service_defaults(p);
88 sset.process_queues();
90 assert(p.get_state() == service_state_t::STARTING);
92 base_process_service_test::exec_succeeded(&p);
93 sset.process_queues();
95 assert(p.get_state() == service_state_t::STARTED);
96 assert(event_loop.active_timers.size() == 0);
98 sset.remove_service(&p);
101 // Test start with readiness notification
102 void test_proc_notify_start()
108 string command = "test-command";
109 list<pair<unsigned,unsigned>> command_offsets;
110 command_offsets.emplace_back(0, command.length());
111 std::list<prelim_dep> depends;
113 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
114 init_service_defaults(p);
115 p.set_notification_fd(3);
116 sset.add_service(&p);
119 sset.process_queues();
121 assert(p.get_state() == service_state_t::STARTING);
123 base_process_service_test::exec_succeeded(&p);
124 sset.process_queues();
126 assert(p.get_state() == service_state_t::STARTING);
128 int nfd = base_process_service_test::get_notification_fd(&p);
131 char notifystr[] = "ok started\n";
132 std::vector<char> rnotifystr;
133 rnotifystr.insert(rnotifystr.end(), notifystr, notifystr + sizeof(notifystr));
134 bp_sys::supply_read_data(nfd, std::move(rnotifystr));
136 event_loop.regd_fd_watchers[nfd]->fd_event(event_loop, nfd, dasynq::IN_EVENTS);
138 assert(p.get_state() == service_state_t::STARTED);
139 assert(event_loop.active_timers.size() == 0);
141 sset.remove_service(&p);
144 // Unexpected termination
145 void test_proc_unexpected_term()
151 string command = "test-command";
152 list<pair<unsigned,unsigned>> command_offsets;
153 command_offsets.emplace_back(0, command.length());
154 std::list<prelim_dep> depends;
156 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
157 init_service_defaults(p);
158 sset.add_service(&p);
161 sset.process_queues();
163 base_process_service_test::exec_succeeded(&p);
164 sset.process_queues();
166 assert(p.get_state() == service_state_t::STARTED);
168 base_process_service_test::handle_exit(&p, 0);
170 assert(p.get_state() == service_state_t::STOPPED);
171 assert(p.get_stop_reason() == stopped_reason_t::TERMINATED);
172 assert(event_loop.active_timers.size() == 0);
174 sset.remove_service(&p);
177 // Unexpected termination with restart
178 void test_proc_term_restart()
184 string command = "test-command";
185 list<pair<unsigned,unsigned>> command_offsets;
186 command_offsets.emplace_back(0, command.length());
187 std::list<prelim_dep> depends;
189 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
190 init_service_defaults(p);
191 p.set_auto_restart(true);
192 sset.add_service(&p);
195 sset.process_queues();
197 base_process_service_test::exec_succeeded(&p);
198 sset.process_queues();
200 assert(p.get_state() == service_state_t::STARTED);
201 assert(event_loop.active_timers.size() == 0);
203 base_process_service_test::handle_exit(&p, 0);
204 sset.process_queues();
206 // Starting, restart timer should be armed:
207 assert(p.get_state() == service_state_t::STARTING);
208 assert(event_loop.active_timers.size() == 1);
210 event_loop.advance_time(time_val(0, 200000000));
211 assert(event_loop.active_timers.size() == 0);
213 sset.process_queues();
214 base_process_service_test::exec_succeeded(&p);
215 sset.process_queues();
217 assert(p.get_state() == service_state_t::STARTED);
218 assert(event_loop.active_timers.size() == 0);
220 sset.remove_service(&p);
223 void test_proc_term_restart2()
229 string command = "test-command";
230 list<pair<unsigned,unsigned>> command_offsets;
231 command_offsets.emplace_back(0, command.length());
232 std::list<prelim_dep> depends;
234 service_record b {&sset, "boot"};
235 sset.add_service(&b);
237 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
238 init_service_defaults(p);
239 p.set_auto_restart(true);
240 sset.add_service(&p);
242 b.add_dep(&p, WAITS);
245 sset.process_queues();
247 assert(p.get_state() == service_state_t::STARTING);
249 base_process_service_test::exec_succeeded(&p);
250 sset.process_queues();
252 assert(p.get_state() == service_state_t::STARTED);
253 assert(event_loop.active_timers.size() == 0);
255 // simulate process terminating, should then be restarted:
256 base_process_service_test::handle_exit(&p, 0);
257 sset.process_queues();
259 // Starting, restart timer should be armed:
260 assert(p.get_state() == service_state_t::STARTING);
261 assert(event_loop.active_timers.size() == 1);
263 event_loop.advance_time(time_val(0, 200000000));
264 assert(event_loop.active_timers.size() == 0);
266 sset.process_queues();
267 base_process_service_test::exec_succeeded(&p);
268 sset.process_queues();
270 assert(p.get_state() == service_state_t::STARTED);
271 assert(event_loop.active_timers.size() == 0);
273 assert(sset.count_active_services() == 2);
275 // Request stop, this time it should not restart:
277 sset.process_queues();
278 base_process_service_test::handle_exit(&p, 0);
279 sset.process_queues();
281 assert(p.get_state() == service_state_t::STOPPED);
282 assert(event_loop.active_timers.size() == 0);
283 assert(sset.count_active_services() == 1);
285 // simulate terminate dinit
286 sset.stop_all_services();
288 //base_process_service_test::handle_exit(&p, 0);
289 sset.process_queues();
291 assert(p.get_state() == service_state_t::STOPPED);
292 assert(event_loop.active_timers.size() == 0);
293 assert(sset.count_active_services() == 0);
295 sset.remove_service(&p);
296 sset.remove_service(&b);
299 // Termination via stop request
300 void test_term_via_stop()
306 string command = "test-command";
307 list<pair<unsigned,unsigned>> command_offsets;
308 command_offsets.emplace_back(0, command.length());
309 std::list<prelim_dep> depends;
311 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
312 init_service_defaults(p);
313 sset.add_service(&p);
316 sset.process_queues();
318 base_process_service_test::exec_succeeded(&p);
319 sset.process_queues();
321 assert(p.get_state() == service_state_t::STARTED);
322 assert(event_loop.active_timers.size() == 0);
325 sset.process_queues();
327 assert(p.get_state() == service_state_t::STOPPING);
328 assert(event_loop.active_timers.size() == 1);
330 base_process_service_test::handle_exit(&p, 0);
331 sset.process_queues();
333 assert(p.get_state() == service_state_t::STOPPED);
334 assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
335 assert(event_loop.active_timers.size() == 0);
337 sset.remove_service(&p);
340 // Termination via stop request, ensure reason is reset:
341 void test_term_via_stop2()
347 string command = "test-command";
348 list<pair<unsigned,unsigned>> command_offsets;
349 command_offsets.emplace_back(0, command.length());
350 std::list<prelim_dep> depends;
352 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
353 init_service_defaults(p);
354 sset.add_service(&p);
357 sset.process_queues();
359 // first set it up with failure reason:
361 base_process_service_test::exec_failed(&p, ENOENT);
362 sset.process_queues();
364 assert(p.get_state() == service_state_t::STOPPED);
365 assert(p.get_stop_reason() == stopped_reason_t::EXECFAILED);
367 // now restart clean:
370 sset.process_queues();
372 base_process_service_test::exec_succeeded(&p);
373 sset.process_queues();
375 assert(p.get_state() == service_state_t::STARTED);
376 assert(event_loop.active_timers.size() == 0);
379 sset.process_queues();
380 assert(p.get_state() == service_state_t::STOPPING);
382 base_process_service_test::handle_exit(&p, 0);
383 sset.process_queues();
384 assert(p.get_state() == service_state_t::STOPPED);
385 assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
386 assert(event_loop.active_timers.size() == 0);
388 sset.remove_service(&p);
391 // Time-out during start
392 void test_proc_start_timeout()
398 string command = "test-command";
399 list<pair<unsigned,unsigned>> command_offsets;
400 command_offsets.emplace_back(0, command.length());
401 std::list<prelim_dep> depends;
403 scripted_service p {&sset, "testproc", std::move(command), command_offsets, depends};
404 init_service_defaults(p);
405 p.set_start_timeout(time_val(10,0));
406 sset.add_service(&p);
409 sset.process_queues();
411 assert(p.get_state() == service_state_t::STARTING);
413 event_loop.advance_time(time_val(10,0));
414 sset.process_queues();
416 assert(p.get_state() == service_state_t::STOPPING);
418 base_process_service_test::handle_signal_exit(&p, SIGTERM);
419 sset.process_queues();
421 // We set no stop script, so state should now be STOPPED with no timer set
422 assert(p.get_state() == service_state_t::STOPPED);
423 assert(p.get_stop_reason() == stopped_reason_t::TIMEDOUT);
424 assert(event_loop.active_timers.size() == 0);
426 sset.remove_service(&p);
429 // Test that a timeout doesn't stop a "waits for" dependent to fail to start
430 void test_proc_start_timeout2()
436 string command = "test-command";
437 list<pair<unsigned,unsigned>> command_offsets;
438 command_offsets.emplace_back(0, command.length());
439 std::list<prelim_dep> depends;
441 scripted_service p {&sset, "testproc", std::move(command), command_offsets, depends};
442 p.set_start_timeout(time_val {1,0});
443 init_service_defaults(p);
444 sset.add_service(&p);
446 service_record ts {&sset, "test-service-1", service_type_t::INTERNAL,
447 {{&p, dependency_type::WAITS_FOR}} };
450 sset.process_queues();
452 assert(p.get_state() == service_state_t::STARTING);
453 assert(ts.get_state() == service_state_t::STARTING);
455 event_loop.advance_time(time_val {1,0}); // start timer should expire
456 sset.process_queues();
458 assert(p.get_state() == service_state_t::STOPPING);
460 base_process_service_test::handle_exit(&p, 0);
461 sset.process_queues();
463 assert(p.get_state() == service_state_t::STOPPED);
464 assert(p.get_stop_reason() == stopped_reason_t::TIMEDOUT);
465 assert(ts.get_state() == service_state_t::STARTED);
466 assert(event_loop.active_timers.size() == 0);
468 sset.remove_service(&p);
471 // Test exec() failure for process service start.
472 void test_proc_start_execfail()
478 string command = "test-command";
479 list<pair<unsigned,unsigned>> command_offsets;
480 command_offsets.emplace_back(0, command.length());
481 std::list<prelim_dep> depends;
483 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
484 init_service_defaults(p);
485 sset.add_service(&p);
488 sset.process_queues();
490 assert(p.get_state() == service_state_t::STARTING);
492 base_process_service_test::exec_failed(&p, ENOENT);
493 sset.process_queues();
495 assert(p.get_state() == service_state_t::STOPPED);
496 assert(p.get_stop_reason() == stopped_reason_t::EXECFAILED);
497 assert(event_loop.active_timers.size() == 0);
499 sset.remove_service(&p);
502 // Test no ready notification before process terminates
503 void test_proc_notify_fail()
509 string command = "test-command";
510 list<pair<unsigned,unsigned>> command_offsets;
511 command_offsets.emplace_back(0, command.length());
512 std::list<prelim_dep> depends;
514 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
515 init_service_defaults(p);
516 p.set_notification_fd(3);
517 sset.add_service(&p);
520 sset.process_queues();
522 assert(p.get_state() == service_state_t::STARTING);
524 base_process_service_test::exec_succeeded(&p);
525 sset.process_queues();
527 assert(p.get_state() == service_state_t::STARTING);
529 int nfd = base_process_service_test::get_notification_fd(&p);
532 // Signal EOF on notify fd:
533 event_loop.regd_fd_watchers[nfd]->fd_event(event_loop, nfd, dasynq::IN_EVENTS);
535 assert(p.get_state() == service_state_t::STOPPING);
537 base_process_service_test::handle_exit(&p, 0);
538 sset.process_queues();
540 assert(p.get_state() == service_state_t::STOPPED);
541 assert(event_loop.active_timers.size() == 0);
543 sset.remove_service(&p);
547 void test_proc_stop_timeout()
553 string command = "test-command";
554 list<pair<unsigned,unsigned>> command_offsets;
555 command_offsets.emplace_back(0, command.length());
556 std::list<prelim_dep> depends;
558 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
559 init_service_defaults(p);
560 p.set_stop_timeout(time_val {10, 0});
561 sset.add_service(&p);
564 sset.process_queues();
566 assert(p.get_state() == service_state_t::STARTING);
568 base_process_service_test::exec_succeeded(&p);
569 sset.process_queues();
571 assert(p.get_state() == service_state_t::STARTED);
574 sset.process_queues();
576 assert(p.get_state() == service_state_t::STOPPING);
577 assert(bp_sys::last_sig_sent == SIGTERM);
579 event_loop.advance_time(time_val {10, 0}); // expire stop timer
580 sset.process_queues();
582 // kill signal (SIGKILL) should have been sent; process not dead until it's dead, however
583 assert(p.get_state() == service_state_t::STOPPING);
584 assert(bp_sys::last_sig_sent == SIGKILL);
586 base_process_service_test::handle_exit(&p, 0);
587 sset.process_queues();
589 assert(p.get_state() == service_state_t::STOPPED);
590 assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
592 assert(event_loop.active_timers.size() == 0);
594 sset.remove_service(&p);
598 void test_proc_smooth_recovery1()
604 string command = "test-command";
605 list<pair<unsigned,unsigned>> command_offsets;
606 command_offsets.emplace_back(0, command.length());
607 std::list<prelim_dep> depends;
609 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
610 init_service_defaults(p);
611 p.set_smooth_recovery(true);
612 p.set_restart_delay(time_val {0, 1000});
613 sset.add_service(&p);
616 sset.process_queues();
618 base_process_service_test::exec_succeeded(&p);
619 sset.process_queues();
621 pid_t first_instance = bp_sys::last_forked_pid;
623 assert(p.get_state() == service_state_t::STARTED);
625 base_process_service_test::handle_exit(&p, 0);
626 sset.process_queues();
628 // since time hasn't been changed, we expect that the process has not yet been re-launched:
629 assert(first_instance == bp_sys::last_forked_pid);
630 assert(p.get_state() == service_state_t::STARTED);
632 event_loop.advance_time(time_val {0, 1000});
633 sset.process_queues();
635 // Now a new process should've been launched:
636 assert(first_instance + 1 == bp_sys::last_forked_pid);
637 assert(p.get_state() == service_state_t::STARTED);
639 assert(event_loop.active_timers.size() == 0);
641 sset.remove_service(&p);
644 // Smooth recovery without restart delay
645 void test_proc_smooth_recovery2()
651 string command = "test-command";
652 list<pair<unsigned,unsigned>> command_offsets;
653 command_offsets.emplace_back(0, command.length());
654 std::list<prelim_dep> depends;
656 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
657 init_service_defaults(p);
658 p.set_smooth_recovery(true);
659 p.set_restart_delay(time_val(0, 0));
660 sset.add_service(&p);
663 sset.process_queues();
665 base_process_service_test::exec_succeeded(&p);
666 sset.process_queues();
668 pid_t first_instance = bp_sys::last_forked_pid;
670 assert(p.get_state() == service_state_t::STARTED);
671 assert(event_loop.active_timers.size() == 0);
673 base_process_service_test::handle_exit(&p, 0);
674 sset.process_queues();
676 // no restart delay, process should restart immediately:
677 assert(first_instance + 1 == bp_sys::last_forked_pid);
678 assert(p.get_state() == service_state_t::STARTED);
679 assert(event_loop.active_timers.size() == 0);
681 sset.remove_service(&p);
684 void test_bgproc_smooth_recover()
690 string command = "test-command";
691 list<pair<unsigned,unsigned>> command_offsets;
692 command_offsets.emplace_back(0, command.length());
693 std::list<prelim_dep> depends;
695 bgproc_service p {&sset, "testproc", std::move(command), command_offsets, depends};
696 init_service_defaults(p);
697 p.set_smooth_recovery(true);
698 p.set_restart_delay(time_val {0, 1000});
699 p.set_pid_file("/run/daemon.pid");
700 sset.add_service(&p);
703 sset.process_queues();
705 base_process_service_test::exec_succeeded(&p);
706 sset.process_queues();
708 // pid_t first_instance = bp_sys::last_forked_pid;
709 pid_t daemon_instance = ++bp_sys::last_forked_pid;
711 // Set up the pid file content with the pid of the daemon
713 str << daemon_instance << std::flush;
714 string pid_file_content = str.str();
715 vector<char> pid_file_content_v(pid_file_content.begin(), pid_file_content.end());
716 bp_sys::supply_file_content("/run/daemon.pid", std::move(pid_file_content_v));
718 assert(p.get_state() == service_state_t::STARTING);
720 base_process_service_test::handle_exit(&p, 0); // exit the launch process
721 sset.process_queues();
723 // daemon process has been started now, state should be STARTED
724 assert(p.get_state() == service_state_t::STARTED);
725 assert(daemon_instance == bp_sys::last_forked_pid);
727 base_process_service_test::handle_exit(&p, 0); // exit the daemon process
729 // since time hasn't been changed, we expect that the process has not yet been re-launched:
730 assert(p.get_state() == service_state_t::STARTED);
731 assert(daemon_instance == bp_sys::last_forked_pid);
733 event_loop.advance_time(time_val {0, 1000});
734 sset.process_queues();
736 // Now a new process should've been launched:
737 assert(event_loop.active_timers.size() == 0);
738 assert(daemon_instance + 1 == bp_sys::last_forked_pid);
739 assert(p.get_state() == service_state_t::STARTED);
740 assert(event_loop.active_timers.size() == 0);
742 base_process_service_test::exec_succeeded(&p);
743 sset.process_queues();
745 assert(event_loop.active_timers.size() == 0);
747 daemon_instance = ++bp_sys::last_forked_pid;
749 str << daemon_instance << std::flush;
750 pid_file_content = str.str();
751 pid_file_content_v = std::vector<char>(pid_file_content.begin(), pid_file_content.end());
752 bp_sys::supply_file_content("/run/daemon.pid", std::move(pid_file_content_v));
754 base_process_service_test::handle_exit(&p, 0);
755 sset.process_queues();
757 assert(p.get_state() == service_state_t::STARTED);
759 assert(event_loop.active_timers.size() == 0);
761 // Now run through it again
763 base_process_service_test::handle_exit(&p, 0); // exit the daemon process
765 // since time hasn't been changed, we expect that the process has not yet been re-launched:
766 assert(p.get_state() == service_state_t::STARTED);
767 assert(daemon_instance == bp_sys::last_forked_pid);
769 event_loop.advance_time(time_val {0, 1000});
770 sset.process_queues();
772 // Now a new process should've been launched:
773 assert(event_loop.active_timers.size() == 0);
774 assert(daemon_instance + 1 == bp_sys::last_forked_pid);
775 assert(p.get_state() == service_state_t::STARTED);
776 assert(event_loop.active_timers.size() == 0);
778 base_process_service_test::exec_succeeded(&p);
779 sset.process_queues();
781 assert(event_loop.active_timers.size() == 0);
783 daemon_instance = ++bp_sys::last_forked_pid;
785 str << daemon_instance << std::flush;
786 pid_file_content = str.str();
787 pid_file_content_v = std::vector<char>(pid_file_content.begin(), pid_file_content.end());
788 bp_sys::supply_file_content("/run/daemon.pid", std::move(pid_file_content_v));
790 base_process_service_test::handle_exit(&p, 0);
791 sset.process_queues();
793 assert(p.get_state() == service_state_t::STARTED);
795 assert(event_loop.active_timers.size() == 0);
797 sset.remove_service(&p);
801 void test_scripted_stop_timeout()
807 string command = "test-command";
808 string stopcommand = "stop-command";
809 list<pair<unsigned,unsigned>> command_offsets;
810 command_offsets.emplace_back(0, command.length());
811 std::list<prelim_dep> depends;
813 scripted_service p {&sset, "testscripted", std::move(command), command_offsets, depends};
814 init_service_defaults(p);
815 p.set_stop_command(stopcommand, command_offsets);
816 p.set_stop_timeout(time_val {10, 0});
817 sset.add_service(&p);
820 sset.process_queues();
822 assert(p.get_state() == service_state_t::STARTING);
824 base_process_service_test::exec_succeeded(&p);
825 sset.process_queues();
826 base_process_service_test::handle_exit(&p, 0);
827 sset.process_queues();
829 assert(p.get_state() == service_state_t::STARTED);
832 sset.process_queues();
834 assert(p.get_state() == service_state_t::STOPPING);
836 base_process_service_test::exec_succeeded(&p);
837 sset.process_queues();
839 // should still be stopping:
840 assert(p.get_state() == service_state_t::STOPPING);
842 event_loop.advance_time(time_val {10, 0}); // expire stop timer
843 sset.process_queues();
845 // kill signal (SIGKILL) should have been sent; process not dead until it's dead, however
846 assert(p.get_state() == service_state_t::STOPPING);
847 assert(bp_sys::last_sig_sent == SIGKILL);
849 base_process_service_test::handle_exit(&p, SIGKILL);
850 sset.process_queues();
852 assert(p.get_state() == service_state_t::STOPPED);
853 assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
855 assert(event_loop.active_timers.size() == 0);
857 sset.remove_service(&p);
860 void test_scripted_start_fail()
866 string command = "test-command";
867 string stopcommand = "stop-command";
868 list<pair<unsigned,unsigned>> command_offsets;
869 command_offsets.emplace_back(0, command.length());
870 std::list<prelim_dep> depends;
872 scripted_service p {&sset, "testscripted", std::move(command), command_offsets, depends};
873 init_service_defaults(p);
874 p.set_stop_command(stopcommand, command_offsets);
875 sset.add_service(&p);
877 service_record *s2 = new service_record(&sset, "test-service-2", service_type_t::INTERNAL, {{&p, REG}});
878 service_record *s3 = new service_record(&sset, "test-service-3",
879 service_type_t::INTERNAL, {{&p, REG}, {s2, REG}});
880 sset.add_service(s2);
881 sset.add_service(s3);
884 sset.process_queues();
886 assert(p.get_state() == service_state_t::STARTING);
888 base_process_service_test::exec_succeeded(&p);
889 sset.process_queues();
890 base_process_service_test::handle_exit(&p, 0x1); // exit fail
891 sset.process_queues();
894 assert(p.get_state() == service_state_t::STOPPED);
895 assert(s2->get_state() == service_state_t::STOPPED);
896 assert(s3->get_state() == service_state_t::STOPPED);
897 assert(p.get_stop_reason() == stopped_reason_t::FAILED);
898 assert(s2->get_stop_reason() == stopped_reason_t::DEPFAILED);
899 assert(s3->get_stop_reason() == stopped_reason_t::DEPFAILED);
901 event_loop.active_timers.clear();
902 sset.remove_service(&p);
904 assert(sset.count_active_services() == 0);
907 void test_scripted_stop_fail()
913 string command = "test-command";
914 string stopcommand = "stop-command";
915 list<pair<unsigned,unsigned>> command_offsets;
916 command_offsets.emplace_back(0, command.length());
917 std::list<prelim_dep> depends;
919 scripted_service p {&sset, "testscripted", std::move(command), command_offsets, depends};
920 init_service_defaults(p);
921 p.set_stop_command(stopcommand, command_offsets);
922 sset.add_service(&p);
924 service_record *s2 = new service_record(&sset, "test-service-2", service_type_t::INTERNAL, {});
925 service_record *s3 = new service_record(&sset, "test-service-3", service_type_t::INTERNAL,
926 {{s2, REG}, {&p, REG}});
927 service_record *s4 = new service_record(&sset, "test-service-4", service_type_t::INTERNAL,
928 {{&p, REG}, {s3, REG}});
929 sset.add_service(s2);
930 sset.add_service(s3);
931 sset.add_service(s4);
934 sset.process_queues();
936 base_process_service_test::exec_succeeded(&p);
937 sset.process_queues();
938 base_process_service_test::handle_exit(&p, 0x0); // success
939 sset.process_queues();
941 assert(p.get_state() == service_state_t::STARTED);
942 assert(s2->get_state() == service_state_t::STARTED);
943 assert(s3->get_state() == service_state_t::STARTED);
944 assert(s4->get_state() == service_state_t::STARTED);
946 pid_t last_forked = bp_sys::last_forked_pid;
949 sset.process_queues();
951 base_process_service_test::exec_succeeded(&p);
952 sset.process_queues();
953 base_process_service_test::handle_exit(&p, 0x1); // failure
954 sset.process_queues();
956 // The stop command should be executed once:
957 assert((bp_sys::last_forked_pid - last_forked) == 1);
959 assert(p.get_state() == service_state_t::STOPPED);
960 assert(s2->get_state() == service_state_t::STOPPED);
961 assert(s3->get_state() == service_state_t::STOPPED);
962 assert(s4->get_state() == service_state_t::STOPPED);
964 event_loop.active_timers.clear();
965 sset.remove_service(&p);
968 void test_scripted_start_skip()
974 string command = "test-command";
975 list<pair<unsigned,unsigned>> command_offsets;
976 command_offsets.emplace_back(0, command.length());
977 std::list<prelim_dep> depends;
979 scripted_service p {&sset, "testscripted", std::move(command), command_offsets, depends};
980 init_service_defaults(p);
981 service_flags_t sflags;
982 sflags.skippable = true;
984 sset.add_service(&p);
986 service_record *s2 = new service_record(&sset, "test-service-2", service_type_t::INTERNAL, {{&p, REG}});
987 sset.add_service(s2);
990 sset.process_queues();
991 assert(p.get_state() == service_state_t::STARTING);
993 base_process_service_test::exec_succeeded(&p);
994 sset.process_queues();
995 assert(p.get_state() == service_state_t::STARTING);
997 base_process_service_test::handle_signal_exit(&p, SIGINT); // interrupted
998 sset.process_queues();
1000 assert(p.get_state() == service_state_t::STARTED);
1001 assert(s2->get_state() == service_state_t::STARTED);
1002 assert(p.was_start_skipped());
1003 assert(! s2->was_start_skipped());
1004 assert(sset.count_active_services() == 2);
1007 sset.process_queues();
1009 assert(p.get_state() == service_state_t::STOPPED);
1010 assert(s2->get_state() == service_state_t::STOPPED);
1011 assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
1012 assert(s2->get_stop_reason() == stopped_reason_t::NORMAL);
1013 assert(sset.count_active_services() == 0);
1015 event_loop.active_timers.clear();
1016 sset.remove_service(&p);
1019 // Test interrupting start of a service marked skippable
1020 void test_scripted_start_skip2()
1022 using namespace std;
1026 string command = "test-command";
1027 list<pair<unsigned,unsigned>> command_offsets;
1028 command_offsets.emplace_back(0, command.length());
1029 std::list<prelim_dep> depends;
1031 scripted_service p {&sset, "testscripted", std::move(command), command_offsets, depends};
1032 init_service_defaults(p);
1033 service_flags_t sflags;
1034 sflags.skippable = true;
1035 sflags.start_interruptible = true;
1036 p.set_flags(sflags);
1037 sset.add_service(&p);
1039 service_record *s2 = new service_record(&sset, "test-service-2", service_type_t::INTERNAL, {{&p, REG}});
1040 sset.add_service(s2);
1043 sset.process_queues();
1044 assert(p.get_state() == service_state_t::STARTING);
1046 base_process_service_test::exec_succeeded(&p);
1047 sset.process_queues();
1048 assert(p.get_state() == service_state_t::STARTING);
1050 s2->stop(true); // abort startup; p should be cancelled
1051 sset.process_queues();
1053 assert(p.get_state() == service_state_t::STOPPING);
1055 base_process_service_test::handle_signal_exit(&p, SIGINT); // interrupted
1056 sset.process_queues();
1058 assert(p.get_state() == service_state_t::STOPPED);
1059 assert(s2->get_state() == service_state_t::STOPPED);
1060 assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
1061 assert(s2->get_stop_reason() == stopped_reason_t::NORMAL);
1062 assert(sset.count_active_services() == 0);
1064 event_loop.active_timers.clear();
1065 sset.remove_service(&p);
1068 // Test that starting a service with a waits-for dependency on another - currently stopping - service,
1069 // causes that service to re-start.
1070 void test_waitsfor_restart()
1072 using namespace std;
1076 string command = "test-command";
1077 list<pair<unsigned,unsigned>> command_offsets;
1078 command_offsets.emplace_back(0, command.length());
1079 std::list<prelim_dep> depends;
1081 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
1082 init_service_defaults(p);
1083 sset.add_service(&p);
1085 service_record tp {&sset, "test-service", service_type_t::INTERNAL, {{&p, WAITS}}};
1086 sset.add_service(&tp);
1091 sset.process_queues();
1093 assert(p.get_state() == service_state_t::STARTING);
1095 base_process_service_test::exec_succeeded(&p);
1096 sset.process_queues();
1098 assert(p.get_state() == service_state_t::STARTED);
1099 assert(event_loop.active_timers.size() == 0);
1101 // begin stopping p:
1104 sset.process_queues();
1106 assert(p.get_state() == service_state_t::STOPPING);
1108 // start tp (which waits-for p):
1111 sset.process_queues();
1113 assert(tp.get_state() == service_state_t::STARTING);
1114 assert(p.get_state() == service_state_t::STOPPING);
1116 // p terminates (finishes stopping). Then it should re-start...
1117 base_process_service_test::handle_signal_exit(&p, SIGTERM);
1118 sset.process_queues();
1120 assert(tp.get_state() == service_state_t::STARTING);
1121 assert(p.get_state() == service_state_t::STARTING);
1123 base_process_service_test::exec_succeeded(&p);
1124 sset.process_queues();
1126 assert(tp.get_state() == service_state_t::STARTED);
1127 assert(p.get_state() == service_state_t::STARTED);
1129 sset.remove_service(&tp);
1130 sset.remove_service(&p);
1134 #define RUN_TEST(name, spacing) \
1135 std::cout << #name "..." spacing << std::flush; \
1137 std::cout << "PASSED" << std::endl;
1139 int main(int argc, char **argv)
1141 RUN_TEST(test_proc_service_start, " ");
1142 RUN_TEST(test_proc_notify_start, " ");
1143 RUN_TEST(test_proc_unexpected_term, " ");
1144 RUN_TEST(test_proc_term_restart, " ");
1145 RUN_TEST(test_proc_term_restart2, " ");
1146 RUN_TEST(test_term_via_stop, " ");
1147 RUN_TEST(test_term_via_stop2, " ");
1148 RUN_TEST(test_proc_start_timeout, " ");
1149 RUN_TEST(test_proc_start_timeout2, " ");
1150 RUN_TEST(test_proc_start_execfail, " ");
1151 RUN_TEST(test_proc_notify_fail, " ");
1152 RUN_TEST(test_proc_stop_timeout, " ");
1153 RUN_TEST(test_proc_smooth_recovery1, "");
1154 RUN_TEST(test_proc_smooth_recovery2, "");
1155 RUN_TEST(test_bgproc_smooth_recover, "");
1156 RUN_TEST(test_scripted_stop_timeout, "");
1157 RUN_TEST(test_scripted_start_fail, " ");
1158 RUN_TEST(test_scripted_stop_fail, " ");
1159 RUN_TEST(test_scripted_start_skip, " ");
1160 RUN_TEST(test_scripted_start_skip2, " ");
1161 RUN_TEST(test_waitsfor_restart, " ");