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);
168 sset.process_queues();
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 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 sset.remove_service(&p);
273 sset.remove_service(&b);
277 // Termination via stop request
278 void test_term_via_stop()
284 string command = "test-command";
285 list<pair<unsigned,unsigned>> command_offsets;
286 command_offsets.emplace_back(0, command.length());
287 std::list<prelim_dep> depends;
289 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
290 init_service_defaults(p);
291 sset.add_service(&p);
294 sset.process_queues();
296 base_process_service_test::exec_succeeded(&p);
297 sset.process_queues();
299 assert(p.get_state() == service_state_t::STARTED);
300 assert(event_loop.active_timers.size() == 0);
303 sset.process_queues();
305 assert(p.get_state() == service_state_t::STOPPING);
306 assert(event_loop.active_timers.size() == 1);
308 base_process_service_test::handle_exit(&p, 0);
309 sset.process_queues();
311 assert(p.get_state() == service_state_t::STOPPED);
312 assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
313 assert(event_loop.active_timers.size() == 0);
315 sset.remove_service(&p);
318 // Termination via stop request, ensure reason is reset:
319 void test_term_via_stop2()
325 string command = "test-command";
326 list<pair<unsigned,unsigned>> command_offsets;
327 command_offsets.emplace_back(0, command.length());
328 std::list<prelim_dep> depends;
330 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
331 init_service_defaults(p);
332 sset.add_service(&p);
335 sset.process_queues();
337 // first set it up with failure reason:
339 base_process_service_test::exec_failed(&p, ENOENT);
340 sset.process_queues();
342 assert(p.get_state() == service_state_t::STOPPED);
343 assert(p.get_stop_reason() == stopped_reason_t::EXECFAILED);
345 // now restart clean:
348 sset.process_queues();
350 base_process_service_test::exec_succeeded(&p);
351 sset.process_queues();
353 assert(p.get_state() == service_state_t::STARTED);
354 assert(event_loop.active_timers.size() == 0);
357 sset.process_queues();
358 assert(p.get_state() == service_state_t::STOPPING);
360 base_process_service_test::handle_exit(&p, 0);
361 sset.process_queues();
362 assert(p.get_state() == service_state_t::STOPPED);
363 assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
364 assert(event_loop.active_timers.size() == 0);
366 sset.remove_service(&p);
369 // Time-out during start
370 void test_proc_start_timeout()
376 string command = "test-command";
377 list<pair<unsigned,unsigned>> command_offsets;
378 command_offsets.emplace_back(0, command.length());
379 std::list<prelim_dep> depends;
381 scripted_service p {&sset, "testproc", std::move(command), command_offsets, depends};
382 init_service_defaults(p);
383 p.set_start_timeout(time_val(10,0));
384 sset.add_service(&p);
387 sset.process_queues();
389 assert(p.get_state() == service_state_t::STARTING);
391 event_loop.advance_time(time_val(10,0));
392 sset.process_queues();
394 assert(p.get_state() == service_state_t::STOPPING);
396 base_process_service_test::handle_signal_exit(&p, SIGTERM);
397 sset.process_queues();
399 // We set no stop script, so state should now be STOPPED with no timer set
400 assert(p.get_state() == service_state_t::STOPPED);
401 assert(p.get_stop_reason() == stopped_reason_t::TIMEDOUT);
402 assert(event_loop.active_timers.size() == 0);
404 sset.remove_service(&p);
407 // Test that a timeout doesn't stop a "waits for" dependent to fail to start
408 void test_proc_start_timeout2()
414 string command = "test-command";
415 list<pair<unsigned,unsigned>> command_offsets;
416 command_offsets.emplace_back(0, command.length());
417 std::list<prelim_dep> depends;
419 scripted_service p {&sset, "testproc", std::move(command), command_offsets, depends};
420 p.set_start_timeout(time_val {1,0});
421 init_service_defaults(p);
422 sset.add_service(&p);
424 service_record ts {&sset, "test-service-1", service_type_t::INTERNAL,
425 {{&p, dependency_type::WAITS_FOR}} };
428 sset.process_queues();
430 assert(p.get_state() == service_state_t::STARTING);
431 assert(ts.get_state() == service_state_t::STARTING);
433 event_loop.advance_time(time_val {1,0}); // start timer should expire
434 sset.process_queues();
436 assert(p.get_state() == service_state_t::STOPPING);
438 base_process_service_test::handle_exit(&p, 0);
439 sset.process_queues();
441 assert(p.get_state() == service_state_t::STOPPED);
442 assert(p.get_stop_reason() == stopped_reason_t::TIMEDOUT);
443 assert(ts.get_state() == service_state_t::STARTED);
444 assert(event_loop.active_timers.size() == 0);
446 sset.remove_service(&p);
449 // Test exec() failure for process service start.
450 void test_proc_start_execfail()
456 string command = "test-command";
457 list<pair<unsigned,unsigned>> command_offsets;
458 command_offsets.emplace_back(0, command.length());
459 std::list<prelim_dep> depends;
461 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
462 init_service_defaults(p);
463 sset.add_service(&p);
466 sset.process_queues();
468 assert(p.get_state() == service_state_t::STARTING);
470 base_process_service_test::exec_failed(&p, ENOENT);
471 sset.process_queues();
473 assert(p.get_state() == service_state_t::STOPPED);
474 assert(p.get_stop_reason() == stopped_reason_t::EXECFAILED);
475 assert(event_loop.active_timers.size() == 0);
477 sset.remove_service(&p);
480 // Test no ready notification before process terminates
481 void test_proc_notify_fail()
487 string command = "test-command";
488 list<pair<unsigned,unsigned>> command_offsets;
489 command_offsets.emplace_back(0, command.length());
490 std::list<prelim_dep> depends;
492 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
493 init_service_defaults(p);
494 p.set_notification_fd(3);
495 sset.add_service(&p);
498 sset.process_queues();
500 assert(p.get_state() == service_state_t::STARTING);
502 base_process_service_test::exec_succeeded(&p);
503 sset.process_queues();
505 assert(p.get_state() == service_state_t::STARTING);
507 int nfd = base_process_service_test::get_notification_fd(&p);
510 // Signal EOF on notify fd:
511 event_loop.regd_fd_watchers[nfd]->fd_event(event_loop, nfd, dasynq::IN_EVENTS);
513 assert(p.get_state() == service_state_t::STOPPING);
515 base_process_service_test::handle_exit(&p, 0);
516 sset.process_queues();
518 assert(p.get_state() == service_state_t::STOPPED);
519 assert(event_loop.active_timers.size() == 0);
521 sset.remove_service(&p);
525 void test_proc_stop_timeout()
531 string command = "test-command";
532 list<pair<unsigned,unsigned>> command_offsets;
533 command_offsets.emplace_back(0, command.length());
534 std::list<prelim_dep> depends;
536 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
537 init_service_defaults(p);
538 p.set_stop_timeout(time_val {10, 0});
539 sset.add_service(&p);
542 sset.process_queues();
544 assert(p.get_state() == service_state_t::STARTING);
546 base_process_service_test::exec_succeeded(&p);
547 sset.process_queues();
549 assert(p.get_state() == service_state_t::STARTED);
552 sset.process_queues();
554 assert(p.get_state() == service_state_t::STOPPING);
555 assert(bp_sys::last_sig_sent == SIGTERM);
557 event_loop.advance_time(time_val {10, 0}); // expire stop timer
558 sset.process_queues();
560 // kill signal (SIGKILL) should have been sent; process not dead until it's dead, however
561 assert(p.get_state() == service_state_t::STOPPING);
562 assert(bp_sys::last_sig_sent == SIGKILL);
564 base_process_service_test::handle_exit(&p, 0);
565 sset.process_queues();
567 assert(p.get_state() == service_state_t::STOPPED);
568 assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
570 assert(event_loop.active_timers.size() == 0);
572 sset.remove_service(&p);
576 void test_proc_smooth_recovery1()
582 string command = "test-command";
583 list<pair<unsigned,unsigned>> command_offsets;
584 command_offsets.emplace_back(0, command.length());
585 std::list<prelim_dep> depends;
587 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
588 init_service_defaults(p);
589 p.set_smooth_recovery(true);
590 p.set_restart_delay(time_val {0, 1000});
591 sset.add_service(&p);
594 sset.process_queues();
596 base_process_service_test::exec_succeeded(&p);
597 sset.process_queues();
599 pid_t first_instance = bp_sys::last_forked_pid;
601 assert(p.get_state() == service_state_t::STARTED);
603 base_process_service_test::handle_exit(&p, 0);
604 sset.process_queues();
606 // since time hasn't been changed, we expect that the process has not yet been re-launched:
607 assert(first_instance == bp_sys::last_forked_pid);
608 assert(p.get_state() == service_state_t::STARTED);
610 event_loop.advance_time(time_val {0, 1000});
611 sset.process_queues();
613 // Now a new process should've been launched:
614 assert(first_instance + 1 == bp_sys::last_forked_pid);
615 assert(p.get_state() == service_state_t::STARTED);
617 assert(event_loop.active_timers.size() == 0);
619 sset.remove_service(&p);
622 // Smooth recovery without restart delay
623 void test_proc_smooth_recovery2()
629 string command = "test-command";
630 list<pair<unsigned,unsigned>> command_offsets;
631 command_offsets.emplace_back(0, command.length());
632 std::list<prelim_dep> depends;
634 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
635 init_service_defaults(p);
636 p.set_smooth_recovery(true);
637 p.set_restart_delay(time_val(0, 0));
638 sset.add_service(&p);
641 sset.process_queues();
643 base_process_service_test::exec_succeeded(&p);
644 sset.process_queues();
646 pid_t first_instance = bp_sys::last_forked_pid;
648 assert(p.get_state() == service_state_t::STARTED);
649 assert(event_loop.active_timers.size() == 0);
651 base_process_service_test::handle_exit(&p, 0);
652 sset.process_queues();
654 // no restart delay, process should restart immediately:
655 assert(first_instance + 1 == bp_sys::last_forked_pid);
656 assert(p.get_state() == service_state_t::STARTED);
657 assert(event_loop.active_timers.size() == 0);
659 sset.remove_service(&p);
663 void test_scripted_stop_timeout()
669 string command = "test-command";
670 string stopcommand = "stop-command";
671 list<pair<unsigned,unsigned>> command_offsets;
672 command_offsets.emplace_back(0, command.length());
673 std::list<prelim_dep> depends;
675 scripted_service p {&sset, "testscripted", std::move(command), command_offsets, depends};
676 init_service_defaults(p);
677 p.set_stop_command(stopcommand, command_offsets);
678 p.set_stop_timeout(time_val {10, 0});
679 sset.add_service(&p);
682 sset.process_queues();
684 assert(p.get_state() == service_state_t::STARTING);
686 base_process_service_test::exec_succeeded(&p);
687 sset.process_queues();
688 base_process_service_test::handle_exit(&p, 0);
689 sset.process_queues();
691 assert(p.get_state() == service_state_t::STARTED);
694 sset.process_queues();
696 assert(p.get_state() == service_state_t::STOPPING);
698 base_process_service_test::exec_succeeded(&p);
699 sset.process_queues();
701 // should still be stopping:
702 assert(p.get_state() == service_state_t::STOPPING);
704 event_loop.advance_time(time_val {10, 0}); // expire stop timer
705 sset.process_queues();
707 // kill signal (SIGKILL) should have been sent; process not dead until it's dead, however
708 assert(p.get_state() == service_state_t::STOPPING);
709 assert(bp_sys::last_sig_sent == SIGKILL);
711 base_process_service_test::handle_exit(&p, SIGKILL);
712 sset.process_queues();
714 assert(p.get_state() == service_state_t::STOPPED);
715 assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
717 assert(event_loop.active_timers.size() == 0);
719 sset.remove_service(&p);
722 void test_scripted_start_fail()
728 string command = "test-command";
729 string stopcommand = "stop-command";
730 list<pair<unsigned,unsigned>> command_offsets;
731 command_offsets.emplace_back(0, command.length());
732 std::list<prelim_dep> depends;
734 scripted_service p {&sset, "testscripted", std::move(command), command_offsets, depends};
735 init_service_defaults(p);
736 p.set_stop_command(stopcommand, command_offsets);
737 sset.add_service(&p);
739 service_record *s2 = new service_record(&sset, "test-service-2", service_type_t::INTERNAL, {{&p, REG}});
740 service_record *s3 = new service_record(&sset, "test-service-3",
741 service_type_t::INTERNAL, {{&p, REG}, {s2, REG}});
742 sset.add_service(s2);
743 sset.add_service(s3);
746 sset.process_queues();
748 assert(p.get_state() == service_state_t::STARTING);
750 base_process_service_test::exec_succeeded(&p);
751 sset.process_queues();
752 base_process_service_test::handle_exit(&p, 0x1); // exit fail
753 sset.process_queues();
756 assert(p.get_state() == service_state_t::STOPPED);
757 assert(s2->get_state() == service_state_t::STOPPED);
758 assert(s3->get_state() == service_state_t::STOPPED);
759 assert(p.get_stop_reason() == stopped_reason_t::FAILED);
760 assert(s2->get_stop_reason() == stopped_reason_t::DEPFAILED);
761 assert(s3->get_stop_reason() == stopped_reason_t::DEPFAILED);
763 event_loop.active_timers.clear();
764 sset.remove_service(&p);
766 assert(sset.count_active_services() == 0);
769 void test_scripted_stop_fail()
775 string command = "test-command";
776 string stopcommand = "stop-command";
777 list<pair<unsigned,unsigned>> command_offsets;
778 command_offsets.emplace_back(0, command.length());
779 std::list<prelim_dep> depends;
781 scripted_service p {&sset, "testscripted", std::move(command), command_offsets, depends};
782 init_service_defaults(p);
783 p.set_stop_command(stopcommand, command_offsets);
784 sset.add_service(&p);
786 service_record *s2 = new service_record(&sset, "test-service-2", service_type_t::INTERNAL, {});
787 service_record *s3 = new service_record(&sset, "test-service-3", service_type_t::INTERNAL,
788 {{s2, REG}, {&p, REG}});
789 service_record *s4 = new service_record(&sset, "test-service-4", service_type_t::INTERNAL,
790 {{&p, REG}, {s3, REG}});
791 sset.add_service(s2);
792 sset.add_service(s3);
793 sset.add_service(s4);
796 sset.process_queues();
798 base_process_service_test::exec_succeeded(&p);
799 sset.process_queues();
800 base_process_service_test::handle_exit(&p, 0x0); // success
801 sset.process_queues();
803 assert(p.get_state() == service_state_t::STARTED);
804 assert(s2->get_state() == service_state_t::STARTED);
805 assert(s3->get_state() == service_state_t::STARTED);
806 assert(s4->get_state() == service_state_t::STARTED);
808 pid_t last_forked = bp_sys::last_forked_pid;
811 sset.process_queues();
813 base_process_service_test::exec_succeeded(&p);
814 sset.process_queues();
815 base_process_service_test::handle_exit(&p, 0x1); // failure
816 sset.process_queues();
818 // The stop command should be executed once:
819 assert((bp_sys::last_forked_pid - last_forked) == 1);
821 assert(p.get_state() == service_state_t::STOPPED);
822 assert(s2->get_state() == service_state_t::STOPPED);
823 assert(s3->get_state() == service_state_t::STOPPED);
824 assert(s4->get_state() == service_state_t::STOPPED);
826 event_loop.active_timers.clear();
827 sset.remove_service(&p);
830 void test_scripted_start_skip()
836 string command = "test-command";
837 list<pair<unsigned,unsigned>> command_offsets;
838 command_offsets.emplace_back(0, command.length());
839 std::list<prelim_dep> depends;
841 scripted_service p {&sset, "testscripted", std::move(command), command_offsets, depends};
842 init_service_defaults(p);
843 service_flags_t sflags;
844 sflags.skippable = true;
846 sset.add_service(&p);
848 service_record *s2 = new service_record(&sset, "test-service-2", service_type_t::INTERNAL, {{&p, REG}});
849 sset.add_service(s2);
852 sset.process_queues();
853 assert(p.get_state() == service_state_t::STARTING);
855 base_process_service_test::exec_succeeded(&p);
856 sset.process_queues();
857 assert(p.get_state() == service_state_t::STARTING);
859 base_process_service_test::handle_signal_exit(&p, SIGINT); // interrupted
860 sset.process_queues();
862 assert(p.get_state() == service_state_t::STARTED);
863 assert(s2->get_state() == service_state_t::STARTED);
864 assert(p.was_start_skipped());
865 assert(! s2->was_start_skipped());
866 assert(sset.count_active_services() == 2);
869 sset.process_queues();
871 assert(p.get_state() == service_state_t::STOPPED);
872 assert(s2->get_state() == service_state_t::STOPPED);
873 assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
874 assert(s2->get_stop_reason() == stopped_reason_t::NORMAL);
875 assert(sset.count_active_services() == 0);
877 event_loop.active_timers.clear();
878 sset.remove_service(&p);
881 // Test interrupting start of a service marked skippable
882 void test_scripted_start_skip2()
888 string command = "test-command";
889 list<pair<unsigned,unsigned>> command_offsets;
890 command_offsets.emplace_back(0, command.length());
891 std::list<prelim_dep> depends;
893 scripted_service p {&sset, "testscripted", std::move(command), command_offsets, depends};
894 init_service_defaults(p);
895 service_flags_t sflags;
896 sflags.skippable = true;
897 sflags.start_interruptible = true;
899 sset.add_service(&p);
901 service_record *s2 = new service_record(&sset, "test-service-2", service_type_t::INTERNAL, {{&p, REG}});
902 sset.add_service(s2);
905 sset.process_queues();
906 assert(p.get_state() == service_state_t::STARTING);
908 base_process_service_test::exec_succeeded(&p);
909 sset.process_queues();
910 assert(p.get_state() == service_state_t::STARTING);
912 s2->stop(true); // abort startup; p should be cancelled
913 sset.process_queues();
915 assert(p.get_state() == service_state_t::STOPPING);
917 base_process_service_test::handle_signal_exit(&p, SIGINT); // interrupted
918 sset.process_queues();
920 assert(p.get_state() == service_state_t::STOPPED);
921 assert(s2->get_state() == service_state_t::STOPPED);
922 assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
923 assert(s2->get_stop_reason() == stopped_reason_t::NORMAL);
924 assert(sset.count_active_services() == 0);
926 event_loop.active_timers.clear();
927 sset.remove_service(&p);
930 // Test that starting a service with a waits-for dependency on another - currently stopping - service,
931 // causes that service to re-start.
932 void test_waitsfor_restart()
938 string command = "test-command";
939 list<pair<unsigned,unsigned>> command_offsets;
940 command_offsets.emplace_back(0, command.length());
941 std::list<prelim_dep> depends;
943 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
944 init_service_defaults(p);
945 sset.add_service(&p);
947 service_record tp {&sset, "test-service", service_type_t::INTERNAL, {{&p, WAITS}}};
948 sset.add_service(&tp);
953 sset.process_queues();
955 assert(p.get_state() == service_state_t::STARTING);
957 base_process_service_test::exec_succeeded(&p);
958 sset.process_queues();
960 assert(p.get_state() == service_state_t::STARTED);
961 assert(event_loop.active_timers.size() == 0);
966 sset.process_queues();
968 assert(p.get_state() == service_state_t::STOPPING);
970 // start tp (which waits-for p):
973 sset.process_queues();
975 assert(tp.get_state() == service_state_t::STARTING);
976 assert(p.get_state() == service_state_t::STOPPING);
978 base_process_service_test::handle_signal_exit(&p, SIGTERM);
979 sset.process_queues();
981 assert(tp.get_state() == service_state_t::STARTING);
982 assert(p.get_state() == service_state_t::STARTING);
984 base_process_service_test::exec_succeeded(&p);
985 sset.process_queues();
987 assert(tp.get_state() == service_state_t::STARTED);
988 assert(p.get_state() == service_state_t::STARTED);
990 sset.remove_service(&tp);
991 sset.remove_service(&p);
995 #define RUN_TEST(name, spacing) \
996 std::cout << #name "..." spacing << std::flush; \
998 std::cout << "PASSED" << std::endl;
1000 int main(int argc, char **argv)
1002 RUN_TEST(test_proc_service_start, " ");
1003 RUN_TEST(test_proc_notify_start, " ");
1004 RUN_TEST(test_proc_unexpected_term, " ");
1005 RUN_TEST(test_proc_term_restart, " ");
1006 RUN_TEST(test_proc_term_restart2, " ");
1007 RUN_TEST(test_term_via_stop, " ");
1008 RUN_TEST(test_term_via_stop2, " ");
1009 RUN_TEST(test_proc_start_timeout, " ");
1010 RUN_TEST(test_proc_start_timeout2, " ");
1011 RUN_TEST(test_proc_start_execfail, " ");
1012 RUN_TEST(test_proc_notify_fail, " ");
1013 RUN_TEST(test_proc_stop_timeout, " ");
1014 RUN_TEST(test_proc_smooth_recovery1, "");
1015 RUN_TEST(test_proc_smooth_recovery2, "");
1016 RUN_TEST(test_scripted_stop_timeout, "");
1017 RUN_TEST(test_scripted_start_fail, " ");
1018 RUN_TEST(test_scripted_stop_fail, " ");
1019 RUN_TEST(test_scripted_start_skip, " ");
1020 RUN_TEST(test_scripted_start_skip2, " ");
1021 RUN_TEST(test_waitsfor_restart, " ");