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 base_process_service_test::handle_exit(&p, 0);
255 sset.process_queues();
257 // Starting, restart timer should be armed:
258 assert(p.get_state() == service_state_t::STARTING);
259 assert(event_loop.active_timers.size() == 1);
261 event_loop.advance_time(time_val(0, 200000000));
262 assert(event_loop.active_timers.size() == 0);
264 sset.process_queues();
265 base_process_service_test::exec_succeeded(&p);
266 sset.process_queues();
268 assert(p.get_state() == service_state_t::STARTED);
269 assert(event_loop.active_timers.size() == 0);
271 sset.remove_service(&p);
272 sset.remove_service(&b);
276 // Termination via stop request
277 void test_term_via_stop()
283 string command = "test-command";
284 list<pair<unsigned,unsigned>> command_offsets;
285 command_offsets.emplace_back(0, command.length());
286 std::list<prelim_dep> depends;
288 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
289 init_service_defaults(p);
290 sset.add_service(&p);
293 sset.process_queues();
295 base_process_service_test::exec_succeeded(&p);
296 sset.process_queues();
298 assert(p.get_state() == service_state_t::STARTED);
299 assert(event_loop.active_timers.size() == 0);
302 sset.process_queues();
304 assert(p.get_state() == service_state_t::STOPPING);
305 assert(event_loop.active_timers.size() == 1);
307 base_process_service_test::handle_exit(&p, 0);
308 sset.process_queues();
310 assert(p.get_state() == service_state_t::STOPPED);
311 assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
312 assert(event_loop.active_timers.size() == 0);
314 sset.remove_service(&p);
317 // Termination via stop request, ensure reason is reset:
318 void test_term_via_stop2()
324 string command = "test-command";
325 list<pair<unsigned,unsigned>> command_offsets;
326 command_offsets.emplace_back(0, command.length());
327 std::list<prelim_dep> depends;
329 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
330 init_service_defaults(p);
331 sset.add_service(&p);
334 sset.process_queues();
336 // first set it up with failure reason:
338 base_process_service_test::exec_failed(&p, ENOENT);
339 sset.process_queues();
341 assert(p.get_state() == service_state_t::STOPPED);
342 assert(p.get_stop_reason() == stopped_reason_t::EXECFAILED);
344 // now restart clean:
347 sset.process_queues();
349 base_process_service_test::exec_succeeded(&p);
350 sset.process_queues();
352 assert(p.get_state() == service_state_t::STARTED);
353 assert(event_loop.active_timers.size() == 0);
356 sset.process_queues();
357 assert(p.get_state() == service_state_t::STOPPING);
359 base_process_service_test::handle_exit(&p, 0);
360 sset.process_queues();
361 assert(p.get_state() == service_state_t::STOPPED);
362 assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
363 assert(event_loop.active_timers.size() == 0);
365 sset.remove_service(&p);
368 // Time-out during start
369 void test_proc_start_timeout()
375 string command = "test-command";
376 list<pair<unsigned,unsigned>> command_offsets;
377 command_offsets.emplace_back(0, command.length());
378 std::list<prelim_dep> depends;
380 scripted_service p {&sset, "testproc", std::move(command), command_offsets, depends};
381 init_service_defaults(p);
382 p.set_start_timeout(time_val(10,0));
383 sset.add_service(&p);
386 sset.process_queues();
388 assert(p.get_state() == service_state_t::STARTING);
390 event_loop.advance_time(time_val(10,0));
391 sset.process_queues();
393 assert(p.get_state() == service_state_t::STOPPING);
395 base_process_service_test::handle_signal_exit(&p, SIGTERM);
396 sset.process_queues();
398 // We set no stop script, so state should now be STOPPED with no timer set
399 assert(p.get_state() == service_state_t::STOPPED);
400 assert(p.get_stop_reason() == stopped_reason_t::TIMEDOUT);
401 assert(event_loop.active_timers.size() == 0);
403 sset.remove_service(&p);
406 // Test that a timeout doesn't stop a "waits for" dependent to fail to start
407 void test_proc_start_timeout2()
413 string command = "test-command";
414 list<pair<unsigned,unsigned>> command_offsets;
415 command_offsets.emplace_back(0, command.length());
416 std::list<prelim_dep> depends;
418 scripted_service p {&sset, "testproc", std::move(command), command_offsets, depends};
419 p.set_start_timeout(time_val {1,0});
420 init_service_defaults(p);
421 sset.add_service(&p);
423 service_record ts {&sset, "test-service-1", service_type_t::INTERNAL,
424 {{&p, dependency_type::WAITS_FOR}} };
427 sset.process_queues();
429 assert(p.get_state() == service_state_t::STARTING);
430 assert(ts.get_state() == service_state_t::STARTING);
432 event_loop.advance_time(time_val {1,0}); // start timer should expire
433 sset.process_queues();
435 assert(p.get_state() == service_state_t::STOPPING);
437 base_process_service_test::handle_exit(&p, 0);
438 sset.process_queues();
440 assert(p.get_state() == service_state_t::STOPPED);
441 assert(p.get_stop_reason() == stopped_reason_t::TIMEDOUT);
442 assert(ts.get_state() == service_state_t::STARTED);
443 assert(event_loop.active_timers.size() == 0);
445 sset.remove_service(&p);
448 // Test exec() failure for process service start.
449 void test_proc_start_execfail()
455 string command = "test-command";
456 list<pair<unsigned,unsigned>> command_offsets;
457 command_offsets.emplace_back(0, command.length());
458 std::list<prelim_dep> depends;
460 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
461 init_service_defaults(p);
462 sset.add_service(&p);
465 sset.process_queues();
467 assert(p.get_state() == service_state_t::STARTING);
469 base_process_service_test::exec_failed(&p, ENOENT);
470 sset.process_queues();
472 assert(p.get_state() == service_state_t::STOPPED);
473 assert(p.get_stop_reason() == stopped_reason_t::EXECFAILED);
474 assert(event_loop.active_timers.size() == 0);
476 sset.remove_service(&p);
479 // Test no ready notification before process terminates
480 void test_proc_notify_fail()
486 string command = "test-command";
487 list<pair<unsigned,unsigned>> command_offsets;
488 command_offsets.emplace_back(0, command.length());
489 std::list<prelim_dep> depends;
491 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
492 init_service_defaults(p);
493 p.set_notification_fd(3);
494 sset.add_service(&p);
497 sset.process_queues();
499 assert(p.get_state() == service_state_t::STARTING);
501 base_process_service_test::exec_succeeded(&p);
502 sset.process_queues();
504 assert(p.get_state() == service_state_t::STARTING);
506 int nfd = base_process_service_test::get_notification_fd(&p);
509 // Signal EOF on notify fd:
510 event_loop.regd_fd_watchers[nfd]->fd_event(event_loop, nfd, dasynq::IN_EVENTS);
512 assert(p.get_state() == service_state_t::STOPPING);
514 base_process_service_test::handle_exit(&p, 0);
515 sset.process_queues();
517 assert(p.get_state() == service_state_t::STOPPED);
518 assert(event_loop.active_timers.size() == 0);
520 sset.remove_service(&p);
524 void test_proc_stop_timeout()
530 string command = "test-command";
531 list<pair<unsigned,unsigned>> command_offsets;
532 command_offsets.emplace_back(0, command.length());
533 std::list<prelim_dep> depends;
535 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
536 init_service_defaults(p);
537 p.set_stop_timeout(time_val {10, 0});
538 sset.add_service(&p);
541 sset.process_queues();
543 assert(p.get_state() == service_state_t::STARTING);
545 base_process_service_test::exec_succeeded(&p);
546 sset.process_queues();
548 assert(p.get_state() == service_state_t::STARTED);
551 sset.process_queues();
553 assert(p.get_state() == service_state_t::STOPPING);
554 assert(bp_sys::last_sig_sent == SIGTERM);
556 event_loop.advance_time(time_val {10, 0}); // expire stop timer
557 sset.process_queues();
559 // kill signal (SIGKILL) should have been sent; process not dead until it's dead, however
560 assert(p.get_state() == service_state_t::STOPPING);
561 assert(bp_sys::last_sig_sent == SIGKILL);
563 base_process_service_test::handle_exit(&p, 0);
564 sset.process_queues();
566 assert(p.get_state() == service_state_t::STOPPED);
567 assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
569 assert(event_loop.active_timers.size() == 0);
571 sset.remove_service(&p);
575 void test_proc_smooth_recovery1()
581 string command = "test-command";
582 list<pair<unsigned,unsigned>> command_offsets;
583 command_offsets.emplace_back(0, command.length());
584 std::list<prelim_dep> depends;
586 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
587 init_service_defaults(p);
588 p.set_smooth_recovery(true);
589 p.set_restart_delay(time_val {0, 1000});
590 sset.add_service(&p);
593 sset.process_queues();
595 base_process_service_test::exec_succeeded(&p);
596 sset.process_queues();
598 pid_t first_instance = bp_sys::last_forked_pid;
600 assert(p.get_state() == service_state_t::STARTED);
602 base_process_service_test::handle_exit(&p, 0);
603 sset.process_queues();
605 // since time hasn't been changed, we expect that the process has not yet been re-launched:
606 assert(first_instance == bp_sys::last_forked_pid);
607 assert(p.get_state() == service_state_t::STARTED);
609 event_loop.advance_time(time_val {0, 1000});
610 sset.process_queues();
612 // Now a new process should've been launched:
613 assert(first_instance + 1 == bp_sys::last_forked_pid);
614 assert(p.get_state() == service_state_t::STARTED);
616 assert(event_loop.active_timers.size() == 0);
618 sset.remove_service(&p);
621 // Smooth recovery without restart delay
622 void test_proc_smooth_recovery2()
628 string command = "test-command";
629 list<pair<unsigned,unsigned>> command_offsets;
630 command_offsets.emplace_back(0, command.length());
631 std::list<prelim_dep> depends;
633 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
634 init_service_defaults(p);
635 p.set_smooth_recovery(true);
636 p.set_restart_delay(time_val(0, 0));
637 sset.add_service(&p);
640 sset.process_queues();
642 base_process_service_test::exec_succeeded(&p);
643 sset.process_queues();
645 pid_t first_instance = bp_sys::last_forked_pid;
647 assert(p.get_state() == service_state_t::STARTED);
648 assert(event_loop.active_timers.size() == 0);
650 base_process_service_test::handle_exit(&p, 0);
651 sset.process_queues();
653 // no restart delay, process should restart immediately:
654 assert(first_instance + 1 == bp_sys::last_forked_pid);
655 assert(p.get_state() == service_state_t::STARTED);
656 assert(event_loop.active_timers.size() == 0);
658 sset.remove_service(&p);
662 void test_scripted_stop_timeout()
668 string command = "test-command";
669 string stopcommand = "stop-command";
670 list<pair<unsigned,unsigned>> command_offsets;
671 command_offsets.emplace_back(0, command.length());
672 std::list<prelim_dep> depends;
674 scripted_service p {&sset, "testscripted", std::move(command), command_offsets, depends};
675 init_service_defaults(p);
676 p.set_stop_command(stopcommand, command_offsets);
677 p.set_stop_timeout(time_val {10, 0});
678 sset.add_service(&p);
681 sset.process_queues();
683 assert(p.get_state() == service_state_t::STARTING);
685 base_process_service_test::exec_succeeded(&p);
686 sset.process_queues();
687 base_process_service_test::handle_exit(&p, 0);
688 sset.process_queues();
690 assert(p.get_state() == service_state_t::STARTED);
693 sset.process_queues();
695 assert(p.get_state() == service_state_t::STOPPING);
697 base_process_service_test::exec_succeeded(&p);
698 sset.process_queues();
700 // should still be stopping:
701 assert(p.get_state() == service_state_t::STOPPING);
703 event_loop.advance_time(time_val {10, 0}); // expire stop timer
704 sset.process_queues();
706 // kill signal (SIGKILL) should have been sent; process not dead until it's dead, however
707 assert(p.get_state() == service_state_t::STOPPING);
708 assert(bp_sys::last_sig_sent == SIGKILL);
710 base_process_service_test::handle_exit(&p, SIGKILL);
711 sset.process_queues();
713 assert(p.get_state() == service_state_t::STOPPED);
714 assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
716 assert(event_loop.active_timers.size() == 0);
718 sset.remove_service(&p);
721 void test_scripted_start_fail()
727 string command = "test-command";
728 string stopcommand = "stop-command";
729 list<pair<unsigned,unsigned>> command_offsets;
730 command_offsets.emplace_back(0, command.length());
731 std::list<prelim_dep> depends;
733 scripted_service p {&sset, "testscripted", std::move(command), command_offsets, depends};
734 init_service_defaults(p);
735 p.set_stop_command(stopcommand, command_offsets);
736 sset.add_service(&p);
738 service_record *s2 = new service_record(&sset, "test-service-2", service_type_t::INTERNAL, {{&p, REG}});
739 service_record *s3 = new service_record(&sset, "test-service-3",
740 service_type_t::INTERNAL, {{&p, REG}, {s2, REG}});
741 sset.add_service(s2);
742 sset.add_service(s3);
745 sset.process_queues();
747 assert(p.get_state() == service_state_t::STARTING);
749 base_process_service_test::exec_succeeded(&p);
750 sset.process_queues();
751 base_process_service_test::handle_exit(&p, 0x1); // exit fail
752 sset.process_queues();
755 assert(p.get_state() == service_state_t::STOPPED);
756 assert(s2->get_state() == service_state_t::STOPPED);
757 assert(s3->get_state() == service_state_t::STOPPED);
758 assert(p.get_stop_reason() == stopped_reason_t::FAILED);
759 assert(s2->get_stop_reason() == stopped_reason_t::DEPFAILED);
760 assert(s3->get_stop_reason() == stopped_reason_t::DEPFAILED);
762 event_loop.active_timers.clear();
763 sset.remove_service(&p);
765 assert(sset.count_active_services() == 0);
768 void test_scripted_stop_fail()
774 string command = "test-command";
775 string stopcommand = "stop-command";
776 list<pair<unsigned,unsigned>> command_offsets;
777 command_offsets.emplace_back(0, command.length());
778 std::list<prelim_dep> depends;
780 scripted_service p {&sset, "testscripted", std::move(command), command_offsets, depends};
781 init_service_defaults(p);
782 p.set_stop_command(stopcommand, command_offsets);
783 sset.add_service(&p);
785 service_record *s2 = new service_record(&sset, "test-service-2", service_type_t::INTERNAL, {});
786 service_record *s3 = new service_record(&sset, "test-service-3", service_type_t::INTERNAL,
787 {{s2, REG}, {&p, REG}});
788 service_record *s4 = new service_record(&sset, "test-service-4", service_type_t::INTERNAL,
789 {{&p, REG}, {s3, REG}});
790 sset.add_service(s2);
791 sset.add_service(s3);
792 sset.add_service(s4);
795 sset.process_queues();
797 base_process_service_test::exec_succeeded(&p);
798 sset.process_queues();
799 base_process_service_test::handle_exit(&p, 0x0); // success
800 sset.process_queues();
802 assert(p.get_state() == service_state_t::STARTED);
803 assert(s2->get_state() == service_state_t::STARTED);
804 assert(s3->get_state() == service_state_t::STARTED);
805 assert(s4->get_state() == service_state_t::STARTED);
807 pid_t last_forked = bp_sys::last_forked_pid;
810 sset.process_queues();
812 base_process_service_test::exec_succeeded(&p);
813 sset.process_queues();
814 base_process_service_test::handle_exit(&p, 0x1); // failure
815 sset.process_queues();
817 // The stop command should be executed once:
818 assert((bp_sys::last_forked_pid - last_forked) == 1);
820 assert(p.get_state() == service_state_t::STOPPED);
821 assert(s2->get_state() == service_state_t::STOPPED);
822 assert(s3->get_state() == service_state_t::STOPPED);
823 assert(s4->get_state() == service_state_t::STOPPED);
825 event_loop.active_timers.clear();
826 sset.remove_service(&p);
829 void test_scripted_start_skip()
835 string command = "test-command";
836 list<pair<unsigned,unsigned>> command_offsets;
837 command_offsets.emplace_back(0, command.length());
838 std::list<prelim_dep> depends;
840 scripted_service p {&sset, "testscripted", std::move(command), command_offsets, depends};
841 init_service_defaults(p);
842 service_flags_t sflags;
843 sflags.skippable = true;
845 sset.add_service(&p);
847 service_record *s2 = new service_record(&sset, "test-service-2", service_type_t::INTERNAL, {{&p, REG}});
848 sset.add_service(s2);
851 sset.process_queues();
852 assert(p.get_state() == service_state_t::STARTING);
854 base_process_service_test::exec_succeeded(&p);
855 sset.process_queues();
856 assert(p.get_state() == service_state_t::STARTING);
858 base_process_service_test::handle_signal_exit(&p, SIGINT); // interrupted
859 sset.process_queues();
861 assert(p.get_state() == service_state_t::STARTED);
862 assert(s2->get_state() == service_state_t::STARTED);
863 assert(p.was_start_skipped());
864 assert(! s2->was_start_skipped());
865 assert(sset.count_active_services() == 2);
868 sset.process_queues();
870 assert(p.get_state() == service_state_t::STOPPED);
871 assert(s2->get_state() == service_state_t::STOPPED);
872 assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
873 assert(s2->get_stop_reason() == stopped_reason_t::NORMAL);
874 assert(sset.count_active_services() == 0);
876 event_loop.active_timers.clear();
877 sset.remove_service(&p);
880 // Test interrupting start of a service marked skippable
881 void test_scripted_start_skip2()
887 string command = "test-command";
888 list<pair<unsigned,unsigned>> command_offsets;
889 command_offsets.emplace_back(0, command.length());
890 std::list<prelim_dep> depends;
892 scripted_service p {&sset, "testscripted", std::move(command), command_offsets, depends};
893 init_service_defaults(p);
894 service_flags_t sflags;
895 sflags.skippable = true;
896 sflags.start_interruptible = true;
898 sset.add_service(&p);
900 service_record *s2 = new service_record(&sset, "test-service-2", service_type_t::INTERNAL, {{&p, REG}});
901 sset.add_service(s2);
904 sset.process_queues();
905 assert(p.get_state() == service_state_t::STARTING);
907 base_process_service_test::exec_succeeded(&p);
908 sset.process_queues();
909 assert(p.get_state() == service_state_t::STARTING);
911 s2->stop(true); // abort startup; p should be cancelled
912 sset.process_queues();
914 assert(p.get_state() == service_state_t::STOPPING);
916 base_process_service_test::handle_signal_exit(&p, SIGINT); // interrupted
917 sset.process_queues();
919 assert(p.get_state() == service_state_t::STOPPED);
920 assert(s2->get_state() == service_state_t::STOPPED);
921 assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
922 assert(s2->get_stop_reason() == stopped_reason_t::NORMAL);
923 assert(sset.count_active_services() == 0);
925 event_loop.active_timers.clear();
926 sset.remove_service(&p);
929 // Test that starting a service with a waits-for dependency on another - currently stopping - service,
930 // causes that service to re-start.
931 void test_waitsfor_restart()
937 string command = "test-command";
938 list<pair<unsigned,unsigned>> command_offsets;
939 command_offsets.emplace_back(0, command.length());
940 std::list<prelim_dep> depends;
942 process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
943 init_service_defaults(p);
944 sset.add_service(&p);
946 service_record tp {&sset, "test-service", service_type_t::INTERNAL, {{&p, WAITS}}};
947 sset.add_service(&tp);
952 sset.process_queues();
954 assert(p.get_state() == service_state_t::STARTING);
956 base_process_service_test::exec_succeeded(&p);
957 sset.process_queues();
959 assert(p.get_state() == service_state_t::STARTED);
960 assert(event_loop.active_timers.size() == 0);
965 sset.process_queues();
967 assert(p.get_state() == service_state_t::STOPPING);
969 // start tp (which waits-for p):
972 sset.process_queues();
974 assert(tp.get_state() == service_state_t::STARTING);
975 assert(p.get_state() == service_state_t::STOPPING);
977 // p terminates (finishes stopping). Then it should re-start...
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, " ");