proctests.cc 71 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370
  1. #include <cassert>
  2. #include <iostream>
  3. #include <list>
  4. #include <utility>
  5. #include <string>
  6. #include <sstream>
  7. #include "service.h"
  8. #include "proc-service.h"
  9. #include "dinit-util.h"
  10. #include "test_procservice.h"
  11. // Tests of process-service related functionality.
  12. //
  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.
  15. extern eventloop_t event_loop;
  16. constexpr static auto REG = dependency_type::REGULAR;
  17. constexpr static auto WAITS = dependency_type::WAITS_FOR;
  18. // Regular service start
  19. void test_proc_service_start()
  20. {
  21. using namespace std;
  22. service_set sset;
  23. ha_string command = "test-command";
  24. list<pair<unsigned,unsigned>> command_offsets;
  25. command_offsets.emplace_back(0, command.length());
  26. std::list<prelim_dep> depends;
  27. process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  28. init_service_defaults(p);
  29. sset.add_service(&p);
  30. p.start();
  31. sset.process_queues();
  32. assert(p.get_state() == service_state_t::STARTING);
  33. base_process_service_test::exec_succeeded(&p);
  34. sset.process_queues();
  35. assert(p.get_state() == service_state_t::STARTED);
  36. assert(event_loop.active_timers.size() == 0);
  37. sset.remove_service(&p);
  38. }
  39. // Test start with readiness notification
  40. void test_proc_notify_start()
  41. {
  42. using namespace std;
  43. service_set sset;
  44. ha_string command = "test-command";
  45. list<pair<unsigned,unsigned>> command_offsets;
  46. command_offsets.emplace_back(0, command.length());
  47. std::list<prelim_dep> depends;
  48. process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  49. init_service_defaults(p);
  50. p.set_notification_fd(3);
  51. sset.add_service(&p);
  52. p.start();
  53. sset.process_queues();
  54. assert(p.get_state() == service_state_t::STARTING);
  55. base_process_service_test::exec_succeeded(&p);
  56. sset.process_queues();
  57. assert(p.get_state() == service_state_t::STARTING);
  58. int nfd = base_process_service_test::get_notification_fd(&p);
  59. assert(nfd > 0);
  60. char notifystr[] = "ok started\n";
  61. std::vector<char> rnotifystr;
  62. rnotifystr.insert(rnotifystr.end(), notifystr, notifystr + sizeof(notifystr));
  63. bp_sys::supply_read_data(nfd, std::move(rnotifystr));
  64. event_loop.regd_fd_watchers[nfd]->fd_event(event_loop, nfd, dasynq::IN_EVENTS);
  65. assert(p.get_state() == service_state_t::STARTED);
  66. assert(event_loop.active_timers.size() == 0);
  67. sset.remove_service(&p);
  68. }
  69. // Unexpected termination
  70. void test_proc_unexpected_term()
  71. {
  72. using namespace std;
  73. service_set sset;
  74. ha_string command = "test-command";
  75. list<pair<unsigned,unsigned>> command_offsets;
  76. command_offsets.emplace_back(0, command.length());
  77. std::list<prelim_dep> depends;
  78. process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  79. init_service_defaults(p);
  80. sset.add_service(&p);
  81. service_record d1 {&sset, "test-service-2", service_type_t::INTERNAL, {{&p, REG}}};
  82. sset.add_service(&d1);
  83. d1.start();
  84. sset.process_queues();
  85. base_process_service_test::exec_succeeded(&p);
  86. sset.process_queues();
  87. assert(p.get_state() == service_state_t::STARTED);
  88. assert(p.get_target_state() == service_state_t::STARTED);
  89. assert(d1.get_state() == service_state_t::STARTED);
  90. assert(d1.get_target_state() == service_state_t::STARTED);
  91. base_process_service_test::handle_exit(&p, 0);
  92. assert(p.get_target_state() == service_state_t::STOPPED);
  93. assert(p.get_state() == service_state_t::STOPPED);
  94. assert(p.get_stop_reason() == stopped_reason_t::TERMINATED);
  95. assert(event_loop.active_timers.size() == 0);
  96. assert(d1.get_state() == service_state_t::STOPPED);
  97. assert(d1.get_target_state() == service_state_t::STOPPED);
  98. sset.remove_service(&d1);
  99. sset.remove_service(&p);
  100. }
  101. // Unexpected termination until restarts exhausted, followed by a normal start.
  102. void test_proc_term_start()
  103. {
  104. using namespace std;
  105. service_set sset;
  106. ha_string command = "test-command";
  107. list<pair<unsigned,unsigned>> command_offsets;
  108. command_offsets.emplace_back(0, command.length());
  109. std::list<prelim_dep> depends;
  110. process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  111. init_service_defaults(p);
  112. // One restart per 1000 interval
  113. p.set_restart_interval({1000, 0}, 1);
  114. p.set_auto_restart(true);
  115. sset.add_service(&p);
  116. // Start the service
  117. p.start();
  118. sset.process_queues();
  119. base_process_service_test::exec_succeeded(&p);
  120. sset.process_queues();
  121. assert(p.get_state() == service_state_t::STARTED);
  122. assert(p.get_target_state() == service_state_t::STARTED);
  123. // Unexpected termination - should restart
  124. base_process_service_test::handle_exit(&p, 0);
  125. sset.process_queues();
  126. assert(p.get_target_state() == service_state_t::STARTED);
  127. assert(p.get_state() == service_state_t::STARTING);
  128. base_process_service_test::exec_succeeded(&p);
  129. sset.process_queues();
  130. assert(p.get_state() == service_state_t::STARTED);
  131. assert(p.get_target_state() == service_state_t::STARTED);
  132. // 2nd unexpected termination - should stop
  133. base_process_service_test::handle_exit(&p, 0);
  134. sset.process_queues();
  135. assert(p.get_target_state() == service_state_t::STOPPED);
  136. assert(p.get_state() == service_state_t::STOPPED);
  137. // explicit restart:
  138. p.start();
  139. sset.process_queues();
  140. base_process_service_test::exec_succeeded(&p);
  141. sset.process_queues();
  142. assert(p.get_state() == service_state_t::STARTED);
  143. assert(p.get_target_state() == service_state_t::STARTED);
  144. // Now, again, one automatic restart should go through if the process terminates
  145. // restart:
  146. base_process_service_test::handle_exit(&p, 0);
  147. sset.process_queues();
  148. assert(p.get_target_state() == service_state_t::STARTED);
  149. assert(p.get_state() == service_state_t::STARTING);
  150. base_process_service_test::exec_succeeded(&p);
  151. sset.process_queues();
  152. assert(p.get_state() == service_state_t::STARTED);
  153. assert(p.get_target_state() == service_state_t::STARTED);
  154. // and stop:
  155. base_process_service_test::handle_exit(&p, 0);
  156. sset.process_queues();
  157. assert(p.get_target_state() == service_state_t::STOPPED);
  158. assert(p.get_state() == service_state_t::STOPPED);
  159. sset.remove_service(&p);
  160. }
  161. // Unexpected termination with restart
  162. void test_proc_term_restart()
  163. {
  164. using namespace std;
  165. service_set sset;
  166. ha_string command = "test-command";
  167. list<pair<unsigned,unsigned>> command_offsets;
  168. command_offsets.emplace_back(0, command.length());
  169. std::list<prelim_dep> depends;
  170. process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  171. init_service_defaults(p);
  172. p.set_auto_restart(true);
  173. sset.add_service(&p);
  174. p.start();
  175. sset.process_queues();
  176. pid_t first_pid = bp_sys::last_forked_pid;
  177. base_process_service_test::exec_succeeded(&p);
  178. sset.process_queues();
  179. assert(p.get_state() == service_state_t::STARTED);
  180. assert(event_loop.active_timers.size() == 0);
  181. base_process_service_test::handle_exit(&p, 0);
  182. sset.process_queues();
  183. // Starting, restart timer should be armed:
  184. assert(p.get_state() == service_state_t::STARTING);
  185. assert(event_loop.active_timers.size() == 1);
  186. assert(bp_sys::last_forked_pid == first_pid);
  187. event_loop.advance_time(default_restart_interval);
  188. // Startup timer now active:
  189. assert(event_loop.active_timers.size() == 1);
  190. assert(bp_sys::last_forked_pid == (first_pid + 1));
  191. base_process_service_test::exec_succeeded(&p);
  192. sset.process_queues();
  193. assert(p.get_state() == service_state_t::STARTED);
  194. assert(event_loop.active_timers.size() == 0);
  195. sset.remove_service(&p);
  196. }
  197. // Unexpected termination with restart, with dependent
  198. void test_proc_term_restart2()
  199. {
  200. using namespace std;
  201. service_set sset;
  202. ha_string command = "test-command";
  203. list<pair<unsigned,unsigned>> command_offsets;
  204. command_offsets.emplace_back(0, command.length());
  205. std::list<prelim_dep> depends;
  206. service_record b {&sset, "boot"};
  207. sset.add_service(&b);
  208. process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  209. init_service_defaults(p);
  210. p.set_auto_restart(true);
  211. sset.add_service(&p);
  212. b.add_dep(&p, WAITS);
  213. pid_t first_pid = bp_sys::last_forked_pid;
  214. b.start();
  215. sset.process_queues();
  216. assert(p.get_state() == service_state_t::STARTING);
  217. assert(bp_sys::last_forked_pid == first_pid + 1);
  218. base_process_service_test::exec_succeeded(&p);
  219. sset.process_queues();
  220. assert(p.get_state() == service_state_t::STARTED);
  221. assert(event_loop.active_timers.size() == 0);
  222. assert(bp_sys::last_forked_pid == first_pid + 1);
  223. // simulate process terminating, should then be restarted:
  224. base_process_service_test::handle_exit(&p, 0);
  225. sset.process_queues();
  226. // Starting, restart timer should be armed:
  227. assert(p.get_state() == service_state_t::STARTING);
  228. assert(event_loop.active_timers.size() == 1);
  229. assert(bp_sys::last_forked_pid == first_pid + 1);
  230. event_loop.advance_time(time_val(0, 200000000));
  231. // startup timer will be active:
  232. assert(event_loop.active_timers.size() == 1);
  233. sset.process_queues();
  234. assert(bp_sys::last_forked_pid == first_pid + 2);
  235. base_process_service_test::exec_succeeded(&p);
  236. sset.process_queues();
  237. assert(p.get_state() == service_state_t::STARTED);
  238. assert(event_loop.active_timers.size() == 0);
  239. assert(sset.count_active_services() == 2);
  240. // Request stop, this time it should not restart:
  241. p.stop(true);
  242. sset.process_queues();
  243. base_process_service_test::handle_exit(&p, 0);
  244. sset.process_queues();
  245. assert(p.get_state() == service_state_t::STOPPED);
  246. assert(event_loop.active_timers.size() == 0);
  247. assert(sset.count_active_services() == 1);
  248. assert(bp_sys::last_forked_pid == first_pid + 2);
  249. // simulate terminate dinit
  250. sset.stop_all_services();
  251. sset.process_queues();
  252. assert(p.get_state() == service_state_t::STOPPED);
  253. assert(event_loop.active_timers.size() == 0);
  254. assert(sset.count_active_services() == 0);
  255. sset.remove_service(&p);
  256. sset.remove_service(&b);
  257. }
  258. // Restart due to dependent, after unexpected termination
  259. void test_proc_term_restart3()
  260. {
  261. using namespace std;
  262. service_set sset;
  263. ha_string command = "test-command";
  264. list<pair<unsigned,unsigned>> command_offsets;
  265. command_offsets.emplace_back(0, command.length());
  266. std::list<prelim_dep> depends;
  267. process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  268. init_service_defaults(p);
  269. sset.add_service(&p);
  270. service_record d1 {&sset, "test-service-2", service_type_t::INTERNAL, {{&p, REG}}};
  271. d1.set_auto_restart(true);
  272. sset.add_service(&d1);
  273. d1.start();
  274. sset.process_queues();
  275. base_process_service_test::exec_succeeded(&p);
  276. sset.process_queues();
  277. assert(p.get_state() == service_state_t::STARTED);
  278. assert(p.get_target_state() == service_state_t::STARTED);
  279. assert(d1.get_state() == service_state_t::STARTED);
  280. assert(d1.get_target_state() == service_state_t::STARTED);
  281. base_process_service_test::handle_exit(&p, 0);
  282. sset.process_queues();
  283. assert(p.get_target_state() == service_state_t::STARTED);
  284. assert(p.get_state() == service_state_t::STARTING);
  285. assert(p.get_stop_reason() == stopped_reason_t::TERMINATED);
  286. assert(d1.get_state() == service_state_t::STARTING);
  287. assert(d1.get_target_state() == service_state_t::STARTED);
  288. sset.remove_service(&d1);
  289. sset.remove_service(&p);
  290. event_loop.active_timers.clear();
  291. }
  292. // Restart after unexpected termination, start times out
  293. void test_proc_term_restart4()
  294. {
  295. using namespace std;
  296. service_set sset;
  297. ha_string command = "test-command";
  298. list<pair<unsigned,unsigned>> command_offsets;
  299. command_offsets.emplace_back(0, command.length());
  300. std::list<prelim_dep> depends;
  301. process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  302. init_service_defaults(p);
  303. p.set_auto_restart(true);
  304. time_val start_timeout {5, 0};
  305. p.set_start_timeout(start_timeout);
  306. sset.add_service(&p);
  307. p.start();
  308. sset.process_queues();
  309. pid_t first_pid = bp_sys::last_forked_pid;
  310. base_process_service_test::exec_succeeded(&p);
  311. sset.process_queues();
  312. assert(p.get_state() == service_state_t::STARTED);
  313. assert(event_loop.active_timers.size() == 0);
  314. base_process_service_test::handle_exit(&p, 0);
  315. sset.process_queues();
  316. // Starting, restart timer should be armed:
  317. assert(p.get_state() == service_state_t::STARTING);
  318. assert(event_loop.active_timers.size() == 1);
  319. assert(bp_sys::last_forked_pid == first_pid);
  320. event_loop.advance_time(default_restart_interval);
  321. // restart timer should have stopped, start timeout timer should have started
  322. assert(event_loop.active_timers.size() == 1);
  323. assert(bp_sys::last_forked_pid == (first_pid + 1));
  324. event_loop.advance_time(start_timeout);
  325. assert(p.get_state() == service_state_t::STOPPING);
  326. assert(event_loop.active_timers.size() == 1); // stop timeout should be set
  327. base_process_service_test::exec_succeeded(&p); // the exec must finally succeed...
  328. base_process_service_test::handle_exit(&p, 0);
  329. assert(p.get_state() == service_state_t::STOPPED);
  330. assert(event_loop.active_timers.size() == 0);
  331. sset.remove_service(&p);
  332. }
  333. // Termination via stop request
  334. void test_term_via_stop()
  335. {
  336. using namespace std;
  337. service_set sset;
  338. ha_string command = "test-command";
  339. list<pair<unsigned,unsigned>> command_offsets;
  340. command_offsets.emplace_back(0, command.length());
  341. std::list<prelim_dep> depends;
  342. process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  343. init_service_defaults(p);
  344. sset.add_service(&p);
  345. p.start();
  346. sset.process_queues();
  347. base_process_service_test::exec_succeeded(&p);
  348. sset.process_queues();
  349. assert(p.get_state() == service_state_t::STARTED);
  350. assert(event_loop.active_timers.size() == 0);
  351. p.stop(true);
  352. sset.process_queues();
  353. assert(p.get_state() == service_state_t::STOPPING);
  354. assert(event_loop.active_timers.size() == 1);
  355. base_process_service_test::handle_exit(&p, 0);
  356. sset.process_queues();
  357. assert(p.get_state() == service_state_t::STOPPED);
  358. assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
  359. assert(event_loop.active_timers.size() == 0);
  360. sset.remove_service(&p);
  361. }
  362. // Termination via stop request, ensure reason is reset:
  363. void test_term_via_stop2()
  364. {
  365. using namespace std;
  366. service_set sset;
  367. ha_string command = "test-command";
  368. list<pair<unsigned,unsigned>> command_offsets;
  369. command_offsets.emplace_back(0, command.length());
  370. std::list<prelim_dep> depends;
  371. process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  372. init_service_defaults(p);
  373. sset.add_service(&p);
  374. p.start();
  375. sset.process_queues();
  376. // first set it up with failure reason:
  377. base_process_service_test::exec_failed(&p, ENOENT);
  378. sset.process_queues();
  379. assert(p.get_state() == service_state_t::STOPPED);
  380. assert(p.get_stop_reason() == stopped_reason_t::EXECFAILED);
  381. // now restart clean:
  382. p.start();
  383. sset.process_queues();
  384. base_process_service_test::exec_succeeded(&p);
  385. sset.process_queues();
  386. assert(p.get_state() == service_state_t::STARTED);
  387. assert(event_loop.active_timers.size() == 0);
  388. p.stop(true);
  389. sset.process_queues();
  390. assert(p.get_state() == service_state_t::STOPPING);
  391. base_process_service_test::handle_exit(&p, 0);
  392. sset.process_queues();
  393. assert(p.get_state() == service_state_t::STOPPED);
  394. assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
  395. assert(event_loop.active_timers.size() == 0);
  396. sset.remove_service(&p);
  397. }
  398. // stop twice
  399. void test_term_via_stop3()
  400. {
  401. using namespace std;
  402. service_set sset;
  403. ha_string command = "test-command";
  404. list<pair<unsigned,unsigned>> command_offsets;
  405. command_offsets.emplace_back(0, command.length());
  406. std::list<prelim_dep> depends;
  407. process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  408. init_service_defaults(p);
  409. sset.add_service(&p);
  410. p.start();
  411. sset.process_queues();
  412. base_process_service_test::exec_succeeded(&p);
  413. sset.process_queues();
  414. assert(p.get_state() == service_state_t::STARTED);
  415. assert(event_loop.active_timers.size() == 0);
  416. p.stop(true);
  417. sset.process_queues();
  418. assert(p.get_state() == service_state_t::STOPPING);
  419. assert(event_loop.active_timers.size() == 1);
  420. base_process_service_test::handle_exit(&p, 0);
  421. sset.process_queues();
  422. assert(p.get_state() == service_state_t::STOPPED);
  423. assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
  424. assert(event_loop.active_timers.size() == 0);
  425. p.start();
  426. sset.process_queues();
  427. base_process_service_test::exec_succeeded(&p);
  428. sset.process_queues();
  429. assert(p.get_state() == service_state_t::STARTED);
  430. assert(event_loop.active_timers.size() == 0);
  431. bp_sys::last_sig_sent = 0; // make sure signal is re-sent
  432. p.stop(true);
  433. sset.process_queues();
  434. assert(p.get_state() == service_state_t::STOPPING);
  435. assert(event_loop.active_timers.size() == 1);
  436. assert(bp_sys::last_sig_sent == SIGTERM);
  437. base_process_service_test::handle_exit(&p, 0);
  438. sset.process_queues();
  439. assert(p.get_state() == service_state_t::STOPPED);
  440. assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
  441. assert(event_loop.active_timers.size() == 0);
  442. sset.remove_service(&p);
  443. }
  444. // Time-out during start
  445. void test_proc_start_timeout()
  446. {
  447. using namespace std;
  448. service_set sset;
  449. ha_string command = "test-command";
  450. list<pair<unsigned,unsigned>> command_offsets;
  451. command_offsets.emplace_back(0, command.length());
  452. std::list<prelim_dep> depends;
  453. scripted_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  454. init_service_defaults(p);
  455. p.set_start_timeout(time_val(10,0));
  456. sset.add_service(&p);
  457. p.start();
  458. sset.process_queues();
  459. assert(p.get_state() == service_state_t::STARTING);
  460. event_loop.advance_time(time_val(10,0));
  461. sset.process_queues();
  462. assert(p.get_state() == service_state_t::STOPPING);
  463. base_process_service_test::handle_signal_exit(&p, SIGTERM);
  464. sset.process_queues();
  465. // We set no stop script, so state should now be STOPPED with no timer set
  466. assert(p.get_state() == service_state_t::STOPPED);
  467. assert(p.get_stop_reason() == stopped_reason_t::TIMEDOUT);
  468. assert(event_loop.active_timers.size() == 0);
  469. sset.remove_service(&p);
  470. }
  471. // Test that a timeout doesn't stop a "waits for" dependent to fail to start
  472. void test_proc_start_timeout2()
  473. {
  474. using namespace std;
  475. service_set sset;
  476. ha_string command = "test-command";
  477. list<pair<unsigned,unsigned>> command_offsets;
  478. command_offsets.emplace_back(0, command.length());
  479. std::list<prelim_dep> depends;
  480. scripted_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  481. p.set_start_timeout(time_val {1,0});
  482. init_service_defaults(p);
  483. sset.add_service(&p);
  484. service_record ts {&sset, "test-service-1", service_type_t::INTERNAL,
  485. {{&p, dependency_type::WAITS_FOR}} };
  486. ts.start();
  487. sset.process_queues();
  488. assert(p.get_state() == service_state_t::STARTING);
  489. assert(ts.get_state() == service_state_t::STARTING);
  490. event_loop.advance_time(time_val {1,0}); // start timer should expire
  491. sset.process_queues();
  492. assert(p.get_state() == service_state_t::STOPPING);
  493. base_process_service_test::handle_exit(&p, 0);
  494. sset.process_queues();
  495. assert(p.get_state() == service_state_t::STOPPED);
  496. assert(p.get_stop_reason() == stopped_reason_t::TIMEDOUT);
  497. assert(ts.get_state() == service_state_t::STARTED);
  498. assert(event_loop.active_timers.size() == 0);
  499. sset.remove_service(&p);
  500. }
  501. // Test exec() failure for process service start.
  502. void test_proc_start_execfail()
  503. {
  504. using namespace std;
  505. service_set sset;
  506. ha_string command = "test-command";
  507. list<pair<unsigned,unsigned>> command_offsets;
  508. command_offsets.emplace_back(0, command.length());
  509. std::list<prelim_dep> depends;
  510. process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  511. init_service_defaults(p);
  512. sset.add_service(&p);
  513. p.start();
  514. sset.process_queues();
  515. assert(p.get_state() == service_state_t::STARTING);
  516. base_process_service_test::exec_failed(&p, ENOENT);
  517. sset.process_queues();
  518. assert(p.get_state() == service_state_t::STOPPED);
  519. assert(p.get_stop_reason() == stopped_reason_t::EXECFAILED);
  520. assert(event_loop.active_timers.size() == 0);
  521. sset.remove_service(&p);
  522. }
  523. // Test no ready notification before process terminates
  524. void test_proc_notify_fail()
  525. {
  526. using namespace std;
  527. service_set sset;
  528. ha_string command = "test-command";
  529. list<pair<unsigned,unsigned>> command_offsets;
  530. command_offsets.emplace_back(0, command.length());
  531. std::list<prelim_dep> depends;
  532. process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  533. init_service_defaults(p);
  534. p.set_notification_fd(3);
  535. sset.add_service(&p);
  536. p.start();
  537. sset.process_queues();
  538. assert(p.get_state() == service_state_t::STARTING);
  539. base_process_service_test::exec_succeeded(&p);
  540. sset.process_queues();
  541. assert(p.get_state() == service_state_t::STARTING);
  542. int nfd = base_process_service_test::get_notification_fd(&p);
  543. assert(nfd > 0);
  544. // Signal EOF on notify fd:
  545. event_loop.regd_fd_watchers[nfd]->fd_event(event_loop, nfd, dasynq::IN_EVENTS);
  546. assert(p.get_state() == service_state_t::STOPPING);
  547. base_process_service_test::handle_exit(&p, 0);
  548. sset.process_queues();
  549. assert(p.get_state() == service_state_t::STOPPED);
  550. assert(event_loop.active_timers.size() == 0);
  551. sset.remove_service(&p);
  552. }
  553. // Test stop timeout
  554. void test_proc_stop_timeout()
  555. {
  556. using namespace std;
  557. service_set sset;
  558. ha_string command = "test-command";
  559. list<pair<unsigned,unsigned>> command_offsets;
  560. command_offsets.emplace_back(0, command.length());
  561. std::list<prelim_dep> depends;
  562. process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  563. init_service_defaults(p);
  564. p.set_stop_timeout(time_val {10, 0});
  565. sset.add_service(&p);
  566. p.start();
  567. sset.process_queues();
  568. assert(p.get_state() == service_state_t::STARTING);
  569. base_process_service_test::exec_succeeded(&p);
  570. sset.process_queues();
  571. assert(p.get_state() == service_state_t::STARTED);
  572. p.stop(true);
  573. sset.process_queues();
  574. assert(p.get_state() == service_state_t::STOPPING);
  575. assert(bp_sys::last_sig_sent == SIGTERM);
  576. event_loop.advance_time(time_val {10, 0}); // expire stop timer
  577. sset.process_queues();
  578. // kill signal (SIGKILL) should have been sent; process not dead until it's dead, however
  579. assert(p.get_state() == service_state_t::STOPPING);
  580. assert(bp_sys::last_sig_sent == SIGKILL);
  581. base_process_service_test::handle_exit(&p, 0);
  582. sset.process_queues();
  583. assert(p.get_state() == service_state_t::STOPPED);
  584. assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
  585. assert(event_loop.active_timers.size() == 0);
  586. sset.remove_service(&p);
  587. }
  588. // Smooth recovery
  589. void test_proc_smooth_recovery1()
  590. {
  591. using namespace std;
  592. service_set sset;
  593. ha_string command = "test-command";
  594. list<pair<unsigned,unsigned>> command_offsets;
  595. command_offsets.emplace_back(0, command.length());
  596. std::list<prelim_dep> depends;
  597. process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  598. init_service_defaults(p);
  599. p.set_smooth_recovery(true);
  600. p.set_restart_delay(time_val {0, 1000});
  601. sset.add_service(&p);
  602. p.start();
  603. sset.process_queues();
  604. base_process_service_test::exec_succeeded(&p);
  605. sset.process_queues();
  606. pid_t first_instance = bp_sys::last_forked_pid;
  607. assert(p.get_state() == service_state_t::STARTED);
  608. base_process_service_test::handle_exit(&p, 0);
  609. sset.process_queues();
  610. // since time hasn't been changed, we expect that the process has not yet been re-launched:
  611. assert(first_instance == bp_sys::last_forked_pid);
  612. assert(p.get_state() == service_state_t::STARTED);
  613. event_loop.advance_time(time_val {0, 1000});
  614. sset.process_queues();
  615. // Now a new process should've been launched:
  616. assert(first_instance + 1 == bp_sys::last_forked_pid);
  617. assert(p.get_state() == service_state_t::STARTED);
  618. base_process_service_test::exec_succeeded(&p);
  619. sset.process_queues();
  620. assert(event_loop.active_timers.size() == 0);
  621. sset.remove_service(&p);
  622. }
  623. // Smooth recovery without restart delay
  624. void test_proc_smooth_recovery2()
  625. {
  626. using namespace std;
  627. service_set sset;
  628. ha_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;
  632. process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  633. init_service_defaults(p);
  634. p.set_smooth_recovery(true);
  635. p.set_restart_delay(time_val(0, 0));
  636. sset.add_service(&p);
  637. p.start();
  638. sset.process_queues();
  639. base_process_service_test::exec_succeeded(&p);
  640. sset.process_queues();
  641. pid_t first_instance = bp_sys::last_forked_pid;
  642. assert(p.get_state() == service_state_t::STARTED);
  643. assert(event_loop.active_timers.size() == 0);
  644. base_process_service_test::handle_exit(&p, 0);
  645. sset.process_queues();
  646. // no restart delay, process should restart immediately:
  647. assert(first_instance + 1 == bp_sys::last_forked_pid);
  648. assert(p.get_state() == service_state_t::STARTED);
  649. base_process_service_test::exec_succeeded(&p);
  650. sset.process_queues();
  651. assert(event_loop.active_timers.size() == 0);
  652. sset.remove_service(&p);
  653. }
  654. // failure during smooth recovery is non-recoverable
  655. void test_proc_smooth_recovery3()
  656. {
  657. using namespace std;
  658. service_set sset;
  659. ha_string command = "test-command";
  660. list<pair<unsigned,unsigned>> command_offsets;
  661. command_offsets.emplace_back(0, command.length());
  662. std::list<prelim_dep> depends;
  663. process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  664. init_service_defaults(p);
  665. p.set_smooth_recovery(true);
  666. p.set_restart_delay(time_val(0, 0));
  667. sset.add_service(&p);
  668. service_record d1 {&sset, "test-service-2", service_type_t::INTERNAL, {{&p, REG}}};
  669. d1.set_auto_restart(true);
  670. sset.add_service(&d1);
  671. d1.start();
  672. //p.start();
  673. sset.process_queues();
  674. base_process_service_test::exec_succeeded(&p);
  675. sset.process_queues();
  676. pid_t first_instance = bp_sys::last_forked_pid;
  677. assert(p.get_state() == service_state_t::STARTED);
  678. assert(event_loop.active_timers.size() == 0);
  679. base_process_service_test::handle_exit(&p, 0);
  680. sset.process_queues();
  681. // no restart delay, process should attempt restart immediately:
  682. assert(first_instance + 1 == bp_sys::last_forked_pid);
  683. assert(p.get_state() == service_state_t::STARTED);
  684. assert(event_loop.active_timers.size() == 1); // (restart timer)
  685. base_process_service_test::exec_failed(&p, ENOENT);
  686. sset.process_queues();
  687. assert(p.get_state() == service_state_t::STOPPED);
  688. assert(p.get_target_state() == service_state_t::STOPPED);
  689. assert(d1.get_state() == service_state_t::STOPPED);
  690. assert(d1.get_target_state() == service_state_t::STOPPED);
  691. assert(event_loop.active_timers.size() == 0);
  692. sset.remove_service(&d1);
  693. sset.remove_service(&p);
  694. }
  695. void test_proc_smooth_recovery4()
  696. {
  697. using namespace std;
  698. service_set sset;
  699. ha_string command = "test-command";
  700. list<pair<unsigned,unsigned>> command_offsets;
  701. command_offsets.emplace_back(0, command.length());
  702. std::list<prelim_dep> depends;
  703. process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  704. init_service_defaults(p);
  705. p.set_smooth_recovery(true);
  706. p.set_restart_delay(time_val(2, 0)); // 2 second restart delay
  707. sset.add_service(&p);
  708. p.start();
  709. sset.process_queues();
  710. base_process_service_test::exec_succeeded(&p);
  711. sset.process_queues();
  712. pid_t first_instance = bp_sys::last_forked_pid;
  713. assert(p.get_state() == service_state_t::STARTED);
  714. assert(event_loop.active_timers.size() == 0);
  715. base_process_service_test::handle_exit(&p, 0);
  716. sset.process_queues();
  717. // smooth recovery should have begun
  718. event_loop.advance_time(time_val(1, 0));
  719. assert(p.get_state() == service_state_t::STARTED);
  720. // If we stop now, timer should be cancelled
  721. p.stop(true);
  722. sset.process_queues();
  723. assert(p.get_state() == service_state_t::STOPPED);
  724. assert(first_instance == bp_sys::last_forked_pid); // no more processes launched
  725. assert(event_loop.active_timers.size() == 0);
  726. sset.remove_service(&p);
  727. }
  728. // stop during smooth recovery
  729. void test_proc_smooth_recovery5()
  730. {
  731. using namespace std;
  732. service_set sset;
  733. ha_string command = "test-command";
  734. list<pair<unsigned,unsigned>> command_offsets;
  735. command_offsets.emplace_back(0, command.length());
  736. std::list<prelim_dep> depends;
  737. process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  738. init_service_defaults(p);
  739. p.set_smooth_recovery(true);
  740. p.set_restart_delay(time_val {0, 1000});
  741. sset.add_service(&p);
  742. p.start();
  743. sset.process_queues();
  744. base_process_service_test::exec_succeeded(&p);
  745. sset.process_queues();
  746. pid_t first_instance = bp_sys::last_forked_pid;
  747. assert(p.get_state() == service_state_t::STARTED);
  748. base_process_service_test::handle_exit(&p, 0);
  749. sset.process_queues();
  750. // since time hasn't been changed, we expect that the process has not yet been re-launched:
  751. assert(first_instance == bp_sys::last_forked_pid);
  752. assert(p.get_state() == service_state_t::STARTED);
  753. event_loop.advance_time(time_val {0, 1000});
  754. sset.process_queues();
  755. // Now a new process should've been launched:
  756. assert(first_instance + 1 == bp_sys::last_forked_pid);
  757. assert(p.get_state() == service_state_t::STARTED);
  758. // However, at this stage the exec has not succeeded. If we issue a stop, we shouldn't see a signal sent yet,
  759. // since it's not clear what signal to send (term signal might not be SIGTERM, but if it's something else, the
  760. // process before exec() may not respond correctly)
  761. bp_sys::last_sig_sent = -1;
  762. p.stop(true);
  763. assert(bp_sys::last_sig_sent == -1);
  764. assert(p.get_state() == service_state_t::STOPPING);
  765. // Once the exec succeeds, then we should:
  766. base_process_service_test::exec_succeeded(&p);
  767. sset.process_queues();
  768. assert(bp_sys::last_sig_sent == SIGTERM);
  769. base_process_service_test::handle_exit(&p, 0);
  770. sset.process_queues();
  771. assert(p.get_state() == service_state_t::STOPPED);
  772. assert(event_loop.active_timers.size() == 0);
  773. sset.remove_service(&p);
  774. }
  775. // stop during smooth recovery (while waiting on restart timer)
  776. void test_proc_smooth_recovery6()
  777. {
  778. using namespace std;
  779. service_set sset;
  780. ha_string command = "test-command";
  781. list<pair<unsigned,unsigned>> command_offsets;
  782. command_offsets.emplace_back(0, command.length());
  783. std::list<prelim_dep> depends;
  784. process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  785. init_service_defaults(p);
  786. p.set_smooth_recovery(true);
  787. p.set_restart_delay(time_val {0, 1000});
  788. sset.add_service(&p);
  789. p.start();
  790. sset.process_queues();
  791. base_process_service_test::exec_succeeded(&p);
  792. sset.process_queues();
  793. pid_t first_instance = bp_sys::last_forked_pid;
  794. assert(p.get_state() == service_state_t::STARTED);
  795. base_process_service_test::handle_exit(&p, 0);
  796. sset.process_queues();
  797. // since time hasn't been changed, we expect that the process has not yet been re-launched:
  798. assert(first_instance == bp_sys::last_forked_pid);
  799. assert(p.get_state() == service_state_t::STARTED);
  800. bp_sys::last_sig_sent = -1;
  801. // Now issue a stop:
  802. p.stop(true);
  803. sset.process_queues();
  804. // since we were waiting on the restart timer, there should be no process signalled and the
  805. // state should now be stopped:
  806. assert(p.get_state() == service_state_t::STOPPED);
  807. assert(bp_sys::last_sig_sent == -1);
  808. assert(event_loop.active_timers.size() == 0);
  809. sset.remove_service(&p);
  810. }
  811. // simulate the launcher process forking a daemon process, and supply the process ID of that
  812. // daemon process in a pid file.
  813. static void supply_pid_contents(const char *pid_file, pid_t *daemon_instance_p = nullptr)
  814. {
  815. using namespace std;
  816. pid_t daemon_instance = ++bp_sys::last_forked_pid;
  817. // Set up the pid file content with the pid of the daemon
  818. stringstream str;
  819. str << daemon_instance << std::flush;
  820. string pid_file_content = str.str();
  821. vector<char> pid_file_content_v(pid_file_content.begin(), pid_file_content.end());
  822. bp_sys::supply_file_content(pid_file, std::move(pid_file_content_v));
  823. if (daemon_instance_p != nullptr) {
  824. *daemon_instance_p = daemon_instance;
  825. }
  826. }
  827. void test_bgproc_start()
  828. {
  829. using namespace std;
  830. service_set sset;
  831. ha_string command = "test-command";
  832. list<pair<unsigned,unsigned>> command_offsets;
  833. command_offsets.emplace_back(0, command.length());
  834. std::list<prelim_dep> depends;
  835. bgproc_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  836. init_service_defaults(p);
  837. p.set_pid_file("/run/daemon.pid");
  838. sset.add_service(&p);
  839. p.start();
  840. sset.process_queues();
  841. assert(p.get_state() == service_state_t::STARTING);
  842. base_process_service_test::exec_succeeded(&p);
  843. sset.process_queues();
  844. assert(p.get_state() == service_state_t::STARTING);
  845. supply_pid_contents("/run/daemon.pid");
  846. base_process_service_test::handle_exit(&p, 0);
  847. assert(p.get_state() == service_state_t::STARTED);
  848. assert(event_loop.active_timers.size() == 0);
  849. sset.remove_service(&p);
  850. }
  851. void test_bgproc_start_fail()
  852. {
  853. using namespace std;
  854. service_set sset;
  855. ha_string command = "test-command";
  856. list<pair<unsigned,unsigned>> command_offsets;
  857. command_offsets.emplace_back(0, command.length());
  858. std::list<prelim_dep> depends;
  859. bgproc_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  860. init_service_defaults(p);
  861. p.set_pid_file("/run/daemon.pid");
  862. sset.add_service(&p);
  863. p.start();
  864. sset.process_queues();
  865. assert(p.get_state() == service_state_t::STARTING);
  866. base_process_service_test::exec_succeeded(&p);
  867. sset.process_queues();
  868. assert(p.get_state() == service_state_t::STARTING);
  869. base_process_service_test::handle_exit(&p, 0x1); // fail status
  870. assert(p.get_state() == service_state_t::STOPPED);
  871. assert(event_loop.active_timers.size() == 0);
  872. sset.remove_service(&p);
  873. }
  874. void test_bgproc_start_fail_pid()
  875. {
  876. using namespace std;
  877. service_set sset;
  878. ha_string command = "test-command";
  879. list<pair<unsigned,unsigned>> command_offsets;
  880. command_offsets.emplace_back(0, command.length());
  881. std::list<prelim_dep> depends;
  882. bgproc_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  883. init_service_defaults(p);
  884. p.set_pid_file("/run/no-exist-daemon.pid");
  885. sset.add_service(&p);
  886. p.start();
  887. sset.process_queues();
  888. assert(p.get_state() == service_state_t::STARTING);
  889. base_process_service_test::exec_succeeded(&p);
  890. sset.process_queues();
  891. assert(p.get_state() == service_state_t::STARTING);
  892. // launcher returns success, but no pid file exists:
  893. base_process_service_test::handle_exit(&p, 0x0);
  894. assert(p.get_state() == service_state_t::STOPPED);
  895. assert(event_loop.active_timers.size() == 0);
  896. sset.remove_service(&p);
  897. }
  898. void test_bgproc_unexpected_term()
  899. {
  900. using namespace std;
  901. service_set sset;
  902. ha_string command = "test-command";
  903. list<pair<unsigned,unsigned>> command_offsets;
  904. command_offsets.emplace_back(0, command.length());
  905. std::list<prelim_dep> depends;
  906. bgproc_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  907. init_service_defaults(p);
  908. p.set_pid_file("/run/daemon.pid");
  909. sset.add_service(&p);
  910. service_record d1 {&sset, "test-service-2", service_type_t::INTERNAL, {{&p, REG}}};
  911. sset.add_service(&d1);
  912. d1.start();
  913. sset.process_queues();
  914. base_process_service_test::exec_succeeded(&p);
  915. assert(p.get_state() == service_state_t::STARTING);
  916. assert(d1.get_state() == service_state_t::STARTING);
  917. supply_pid_contents("/run/daemon.pid");
  918. base_process_service_test::handle_exit(&p, 0);
  919. assert(p.get_target_state() == service_state_t::STARTED);
  920. assert(p.get_state() == service_state_t::STARTED);
  921. assert(d1.get_target_state() == service_state_t::STARTED);
  922. assert(d1.get_state() == service_state_t::STARTED);
  923. // Now the backgrounded daemon itself terminates:
  924. base_process_service_test::handle_exit(&p, 0);
  925. assert(p.get_state() == service_state_t::STOPPED);
  926. assert(p.get_target_state() == service_state_t::STOPPED);
  927. assert(p.get_stop_reason() == stopped_reason_t::TERMINATED);
  928. assert(event_loop.active_timers.size() == 0);
  929. assert(d1.get_state() == service_state_t::STOPPED);
  930. assert(d1.get_target_state() == service_state_t::STOPPED);
  931. sset.remove_service(&d1);
  932. sset.remove_service(&p);
  933. }
  934. void test_bgproc_smooth_recover()
  935. {
  936. using namespace std;
  937. service_set sset;
  938. ha_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;
  942. bgproc_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  943. init_service_defaults(p);
  944. p.set_smooth_recovery(true);
  945. p.set_restart_delay(time_val {0, 1000});
  946. p.set_pid_file("/run/daemon.pid");
  947. sset.add_service(&p);
  948. p.start();
  949. sset.process_queues();
  950. base_process_service_test::exec_succeeded(&p);
  951. sset.process_queues();
  952. pid_t daemon_instance;
  953. supply_pid_contents("/run/daemon.pid", &daemon_instance);
  954. assert(p.get_state() == service_state_t::STARTING);
  955. base_process_service_test::handle_exit(&p, 0); // exit the launch process
  956. sset.process_queues();
  957. // daemon process has been started now, state should be STARTED
  958. assert(p.get_state() == service_state_t::STARTED);
  959. assert(daemon_instance == bp_sys::last_forked_pid);
  960. base_process_service_test::handle_exit(&p, 0); // exit the daemon process
  961. // since time hasn't been changed, we expect that the process has not yet been re-launched:
  962. assert(p.get_state() == service_state_t::STARTED);
  963. assert(daemon_instance == bp_sys::last_forked_pid);
  964. event_loop.advance_time(time_val {0, 1000});
  965. sset.process_queues();
  966. // Now a new process should've been launched:
  967. assert(daemon_instance + 1 == bp_sys::last_forked_pid);
  968. assert(p.get_state() == service_state_t::STARTED);
  969. assert(event_loop.active_timers.size() == 1); // start timer
  970. base_process_service_test::exec_succeeded(&p);
  971. sset.process_queues();
  972. assert(event_loop.active_timers.size() == 1);
  973. supply_pid_contents("/run/daemon.pid", &daemon_instance);
  974. base_process_service_test::handle_exit(&p, 0);
  975. sset.process_queues();
  976. assert(p.get_state() == service_state_t::STARTED);
  977. assert(event_loop.active_timers.size() == 0);
  978. // Now run through it again
  979. base_process_service_test::handle_exit(&p, 0); // exit the daemon process
  980. // since time hasn't been changed, we expect that the process has not yet been re-launched:
  981. assert(p.get_state() == service_state_t::STARTED);
  982. assert(p.get_pid() == -1);
  983. assert(daemon_instance == bp_sys::last_forked_pid);
  984. event_loop.advance_time(time_val {0, 1000});
  985. sset.process_queues();
  986. // Now a new process should've been launched:
  987. assert(daemon_instance + 1 == bp_sys::last_forked_pid);
  988. assert(p.get_state() == service_state_t::STARTED);
  989. assert(event_loop.active_timers.size() == 1);
  990. base_process_service_test::exec_succeeded(&p);
  991. sset.process_queues();
  992. assert(event_loop.active_timers.size() == 1);
  993. supply_pid_contents("/run/daemon.pid", &daemon_instance);
  994. base_process_service_test::handle_exit(&p, 0);
  995. sset.process_queues();
  996. assert(p.get_state() == service_state_t::STARTED);
  997. assert(p.get_pid() == daemon_instance);
  998. assert(event_loop.active_timers.size() == 0);
  999. sset.remove_service(&p);
  1000. }
  1001. // stop issued during smooth recovery, with dependent
  1002. void test_bgproc_smooth_recove2()
  1003. {
  1004. using namespace std;
  1005. service_set sset;
  1006. ha_string command = "test-command";
  1007. list<pair<unsigned,unsigned>> command_offsets;
  1008. command_offsets.emplace_back(0, command.length());
  1009. bgproc_service p {&sset, "testproc", ha_string(command), command_offsets, {}};
  1010. init_service_defaults(p);
  1011. p.set_smooth_recovery(true);
  1012. p.set_restart_delay(time_val {0, 1000});
  1013. p.set_pid_file("/run/daemon.pid");
  1014. sset.add_service(&p);
  1015. process_service d1 {&sset, "testproc-d1", std::move(command), command_offsets, {{&p, REG}}};
  1016. init_service_defaults(d1);
  1017. sset.add_service(&d1);
  1018. d1.start();
  1019. sset.process_queues();
  1020. // process for p exec succeds, reads pid file, starts
  1021. base_process_service_test::exec_succeeded(&p);
  1022. sset.process_queues();
  1023. pid_t daemon_instance;
  1024. supply_pid_contents("/run/daemon.pid", &daemon_instance);
  1025. assert(p.get_state() == service_state_t::STARTING);
  1026. base_process_service_test::handle_exit(&p, 0); // exit the launch process
  1027. sset.process_queues();
  1028. assert(p.get_state() == service_state_t::STARTED);
  1029. // dependent has been forked already:
  1030. assert(bp_sys::last_forked_pid == daemon_instance + 1);
  1031. // dependent then starts
  1032. base_process_service_test::exec_succeeded(&d1);
  1033. assert(bp_sys::last_forked_pid == daemon_instance + 1);
  1034. // exit daemon process unexpectedly:
  1035. base_process_service_test::handle_exit(&p, 0);
  1036. // since time hasn't been changed, we expect that the process has not yet been re-launched:
  1037. assert(p.get_state() == service_state_t::STARTED);
  1038. assert(bp_sys::last_forked_pid == daemon_instance + 1);
  1039. event_loop.advance_time(time_val {0, 1000});
  1040. // Now a new process should've been launched:
  1041. assert(bp_sys::last_forked_pid == daemon_instance + 2);
  1042. assert(p.get_state() == service_state_t::STARTED);
  1043. assert(event_loop.active_timers.size() == 1); // start timer
  1044. // We tell the service to stop, before the smooth recovery completes (in fact
  1045. // before the exec even succeeds):
  1046. p.stop(true);
  1047. sset.process_queues();
  1048. assert(p.get_state() == service_state_t::STOPPING);
  1049. assert(d1.get_state() == service_state_t::STOPPING);
  1050. // Now the bgprocess launcher completes but with a bogus pid file contents:
  1051. string pid_file_content_str = "";
  1052. vector<char> pid_file_content_v(pid_file_content_str.begin(), pid_file_content_str.end());
  1053. bp_sys::supply_file_content("/run/daemon.pid", std::move(pid_file_content_v));
  1054. base_process_service_test::exec_succeeded(&p);
  1055. base_process_service_test::handle_exit(&p, 0); // exit the launch process
  1056. assert(p.get_state() == service_state_t::STOPPING);
  1057. assert(d1.get_state() == service_state_t::STOPPING);
  1058. // Now the dependent stops:
  1059. base_process_service_test::handle_exit(&d1, 0);
  1060. assert(d1.get_state() == service_state_t::STOPPED);
  1061. assert(p.get_state() == service_state_t::STOPPED);
  1062. assert(event_loop.active_timers.size() == 0);
  1063. sset.remove_service(&p);
  1064. sset.remove_service(&d1);
  1065. }
  1066. // bgproc smooth recovery failure
  1067. void test_bgproc_smooth_recove3()
  1068. {
  1069. using namespace std;
  1070. service_set sset;
  1071. ha_string command = "test-command";
  1072. list<pair<unsigned,unsigned>> command_offsets;
  1073. command_offsets.emplace_back(0, command.length());
  1074. bgproc_service p {&sset, "testproc", ha_string(command), command_offsets, {}};
  1075. init_service_defaults(p);
  1076. p.set_smooth_recovery(true);
  1077. p.set_restart_delay(time_val {0, 1000});
  1078. p.set_pid_file("/run/daemon.pid");
  1079. sset.add_service(&p);
  1080. p.start();
  1081. sset.process_queues();
  1082. // process for p exec succeds, reads pid file, starts
  1083. base_process_service_test::exec_succeeded(&p);
  1084. sset.process_queues();
  1085. pid_t daemon_instance;
  1086. supply_pid_contents("/run/daemon.pid", &daemon_instance);
  1087. assert(p.get_state() == service_state_t::STARTING);
  1088. base_process_service_test::handle_exit(&p, 0); // exit the launch process
  1089. sset.process_queues();
  1090. assert(p.get_state() == service_state_t::STARTED);
  1091. // exit daemon process unexpectedly:
  1092. base_process_service_test::handle_exit(&p, 0);
  1093. // since time hasn't been changed, we expect that the process has not yet been re-launched:
  1094. assert(p.get_state() == service_state_t::STARTED);
  1095. assert(bp_sys::last_forked_pid == daemon_instance);
  1096. event_loop.advance_time(time_val {0, 1000});
  1097. // Now a new process should've been launched:
  1098. assert(bp_sys::last_forked_pid == daemon_instance + 1);
  1099. assert(p.get_state() == service_state_t::STARTED);
  1100. assert(event_loop.active_timers.size() == 1); // start timer
  1101. // Let the new process fail to executable:
  1102. base_process_service_test::exec_failed(&p, ENOMEM);
  1103. sset.process_queues();
  1104. assert(p.get_state() == service_state_t::STOPPED);
  1105. assert(p.get_stop_reason() == stopped_reason_t::TERMINATED);
  1106. assert(event_loop.active_timers.size() == 0);
  1107. sset.remove_service(&p);
  1108. }
  1109. // stop while in smooth recovery - waiting for restart timer
  1110. void test_bgproc_smooth_recove4()
  1111. {
  1112. using namespace std;
  1113. service_set sset;
  1114. ha_string command = "test-command";
  1115. list<pair<unsigned,unsigned>> command_offsets;
  1116. command_offsets.emplace_back(0, command.length());
  1117. bgproc_service p {&sset, "testproc", ha_string(command), command_offsets, {}};
  1118. init_service_defaults(p);
  1119. p.set_smooth_recovery(true);
  1120. p.set_restart_delay(time_val {0, 1000});
  1121. p.set_pid_file("/run/daemon.pid");
  1122. sset.add_service(&p);
  1123. p.start();
  1124. sset.process_queues();
  1125. // process for p exec succeds, reads pid file, starts
  1126. base_process_service_test::exec_succeeded(&p);
  1127. sset.process_queues();
  1128. pid_t daemon_instance;
  1129. supply_pid_contents("/run/daemon.pid", &daemon_instance);
  1130. assert(p.get_state() == service_state_t::STARTING);
  1131. base_process_service_test::handle_exit(&p, 0); // exit the launch process
  1132. sset.process_queues();
  1133. assert(p.get_state() == service_state_t::STARTED);
  1134. // exit daemon process unexpectedly:
  1135. base_process_service_test::handle_exit(&p, 0);
  1136. // since time hasn't been changed, we expect that the process has not yet been re-launched:
  1137. assert(p.get_state() == service_state_t::STARTED);
  1138. assert(bp_sys::last_forked_pid == daemon_instance);
  1139. // Now issue stop:
  1140. p.stop();
  1141. sset.process_queues();
  1142. // since process was not running, shouldn't need to wait for it to end:
  1143. assert(p.get_state() == service_state_t::STOPPED);
  1144. assert(event_loop.active_timers.size() == 0);
  1145. assert(bp_sys::last_forked_pid == daemon_instance);
  1146. // now start again:
  1147. p.start();
  1148. sset.process_queues();
  1149. supply_pid_contents("/run/daemon.pid", &daemon_instance);
  1150. assert(p.get_state() == service_state_t::STARTING);
  1151. base_process_service_test::exec_succeeded(&p);
  1152. base_process_service_test::handle_exit(&p, 0); // exit the launch process
  1153. sset.process_queues();
  1154. assert(p.get_state() == service_state_t::STARTED);
  1155. // and terminate:
  1156. p.stop();
  1157. sset.process_queues();
  1158. base_process_service_test::handle_exit(&p, 0);
  1159. sset.process_queues();
  1160. assert(p.get_state() == service_state_t::STOPPED);
  1161. sset.remove_service(&p);
  1162. }
  1163. // Unexpected termination with restart
  1164. void test_bgproc_term_restart()
  1165. {
  1166. using namespace std;
  1167. service_set sset;
  1168. ha_string command = "test-command";
  1169. list<pair<unsigned,unsigned>> command_offsets;
  1170. command_offsets.emplace_back(0, command.length());
  1171. std::list<prelim_dep> depends;
  1172. bgproc_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  1173. init_service_defaults(p);
  1174. p.set_auto_restart(true);
  1175. p.set_restart_delay(time_val {0, 1000});
  1176. p.set_pid_file("/run/daemon.pid");
  1177. sset.add_service(&p);
  1178. p.start();
  1179. sset.process_queues();
  1180. base_process_service_test::exec_succeeded(&p);
  1181. sset.process_queues();
  1182. assert(p.get_state() == service_state_t::STARTING);
  1183. pid_t daemon_instance;
  1184. supply_pid_contents("/run/daemon.pid", &daemon_instance);
  1185. // Launch process completes:
  1186. base_process_service_test::handle_exit(&p, 0); // exit the launch process
  1187. assert(p.get_state() == service_state_t::STARTED);
  1188. assert(p.get_pid() == daemon_instance);
  1189. // Unexpected termination of daemon:
  1190. base_process_service_test::handle_exit(&p, 1);
  1191. // Should re-start:
  1192. assert(p.get_state() == service_state_t::STARTING);
  1193. // Starting, restart timer should be armed:
  1194. assert(p.get_state() == service_state_t::STARTING);
  1195. assert(p.get_pid() == -1);
  1196. assert(event_loop.active_timers.size() == 1);
  1197. event_loop.advance_time(time_val(0, 1000));
  1198. assert(event_loop.active_timers.size() == 1); // start timer
  1199. assert(p.get_pid() != -1);
  1200. // Supply new pid
  1201. supply_pid_contents("/run/daemon.pid", &daemon_instance);
  1202. // Launch process completes again
  1203. base_process_service_test::handle_exit(&p, 0);
  1204. assert(p.get_state() == service_state_t::STARTED);
  1205. assert(p.get_pid() == daemon_instance);
  1206. assert(event_loop.active_timers.size() == 0);
  1207. sset.remove_service(&p);
  1208. }
  1209. void test_bgproc_stop()
  1210. {
  1211. using namespace std;
  1212. service_set sset;
  1213. ha_string command = "test-command";
  1214. list<pair<unsigned,unsigned>> command_offsets;
  1215. command_offsets.emplace_back(0, command.length());
  1216. std::list<prelim_dep> depends;
  1217. bgproc_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  1218. init_service_defaults(p);
  1219. p.set_auto_restart(true);
  1220. p.set_pid_file("/run/daemon.pid");
  1221. sset.add_service(&p);
  1222. p.start();
  1223. sset.process_queues();
  1224. base_process_service_test::exec_succeeded(&p);
  1225. sset.process_queues();
  1226. assert(p.get_state() == service_state_t::STARTING);
  1227. pid_t daemon_instance;
  1228. supply_pid_contents("/run/daemon.pid", &daemon_instance);
  1229. // Launch process completes:
  1230. base_process_service_test::handle_exit(&p, 0); // exit the launch process
  1231. assert(p.get_state() == service_state_t::STARTED);
  1232. assert(p.get_pid() == daemon_instance);
  1233. // Issue stop:
  1234. p.stop();
  1235. sset.process_queues();
  1236. assert(p.get_state() == service_state_t::STOPPING);
  1237. base_process_service_test::handle_exit(&p, 1);
  1238. assert(p.get_state() == service_state_t::STOPPED);
  1239. assert(event_loop.active_timers.size() == 0);
  1240. sset.remove_service(&p);
  1241. }
  1242. // If launch process completes successfully (exit code 0) after "stop" issued during startup,
  1243. // make sure the pid file is read and the daemon process is signalled.
  1244. void test_bgproc_stop2()
  1245. {
  1246. using namespace std;
  1247. service_set sset;
  1248. ha_string command = "test-command";
  1249. list<pair<unsigned,unsigned>> command_offsets;
  1250. command_offsets.emplace_back(0, command.length());
  1251. std::list<prelim_dep> depends;
  1252. bgproc_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  1253. init_service_defaults(p);
  1254. p.set_auto_restart(true);
  1255. p.set_pid_file("/run/daemon.pid");
  1256. sset.add_service(&p);
  1257. p.start();
  1258. sset.process_queues();
  1259. base_process_service_test::exec_succeeded(&p);
  1260. sset.process_queues();
  1261. assert(p.get_state() == service_state_t::STARTING);
  1262. pid_t daemon_instance;
  1263. supply_pid_contents("/run/daemon.pid", &daemon_instance);
  1264. // Now issue stop
  1265. p.stop();
  1266. // doesn't really matter if state is STARTING or STOPPING
  1267. assert(p.get_state() == service_state_t::STARTING || p.get_state() == service_state_t::STOPPING);
  1268. // Launch process completes:
  1269. bp_sys::last_sig_sent = -1;
  1270. base_process_service_test::handle_exit(&p, 0); // exit the launch process
  1271. // What should happen now: read the pid file, immediately signal the daemon, and go STOPPING
  1272. assert(p.get_pid() == daemon_instance);
  1273. assert(bp_sys::last_sig_sent == SIGTERM);
  1274. assert(p.get_state() == service_state_t::STOPPING);
  1275. // daemon exits:
  1276. base_process_service_test::handle_exit(&p, 1);
  1277. assert(p.get_state() == service_state_t::STOPPED);
  1278. assert(event_loop.active_timers.size() == 0);
  1279. sset.remove_service(&p);
  1280. }
  1281. // Stop issued during smooth recovery
  1282. void test_bgproc_stop3()
  1283. {
  1284. using namespace std;
  1285. service_set sset;
  1286. ha_string command = "test-command";
  1287. list<pair<unsigned,unsigned>> command_offsets;
  1288. command_offsets.emplace_back(0, command.length());
  1289. std::list<prelim_dep> depends;
  1290. bgproc_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  1291. init_service_defaults(p);
  1292. p.set_smooth_recovery(true);
  1293. p.set_restart_delay(time_val {0, 1000});
  1294. p.set_pid_file("/run/daemon.pid");
  1295. sset.add_service(&p);
  1296. p.start();
  1297. sset.process_queues();
  1298. base_process_service_test::exec_succeeded(&p);
  1299. sset.process_queues();
  1300. pid_t daemon_instance;
  1301. supply_pid_contents("/run/daemon.pid", &daemon_instance);
  1302. assert(p.get_state() == service_state_t::STARTING);
  1303. base_process_service_test::handle_exit(&p, 0); // exit the launch process
  1304. sset.process_queues();
  1305. // daemon process has been started now, state should be STARTED
  1306. assert(p.get_state() == service_state_t::STARTED);
  1307. assert(daemon_instance == bp_sys::last_forked_pid);
  1308. base_process_service_test::handle_exit(&p, 0); // exit the daemon process
  1309. // since time hasn't been changed, we expect that the process has not yet been re-launched:
  1310. assert(p.get_state() == service_state_t::STARTED);
  1311. assert(daemon_instance == bp_sys::last_forked_pid);
  1312. event_loop.advance_time(time_val {0, 1000});
  1313. sset.process_queues();
  1314. // Now a new process should've been launched:
  1315. assert(daemon_instance + 1 == bp_sys::last_forked_pid);
  1316. assert(p.get_state() == service_state_t::STARTED);
  1317. assert(event_loop.active_timers.size() == 1); // start timer
  1318. base_process_service_test::exec_succeeded(&p);
  1319. supply_pid_contents("/run/daemon.pid", &daemon_instance);
  1320. // Now, we are in smooth recovery (state = STARTED), launch process is running.
  1321. p.stop();
  1322. assert(p.get_state() == service_state_t::STOPPING);
  1323. assert(event_loop.active_timers.size() == 1);
  1324. base_process_service_test::handle_exit(&p, 0);
  1325. // The launch process terminated, but *successfully*. So the PID file should be read and the
  1326. // daemon process killed also.
  1327. assert(p.get_state() == service_state_t::STOPPING);
  1328. assert(p.get_pid() == daemon_instance);
  1329. base_process_service_test::handle_exit(&p, 0); // exit the daemon process
  1330. assert(p.get_state() == service_state_t::STOPPED);
  1331. assert(daemon_instance == bp_sys::last_forked_pid);
  1332. assert(event_loop.active_timers.size() == 0);
  1333. sset.remove_service(&p);
  1334. }
  1335. // stop issued via command (service with stop-command set)
  1336. void test_bgproc_stop4()
  1337. {
  1338. using namespace std;
  1339. service_set sset;
  1340. ha_string command = "test-command";
  1341. list<pair<unsigned,unsigned>> command_offsets;
  1342. command_offsets.emplace_back(0, command.length());
  1343. std::list<prelim_dep> depends;
  1344. ha_string stop_command = "stop-command";
  1345. list<pair<unsigned,unsigned>> stop_command_offsets;
  1346. stop_command_offsets.emplace_back(0, stop_command.length());
  1347. bgproc_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  1348. init_service_defaults(p);
  1349. p.set_smooth_recovery(true);
  1350. p.set_restart_delay(time_val {0, 1000});
  1351. p.set_pid_file("/run/daemon.pid");
  1352. sset.add_service(&p);
  1353. p.set_stop_command(stop_command, stop_command_offsets);
  1354. p.start();
  1355. sset.process_queues();
  1356. base_process_service_test::exec_succeeded(&p);
  1357. sset.process_queues();
  1358. pid_t daemon_instance;
  1359. supply_pid_contents("/run/daemon.pid", &daemon_instance);
  1360. assert(p.get_state() == service_state_t::STARTING);
  1361. base_process_service_test::handle_exit(&p, 0); // exit the launch process
  1362. sset.process_queues();
  1363. // daemon process has been started now, state should be STARTED
  1364. assert(p.get_state() == service_state_t::STARTED);
  1365. assert(daemon_instance == bp_sys::last_forked_pid);
  1366. // so stop:
  1367. p.stop();
  1368. sset.process_queues();
  1369. base_process_service_test::handle_stop_exit(&p, 0); // exit the daemon process
  1370. sset.process_queues();
  1371. assert(p.get_state() == service_state_t::STOPPING);
  1372. base_process_service_test::handle_exit(&p, 0);
  1373. sset.process_queues();
  1374. assert(p.get_state() == service_state_t::STOPPED);
  1375. assert(event_loop.active_timers.size() == 0);
  1376. sset.remove_service(&p);
  1377. }
  1378. // stop issued via command (service with stop-command set); service process dies before stop command
  1379. void test_bgproc_stop5()
  1380. {
  1381. using namespace std;
  1382. service_set sset;
  1383. ha_string command = "test-command";
  1384. list<pair<unsigned,unsigned>> command_offsets;
  1385. command_offsets.emplace_back(0, command.length());
  1386. std::list<prelim_dep> depends;
  1387. ha_string stop_command = "stop-command";
  1388. list<pair<unsigned,unsigned>> stop_command_offsets;
  1389. stop_command_offsets.emplace_back(0, stop_command.length());
  1390. bgproc_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  1391. init_service_defaults(p);
  1392. p.set_smooth_recovery(true);
  1393. p.set_restart_delay(time_val {0, 1000});
  1394. p.set_pid_file("/run/daemon.pid");
  1395. sset.add_service(&p);
  1396. p.set_stop_command(stop_command, stop_command_offsets);
  1397. p.start();
  1398. sset.process_queues();
  1399. base_process_service_test::exec_succeeded(&p);
  1400. sset.process_queues();
  1401. pid_t daemon_instance;
  1402. supply_pid_contents("/run/daemon.pid", &daemon_instance);
  1403. assert(p.get_state() == service_state_t::STARTING);
  1404. base_process_service_test::handle_exit(&p, 0); // exit the launch process
  1405. sset.process_queues();
  1406. // daemon process has been started now, state should be STARTED
  1407. assert(p.get_state() == service_state_t::STARTED);
  1408. assert(daemon_instance == bp_sys::last_forked_pid);
  1409. // so stop:
  1410. p.stop();
  1411. sset.process_queues();
  1412. assert(p.get_state() == service_state_t::STOPPING);
  1413. base_process_service_test::handle_exit(&p, 0);
  1414. sset.process_queues();
  1415. assert(p.get_state() == service_state_t::STOPPING);
  1416. base_process_service_test::handle_stop_exit(&p, 0); // exit the daemon process
  1417. sset.process_queues();
  1418. assert(p.get_state() == service_state_t::STOPPED);
  1419. assert(event_loop.active_timers.size() == 0);
  1420. sset.remove_service(&p);
  1421. }
  1422. // Test stop timeout
  1423. void test_scripted_stop_timeout()
  1424. {
  1425. using namespace std;
  1426. service_set sset;
  1427. ha_string command = "test-command";
  1428. ha_string stopcommand = "stop-command";
  1429. list<pair<unsigned,unsigned>> command_offsets;
  1430. command_offsets.emplace_back(0, command.length());
  1431. std::list<prelim_dep> depends;
  1432. scripted_service p {&sset, "testscripted", std::move(command), command_offsets, depends};
  1433. init_service_defaults(p);
  1434. p.set_stop_command(stopcommand, command_offsets);
  1435. p.set_stop_timeout(time_val {10, 0});
  1436. sset.add_service(&p);
  1437. p.start();
  1438. sset.process_queues();
  1439. assert(p.get_state() == service_state_t::STARTING);
  1440. base_process_service_test::exec_succeeded(&p);
  1441. sset.process_queues();
  1442. base_process_service_test::handle_exit(&p, 0);
  1443. sset.process_queues();
  1444. assert(p.get_state() == service_state_t::STARTED);
  1445. p.stop(true);
  1446. sset.process_queues();
  1447. assert(p.get_state() == service_state_t::STOPPING);
  1448. base_process_service_test::exec_succeeded(&p);
  1449. sset.process_queues();
  1450. // should still be stopping:
  1451. assert(p.get_state() == service_state_t::STOPPING);
  1452. event_loop.advance_time(time_val {10, 0}); // expire stop timer
  1453. sset.process_queues();
  1454. // kill signal (SIGKILL) should have been sent; process not dead until it's dead, however
  1455. assert(p.get_state() == service_state_t::STOPPING);
  1456. assert(bp_sys::last_sig_sent == SIGKILL);
  1457. base_process_service_test::handle_exit(&p, SIGKILL);
  1458. sset.process_queues();
  1459. assert(p.get_state() == service_state_t::STOPPED);
  1460. assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
  1461. assert(event_loop.active_timers.size() == 0);
  1462. sset.remove_service(&p);
  1463. }
  1464. void test_scripted_start_fail()
  1465. {
  1466. using namespace std;
  1467. service_set sset;
  1468. ha_string command = "test-command";
  1469. ha_string stopcommand = "stop-command";
  1470. list<pair<unsigned,unsigned>> command_offsets;
  1471. command_offsets.emplace_back(0, command.length());
  1472. std::list<prelim_dep> depends;
  1473. scripted_service p {&sset, "testscripted", std::move(command), command_offsets, depends};
  1474. init_service_defaults(p);
  1475. p.set_stop_command(stopcommand, command_offsets);
  1476. sset.add_service(&p);
  1477. service_record *s2 = new service_record(&sset, "test-service-2", service_type_t::INTERNAL, {{&p, REG}});
  1478. service_record *s3 = new service_record(&sset, "test-service-3",
  1479. service_type_t::INTERNAL, {{&p, REG}, {s2, REG}});
  1480. sset.add_service(s2);
  1481. sset.add_service(s3);
  1482. s3->start();
  1483. sset.process_queues();
  1484. assert(p.get_state() == service_state_t::STARTING);
  1485. base_process_service_test::exec_succeeded(&p);
  1486. sset.process_queues();
  1487. base_process_service_test::handle_exit(&p, 0x1); // exit fail
  1488. sset.process_queues();
  1489. // failed to start:
  1490. assert(p.get_state() == service_state_t::STOPPED);
  1491. assert(s2->get_state() == service_state_t::STOPPED);
  1492. assert(s3->get_state() == service_state_t::STOPPED);
  1493. assert(p.get_stop_reason() == stopped_reason_t::FAILED);
  1494. assert(s2->get_stop_reason() == stopped_reason_t::DEPFAILED);
  1495. assert(s3->get_stop_reason() == stopped_reason_t::DEPFAILED);
  1496. event_loop.active_timers.clear();
  1497. sset.remove_service(&p);
  1498. assert(sset.count_active_services() == 0);
  1499. }
  1500. void test_scripted_stop_fail()
  1501. {
  1502. using namespace std;
  1503. service_set sset;
  1504. ha_string command = "test-command";
  1505. ha_string stopcommand = "stop-command";
  1506. list<pair<unsigned,unsigned>> command_offsets;
  1507. command_offsets.emplace_back(0, command.length());
  1508. std::list<prelim_dep> depends;
  1509. scripted_service p {&sset, "testscripted", std::move(command), command_offsets, depends};
  1510. init_service_defaults(p);
  1511. p.set_stop_command(stopcommand, command_offsets);
  1512. sset.add_service(&p);
  1513. service_record *s2 = new service_record(&sset, "test-service-2", service_type_t::INTERNAL, {});
  1514. service_record *s3 = new service_record(&sset, "test-service-3", service_type_t::INTERNAL,
  1515. {{s2, REG}, {&p, REG}});
  1516. service_record *s4 = new service_record(&sset, "test-service-4", service_type_t::INTERNAL,
  1517. {{&p, REG}, {s3, REG}});
  1518. sset.add_service(s2);
  1519. sset.add_service(s3);
  1520. sset.add_service(s4);
  1521. s4->start();
  1522. sset.process_queues();
  1523. base_process_service_test::exec_succeeded(&p);
  1524. sset.process_queues();
  1525. base_process_service_test::handle_exit(&p, 0x0); // success
  1526. sset.process_queues();
  1527. assert(p.get_state() == service_state_t::STARTED);
  1528. assert(s2->get_state() == service_state_t::STARTED);
  1529. assert(s3->get_state() == service_state_t::STARTED);
  1530. assert(s4->get_state() == service_state_t::STARTED);
  1531. pid_t last_forked = bp_sys::last_forked_pid;
  1532. s4->stop(true);
  1533. sset.process_queues();
  1534. base_process_service_test::exec_succeeded(&p);
  1535. sset.process_queues();
  1536. base_process_service_test::handle_exit(&p, 0x1); // failure
  1537. sset.process_queues();
  1538. // The stop command should be executed once:
  1539. assert((bp_sys::last_forked_pid - last_forked) == 1);
  1540. assert(p.get_state() == service_state_t::STOPPED);
  1541. assert(s2->get_state() == service_state_t::STOPPED);
  1542. assert(s3->get_state() == service_state_t::STOPPED);
  1543. assert(s4->get_state() == service_state_t::STOPPED);
  1544. event_loop.active_timers.clear();
  1545. sset.remove_service(&p);
  1546. }
  1547. void test_scripted_start_skip()
  1548. {
  1549. using namespace std;
  1550. service_set sset;
  1551. ha_string command = "test-command";
  1552. list<pair<unsigned,unsigned>> command_offsets;
  1553. command_offsets.emplace_back(0, command.length());
  1554. std::list<prelim_dep> depends;
  1555. scripted_service p {&sset, "testscripted", std::move(command), command_offsets, depends};
  1556. init_service_defaults(p);
  1557. service_flags_t sflags;
  1558. sflags.skippable = true;
  1559. p.set_flags(sflags);
  1560. sset.add_service(&p);
  1561. service_record *s2 = new service_record(&sset, "test-service-2", service_type_t::INTERNAL, {{&p, REG}});
  1562. sset.add_service(s2);
  1563. s2->start();
  1564. sset.process_queues();
  1565. assert(p.get_state() == service_state_t::STARTING);
  1566. base_process_service_test::exec_succeeded(&p);
  1567. sset.process_queues();
  1568. assert(p.get_state() == service_state_t::STARTING);
  1569. base_process_service_test::handle_signal_exit(&p, SIGINT); // interrupted
  1570. sset.process_queues();
  1571. assert(p.get_state() == service_state_t::STARTED);
  1572. assert(s2->get_state() == service_state_t::STARTED);
  1573. assert(p.was_start_skipped());
  1574. assert(! s2->was_start_skipped());
  1575. assert(sset.count_active_services() == 2);
  1576. s2->stop(true);
  1577. sset.process_queues();
  1578. assert(p.get_state() == service_state_t::STOPPED);
  1579. assert(s2->get_state() == service_state_t::STOPPED);
  1580. assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
  1581. assert(s2->get_stop_reason() == stopped_reason_t::NORMAL);
  1582. assert(sset.count_active_services() == 0);
  1583. event_loop.active_timers.clear();
  1584. sset.remove_service(&p);
  1585. }
  1586. // Test interrupting start of a service marked skippable
  1587. void test_scripted_start_skip2()
  1588. {
  1589. using namespace std;
  1590. service_set sset;
  1591. ha_string command = "test-command";
  1592. list<pair<unsigned,unsigned>> command_offsets;
  1593. command_offsets.emplace_back(0, command.length());
  1594. std::list<prelim_dep> depends;
  1595. scripted_service p {&sset, "testscripted", std::move(command), command_offsets, depends};
  1596. init_service_defaults(p);
  1597. service_flags_t sflags;
  1598. sflags.skippable = true;
  1599. sflags.start_interruptible = true;
  1600. p.set_flags(sflags);
  1601. sset.add_service(&p);
  1602. service_record *s2 = new service_record(&sset, "test-service-2", service_type_t::INTERNAL, {{&p, REG}});
  1603. sset.add_service(s2);
  1604. s2->start();
  1605. sset.process_queues();
  1606. assert(p.get_state() == service_state_t::STARTING);
  1607. base_process_service_test::exec_succeeded(&p);
  1608. sset.process_queues();
  1609. assert(p.get_state() == service_state_t::STARTING);
  1610. s2->stop(true); // abort startup; p should be cancelled
  1611. sset.process_queues();
  1612. assert(p.get_state() == service_state_t::STOPPING);
  1613. base_process_service_test::handle_signal_exit(&p, SIGINT); // interrupted
  1614. sset.process_queues();
  1615. assert(p.get_state() == service_state_t::STOPPED);
  1616. assert(s2->get_state() == service_state_t::STOPPED);
  1617. assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
  1618. assert(s2->get_stop_reason() == stopped_reason_t::NORMAL);
  1619. assert(sset.count_active_services() == 0);
  1620. event_loop.active_timers.clear();
  1621. sset.remove_service(&p);
  1622. }
  1623. // Test that starting a service with a waits-for dependency on another - currently stopping - service,
  1624. // causes that service to re-start.
  1625. void test_waitsfor_restart()
  1626. {
  1627. using namespace std;
  1628. service_set sset;
  1629. ha_string command = "test-command";
  1630. list<pair<unsigned,unsigned>> command_offsets;
  1631. command_offsets.emplace_back(0, command.length());
  1632. std::list<prelim_dep> depends;
  1633. process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
  1634. init_service_defaults(p);
  1635. sset.add_service(&p);
  1636. service_record tp {&sset, "test-service", service_type_t::INTERNAL, {{&p, WAITS}}};
  1637. sset.add_service(&tp);
  1638. // start p:
  1639. p.start();
  1640. sset.process_queues();
  1641. assert(p.get_state() == service_state_t::STARTING);
  1642. base_process_service_test::exec_succeeded(&p);
  1643. sset.process_queues();
  1644. assert(p.get_state() == service_state_t::STARTED);
  1645. assert(event_loop.active_timers.size() == 0);
  1646. // begin stopping p:
  1647. p.stop(true);
  1648. sset.process_queues();
  1649. assert(p.get_state() == service_state_t::STOPPING);
  1650. // start tp (which waits-for p):
  1651. tp.start();
  1652. sset.process_queues();
  1653. assert(tp.get_state() == service_state_t::STARTING);
  1654. assert(p.get_state() == service_state_t::STOPPING);
  1655. // p terminates (finishes stopping). Then it should re-start...
  1656. base_process_service_test::handle_signal_exit(&p, SIGTERM);
  1657. sset.process_queues();
  1658. assert(tp.get_state() == service_state_t::STARTING);
  1659. assert(p.get_state() == service_state_t::STARTING);
  1660. base_process_service_test::exec_succeeded(&p);
  1661. sset.process_queues();
  1662. assert(tp.get_state() == service_state_t::STARTED);
  1663. assert(p.get_state() == service_state_t::STARTED);
  1664. sset.remove_service(&tp);
  1665. sset.remove_service(&p);
  1666. }
  1667. #define RUN_TEST(name, spacing) \
  1668. std::cout << #name "..." spacing << std::flush; \
  1669. name(); \
  1670. std::cout << "PASSED" << std::endl;
  1671. int main(int argc, char **argv)
  1672. {
  1673. RUN_TEST(test_proc_service_start, " ");
  1674. RUN_TEST(test_proc_notify_start, " ");
  1675. RUN_TEST(test_proc_unexpected_term, " ");
  1676. RUN_TEST(test_proc_term_start, " ");
  1677. RUN_TEST(test_proc_term_restart, " ");
  1678. RUN_TEST(test_proc_term_restart2, " ");
  1679. RUN_TEST(test_proc_term_restart3, " ");
  1680. RUN_TEST(test_proc_term_restart4, " ");
  1681. RUN_TEST(test_term_via_stop, " ");
  1682. RUN_TEST(test_term_via_stop2, " ");
  1683. RUN_TEST(test_term_via_stop3, " ");
  1684. RUN_TEST(test_proc_start_timeout, " ");
  1685. RUN_TEST(test_proc_start_timeout2, " ");
  1686. RUN_TEST(test_proc_start_execfail, " ");
  1687. RUN_TEST(test_proc_notify_fail, " ");
  1688. RUN_TEST(test_proc_stop_timeout, " ");
  1689. RUN_TEST(test_proc_smooth_recovery1, " ");
  1690. RUN_TEST(test_proc_smooth_recovery2, " ");
  1691. RUN_TEST(test_proc_smooth_recovery3, " ");
  1692. RUN_TEST(test_proc_smooth_recovery4, " ");
  1693. RUN_TEST(test_proc_smooth_recovery5, " ");
  1694. RUN_TEST(test_proc_smooth_recovery6, " ");
  1695. RUN_TEST(test_bgproc_start, " ");
  1696. RUN_TEST(test_bgproc_start_fail, " ");
  1697. RUN_TEST(test_bgproc_start_fail_pid, " ");
  1698. RUN_TEST(test_bgproc_unexpected_term, "");
  1699. RUN_TEST(test_bgproc_smooth_recover, " ");
  1700. RUN_TEST(test_bgproc_smooth_recove2, " ");
  1701. RUN_TEST(test_bgproc_smooth_recove3, " ");
  1702. RUN_TEST(test_bgproc_smooth_recove4, " ");
  1703. RUN_TEST(test_bgproc_term_restart, " ");
  1704. RUN_TEST(test_bgproc_stop, " ");
  1705. RUN_TEST(test_bgproc_stop2, " ");
  1706. RUN_TEST(test_bgproc_stop3, " ");
  1707. RUN_TEST(test_bgproc_stop4, " ");
  1708. RUN_TEST(test_bgproc_stop5, " ");
  1709. RUN_TEST(test_scripted_stop_timeout, " ");
  1710. RUN_TEST(test_scripted_start_fail, " ");
  1711. RUN_TEST(test_scripted_stop_fail, " ");
  1712. RUN_TEST(test_scripted_start_skip, " ");
  1713. RUN_TEST(test_scripted_start_skip2, " ");
  1714. RUN_TEST(test_waitsfor_restart, " ");
  1715. }