019-link-unlink.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543
  1. //
  2. // Copyright (c) 2019-2020 Ivan Baidakou (basiliscos) (the dot dmol at gmail dot com)
  3. //
  4. // Distributed under the MIT Software License
  5. //
  6. #include "catch.hpp"
  7. #include "rotor.hpp"
  8. #include "actor_test.h"
  9. #include "supervisor_test.h"
  10. #include "system_context_test.h"
  11. #include "access.h"
  12. namespace r = rotor;
  13. namespace rt = r::test;
  14. struct double_linked_actor_t : r::actor_base_t {
  15. using r::actor_base_t::actor_base_t;
  16. using message_ptr_t = r::intrusive_ptr_t<r::message::link_response_t>;
  17. struct resource {
  18. static const constexpr r::plugin::resource_id_t linking = 0;
  19. static const constexpr r::plugin::resource_id_t unlinking = 1;
  20. };
  21. void configure(r::plugin::plugin_base_t &plugin) noexcept override {
  22. plugin.with_casted<r::plugin::address_maker_plugin_t>([&](auto &p) { alternative = p.create_address(); });
  23. plugin.with_casted<r::plugin::starter_plugin_t>([&](auto &p) {
  24. p.subscribe_actor(&double_linked_actor_t::on_link, alternative);
  25. p.subscribe_actor(&double_linked_actor_t::on_unlink, alternative);
  26. for (auto i = 0; i < 2; ++i) {
  27. resources->acquire(resource::linking);
  28. request_via<r::payload::link_request_t>(target, alternative, false).send(rt::default_timeout);
  29. }
  30. });
  31. }
  32. void on_link(r::message::link_response_t &res) noexcept {
  33. resources->release(resource::linking);
  34. if (!message1)
  35. message1 = &res;
  36. else if (!message2)
  37. message2 = &res;
  38. }
  39. virtual void on_start() noexcept override {
  40. r::actor_base_t::on_start();
  41. resources->acquire(resource::unlinking);
  42. }
  43. void on_unlink(r::message::unlink_request_t &message) noexcept {
  44. reply_to(message, alternative);
  45. if (resources->has(resource::unlinking))
  46. resources->release(resource::unlinking);
  47. }
  48. r::address_ptr_t target;
  49. message_ptr_t message1, message2;
  50. r::address_ptr_t alternative;
  51. };
  52. struct tracked_actor_t : rt::actor_test_t {
  53. using rt::actor_test_t::actor_test_t;
  54. std::uint32_t shutdown_event = 0;
  55. };
  56. TEST_CASE("client/server, common workflow", "[actor]") {
  57. r::system_context_t system_context;
  58. auto sup = system_context.create_supervisor<rt::supervisor_test_t>().timeout(rt::default_timeout).finish();
  59. auto act_s = sup->create_actor<rt::actor_test_t>().timeout(rt::default_timeout).finish();
  60. auto act_c = sup->create_actor<rt::actor_test_t>().timeout(rt::default_timeout).finish();
  61. auto &addr_s = act_s->get_address();
  62. bool invoked = false;
  63. act_c->configurer = [&](auto &, r::plugin::plugin_base_t &plugin) {
  64. plugin.with_casted<r::plugin::link_client_plugin_t>([&](auto &p) {
  65. p.link(addr_s, false, [&](auto &ec) mutable {
  66. REQUIRE(ec.category().name() == std::string("rotor_error"));
  67. REQUIRE(ec.message() == std::string("success"));
  68. invoked = true;
  69. });
  70. });
  71. };
  72. sup->do_process();
  73. REQUIRE(sup->get_state() == r::state_t::OPERATIONAL);
  74. REQUIRE(invoked);
  75. SECTION("simultaneous shutdown") {
  76. sup->do_shutdown();
  77. sup->do_process();
  78. }
  79. SECTION("controlled shutdown") {
  80. SECTION("indirect client-initiated unlink via client-shutdown") {
  81. act_c->do_shutdown();
  82. sup->do_process();
  83. CHECK(act_c->get_state() == r::state_t::SHUT_DOWN);
  84. }
  85. SECTION("indirect client-initiated unlink via server-shutdown") {
  86. act_s->do_shutdown();
  87. sup->do_process();
  88. CHECK(act_s->get_state() == r::state_t::SHUT_DOWN);
  89. CHECK(act_c->get_state() == r::state_t::SHUT_DOWN);
  90. }
  91. sup->do_shutdown();
  92. sup->do_process();
  93. }
  94. }
  95. TEST_CASE("link not possible (timeout) => shutdown", "[actor]") {
  96. r::system_context_t system_context;
  97. auto sup = system_context.create_supervisor<rt::supervisor_test_t>().timeout(rt::default_timeout).finish();
  98. auto act_c = sup->create_actor<rt::actor_test_t>().timeout(rt::default_timeout).finish();
  99. auto some_addr = sup->make_address();
  100. bool invoked = false;
  101. act_c->configurer = [&](auto &, r::plugin::plugin_base_t &plugin) {
  102. plugin.with_casted<r::plugin::link_client_plugin_t>([&](auto &p) {
  103. p.link(some_addr, false, [&](auto &ec) mutable {
  104. REQUIRE(ec);
  105. invoked = true;
  106. });
  107. });
  108. };
  109. sup->do_process();
  110. REQUIRE(sup->get_state() == r::state_t::INITIALIZING);
  111. REQUIRE(sup->active_timers.size() == 3);
  112. auto timer_it = *(sup->active_timers.rbegin());
  113. sup->do_invoke_timer(timer_it->request_id);
  114. sup->do_process();
  115. REQUIRE(invoked);
  116. REQUIRE(sup->get_state() == r::state_t::SHUT_DOWN);
  117. }
  118. #if 0
  119. TEST_CASE("link not possible => supervisor is shutted down", "[actor]") {
  120. r::system_context_t system_context;
  121. auto sup = system_context.create_supervisor<rt::supervisor_test_t>().timeout(rt::default_timeout).finish();
  122. auto act_s = sup->create_actor<rt::actor_test_t>().timeout(rt::default_timeout).finish();
  123. auto act_c = sup->create_actor<rt::actor_test_t>().timeout(rt::default_timeout).finish();
  124. auto server_addr = act_s->get_address();
  125. act_c->link_request(server_addr, rt::default_timeout);
  126. sup->do_process();
  127. REQUIRE(act_c->get_state() == r::state_t::SHUT_DOWN);
  128. REQUIRE(act_s->get_state() == r::state_t::SHUT_DOWN);
  129. REQUIRE(sup->get_state() == r::state_t::SHUT_DOWN);
  130. }
  131. #endif
  132. TEST_CASE("unlink", "[actor]") {
  133. rt::system_context_test_t system_context;
  134. const char l1[] = "abc";
  135. const char l2[] = "def";
  136. auto sup1 =
  137. system_context.create_supervisor<rt::supervisor_test_t>().timeout(rt::default_timeout).locality(l1).finish();
  138. auto sup2 = sup1->create_actor<rt::supervisor_test_t>().timeout(rt::default_timeout).locality(l2).finish();
  139. auto act_s = sup1->create_actor<rt::actor_test_t>().timeout(rt::default_timeout).finish();
  140. auto act_c = sup2->create_actor<rt::actor_test_t>().timeout(rt::default_timeout).finish();
  141. auto &addr_s = act_s->get_address();
  142. act_c->configurer = [&](auto &, r::plugin::plugin_base_t &plugin) {
  143. plugin.with_casted<r::plugin::link_client_plugin_t>([&](auto &p) { p.link(addr_s, false, [&](auto &) {}); });
  144. };
  145. while (!sup1->get_leader_queue().empty() || !sup2->get_leader_queue().empty()) {
  146. sup1->do_process();
  147. sup2->do_process();
  148. }
  149. REQUIRE(sup1->get_state() == r::state_t::OPERATIONAL);
  150. SECTION("unlink failure") {
  151. act_s->do_shutdown();
  152. sup1->do_process();
  153. REQUIRE(sup1->active_timers.size() == 2);
  154. auto unlink_req = sup1->get_timer(1);
  155. sup1->do_invoke_timer(unlink_req);
  156. sup1->do_process();
  157. REQUIRE(system_context.ec == r::error_code_t::request_timeout);
  158. REQUIRE(act_s->get_state() == r::state_t::SHUTTING_DOWN);
  159. act_s->force_cleanup();
  160. }
  161. SECTION("unlink-notify on unlink-request") {
  162. SECTION("client, then server") {
  163. act_s->do_shutdown();
  164. act_c->do_shutdown();
  165. sup2->do_process();
  166. sup1->do_process();
  167. sup2->do_process();
  168. sup1->do_process();
  169. }
  170. SECTION("server, then client") {
  171. act_s->do_shutdown();
  172. act_c->do_shutdown();
  173. sup1->do_process();
  174. sup2->do_process();
  175. sup1->do_process();
  176. sup2->do_process();
  177. }
  178. }
  179. sup1->do_shutdown();
  180. while (!sup1->get_leader_queue().empty() || !sup2->get_leader_queue().empty()) {
  181. sup1->do_process();
  182. sup2->do_process();
  183. }
  184. REQUIRE(sup1->get_state() == r::state_t::SHUT_DOWN);
  185. }
  186. TEST_CASE("unlink reaction", "[actor]") {
  187. using request_ptr_t = r::intrusive_ptr_t<r::message::unlink_request_t>;
  188. rt::system_context_test_t system_context;
  189. auto sup = system_context.create_supervisor<rt::supervisor_test_t>().timeout(rt::default_timeout).finish();
  190. auto act_s = sup->create_actor<rt::actor_test_t>().timeout(rt::default_timeout).finish();
  191. auto act_c = sup->create_actor<rt::actor_test_t>().timeout(rt::default_timeout).finish();
  192. auto &addr_s = act_s->get_address();
  193. request_ptr_t unlink_req;
  194. act_c->configurer = [&](auto &, r::plugin::plugin_base_t &plugin) {
  195. plugin.with_casted<r::plugin::link_client_plugin_t>([&](auto &p) {
  196. p.link(addr_s, false, [&](auto &) {});
  197. p.on_unlink([&](auto &req) {
  198. unlink_req = &req;
  199. p.forget_link(req);
  200. return true;
  201. });
  202. });
  203. };
  204. sup->do_process();
  205. act_s->do_shutdown();
  206. sup->do_process();
  207. REQUIRE(unlink_req);
  208. REQUIRE(unlink_req->message_type == r::message::unlink_request_t::message_type);
  209. sup->do_shutdown();
  210. sup->do_process();
  211. REQUIRE(sup->get_state() == r::state_t::SHUT_DOWN);
  212. }
  213. TEST_CASE("auto-unlink on shutdown", "[actor]") {
  214. rt::system_context_test_t ctx1;
  215. rt::system_context_test_t ctx2;
  216. const char l1[] = "abc";
  217. const char l2[] = "def";
  218. auto sup1 = ctx1.create_supervisor<rt::supervisor_test_t>().timeout(rt::default_timeout).locality(l1).finish();
  219. auto sup2 = ctx2.create_supervisor<rt::supervisor_test_t>().timeout(rt::default_timeout).locality(l2).finish();
  220. auto act_c = sup1->create_actor<rt::actor_test_t>().timeout(rt::default_timeout).finish();
  221. auto act_s = sup2->create_actor<rt::actor_test_t>().timeout(rt::default_timeout).finish();
  222. auto &addr_s = act_s->get_address();
  223. act_c->configurer = [&](auto &, r::plugin::plugin_base_t &plugin) {
  224. plugin.with_casted<r::plugin::link_client_plugin_t>([&](auto &p) { p.link(addr_s, false, [&](auto &) {}); });
  225. };
  226. sup1->do_process();
  227. REQUIRE(act_c->get_state() == r::state_t::INITIALIZING);
  228. act_c->do_shutdown();
  229. sup1->do_process();
  230. REQUIRE(act_c->get_state() == r::state_t::SHUT_DOWN);
  231. REQUIRE(sup1->get_state() == r::state_t::SHUT_DOWN);
  232. sup2->do_process();
  233. REQUIRE(sup2->get_state() == r::state_t::OPERATIONAL);
  234. sup2->do_shutdown();
  235. sup2->do_process();
  236. REQUIRE(sup2->get_state() == r::state_t::SHUT_DOWN);
  237. }
  238. TEST_CASE("link to operational only", "[actor]") {
  239. rt::system_context_test_t ctx1;
  240. rt::system_context_test_t ctx2;
  241. rt::system_context_test_t ctx3;
  242. const char l1[] = "abc";
  243. const char l2[] = "def";
  244. const char l3[] = "ghi";
  245. auto sup1 = ctx1.create_supervisor<rt::supervisor_test_t>().timeout(rt::default_timeout).locality(l1).finish();
  246. auto sup2 = ctx2.create_supervisor<rt::supervisor_test_t>().timeout(rt::default_timeout).locality(l2).finish();
  247. auto sup3 = ctx3.create_supervisor<rt::supervisor_test_t>().timeout(rt::default_timeout).locality(l3).finish();
  248. auto act_c = sup1->create_actor<rt::actor_test_t>().timeout(rt::default_timeout).finish();
  249. auto act_s1 = sup2->create_actor<rt::actor_test_t>().timeout(rt::default_timeout).finish();
  250. auto act_s2 = sup3->create_actor<rt::actor_test_t>().timeout(rt::default_timeout).finish();
  251. auto &addr_s1 = act_s1->get_address();
  252. auto &addr_s2 = act_s2->get_address();
  253. auto process_12 = [&]() {
  254. while (!sup1->get_leader_queue().empty() || !sup2->get_leader_queue().empty()) {
  255. sup1->do_process();
  256. sup2->do_process();
  257. }
  258. };
  259. auto process_123 = [&]() {
  260. while (!sup1->get_leader_queue().empty() || !sup2->get_leader_queue().empty() ||
  261. !sup3->get_leader_queue().empty()) {
  262. sup1->do_process();
  263. sup2->do_process();
  264. sup3->do_process();
  265. }
  266. };
  267. act_c->configurer = [&](auto &, r::plugin::plugin_base_t &plugin) {
  268. plugin.with_casted<r::plugin::link_client_plugin_t>([&](auto &p) { p.link(addr_s1, true, [&](auto &) {}); });
  269. };
  270. act_s1->configurer = [&](auto &, r::plugin::plugin_base_t &plugin) {
  271. plugin.with_casted<r::plugin::link_client_plugin_t>([&](auto &p) { p.link(addr_s2, true, [&](auto &) {}); });
  272. };
  273. process_12();
  274. CHECK(act_c->get_state() == r::state_t::INITIALIZING);
  275. CHECK(act_s1->get_state() == r::state_t::INITIALIZING);
  276. process_123();
  277. CHECK(act_c->get_state() == r::state_t::OPERATIONAL);
  278. CHECK(act_s1->get_state() == r::state_t::OPERATIONAL);
  279. CHECK(act_s2->get_state() == r::state_t::OPERATIONAL);
  280. sup1->do_shutdown();
  281. sup2->do_shutdown();
  282. sup3->do_shutdown();
  283. process_123();
  284. CHECK(act_c->get_state() == r::state_t::SHUT_DOWN);
  285. CHECK(act_s1->get_state() == r::state_t::SHUT_DOWN);
  286. CHECK(act_s2->get_state() == r::state_t::SHUT_DOWN);
  287. }
  288. TEST_CASE("unlink notify / response race", "[actor]") {
  289. rt::system_context_test_t system_context;
  290. const char l1[] = "abc";
  291. const char l2[] = "def";
  292. auto sup1 =
  293. system_context.create_supervisor<rt::supervisor_test_t>().timeout(rt::default_timeout).locality(l1).finish();
  294. auto sup2 = sup1->create_actor<rt::supervisor_test_t>().timeout(rt::default_timeout).locality(l2).finish();
  295. auto act_s = sup1->create_actor<rt::actor_test_t>().timeout(rt::default_timeout).finish();
  296. auto act_c = sup2->create_actor<rt::actor_test_t>().timeout(rt::default_timeout).finish();
  297. auto &addr_s = act_s->get_address();
  298. act_c->configurer = [&](auto &, r::plugin::plugin_base_t &plugin) {
  299. plugin.with_casted<r::plugin::link_client_plugin_t>([&](auto &p) { p.link(addr_s, true, [&](auto &) {}); });
  300. };
  301. while (!sup1->get_leader_queue().empty() || !sup2->get_leader_queue().empty()) {
  302. sup1->do_process();
  303. sup2->do_process();
  304. }
  305. REQUIRE(sup1->get_state() == r::state_t::OPERATIONAL);
  306. act_s->do_shutdown();
  307. act_c->do_shutdown();
  308. sup1->do_process();
  309. // extract unlink request to let it produce unlink notify
  310. auto unlink_request = sup2->get_leader_queue().back();
  311. REQUIRE(unlink_request->type_index == r::message::unlink_request_t::message_type);
  312. sup2->get_leader_queue().pop_back();
  313. sup2->do_process();
  314. sup1->do_shutdown();
  315. while (!sup1->get_leader_queue().empty() || !sup2->get_leader_queue().empty()) {
  316. sup1->do_process();
  317. sup2->do_process();
  318. }
  319. CHECK(sup1->active_timers.size() == 0);
  320. CHECK(sup1->get_state() == r::state_t::SHUT_DOWN);
  321. }
  322. TEST_CASE("link errors", "[actor]") {
  323. rt::system_context_test_t ctx1;
  324. rt::system_context_test_t ctx2;
  325. const char l1[] = "abc";
  326. const char l2[] = "def";
  327. auto sup1 = ctx1.create_supervisor<rt::supervisor_test_t>().timeout(rt::default_timeout).locality(l1).finish();
  328. auto sup2 = ctx2.create_supervisor<rt::supervisor_test_t>().timeout(rt::default_timeout).locality(l2).finish();
  329. auto process_12 = [&]() {
  330. while (!sup1->get_leader_queue().empty() || !sup2->get_leader_queue().empty()) {
  331. sup1->do_process();
  332. sup2->do_process();
  333. }
  334. };
  335. SECTION("double link attempt") {
  336. auto act_c = sup1->create_actor<double_linked_actor_t>().timeout(rt::default_timeout).finish();
  337. auto act_s = sup2->create_actor<rt::actor_test_t>().timeout(rt::default_timeout).finish();
  338. act_c->target = act_s->get_address();
  339. process_12();
  340. REQUIRE(act_c->message1);
  341. CHECK(!act_c->message1->payload.ec);
  342. REQUIRE(act_c->message2);
  343. CHECK(act_c->message2->payload.ec);
  344. CHECK(act_c->message2->payload.ec.message() == std::string("already linked"));
  345. }
  346. SECTION("not linkeable") {
  347. auto act_s = sup2->create_actor<rt::actor_test_t>().timeout(rt::default_timeout).finish();
  348. sup2->do_process();
  349. act_s->access<rt::to::resources>()->acquire();
  350. act_s->do_shutdown();
  351. sup2->do_process();
  352. REQUIRE(act_s->get_state() == r::state_t::SHUTTING_DOWN);
  353. SECTION("check error") {
  354. std::error_code err;
  355. auto act_c = sup1->create_actor<rt::actor_test_t>().timeout(rt::default_timeout).finish();
  356. act_c->configurer = [&](auto &, r::plugin::plugin_base_t &plugin) {
  357. plugin.with_casted<r::plugin::link_client_plugin_t>(
  358. [&](auto &p) { p.link(act_s->get_address(), false, [&](auto &ec) { err = ec; }); });
  359. };
  360. process_12();
  361. CHECK(act_c->get_state() == r::state_t::SHUT_DOWN);
  362. CHECK(err.message() == std::string("actor is not linkeable"));
  363. }
  364. SECTION("get the error during shutdown") {
  365. auto act_c = sup1->create_actor<rt::actor_test_t>().timeout(rt::default_timeout).finish();
  366. sup1->do_process();
  367. CHECK(act_c->get_state() == r::state_t::OPERATIONAL);
  368. auto plugin1 = act_c->access<rt::to::get_plugin>(r::plugin::link_client_plugin_t::class_identity);
  369. auto p1 = static_cast<r::plugin::link_client_plugin_t *>(plugin1);
  370. p1->link(act_s->get_address(), false, [&](auto &) {});
  371. act_c->access<rt::to::resources>()->acquire();
  372. act_c->do_shutdown();
  373. process_12();
  374. CHECK(act_c->get_state() == r::state_t::SHUTTING_DOWN);
  375. act_c->access<rt::to::resources>()->release();
  376. }
  377. act_s->access<rt::to::resources>()->release();
  378. }
  379. SECTION("unlink during shutring down") {
  380. auto act_c = sup1->create_actor<rt::actor_test_t>().timeout(rt::default_timeout).finish();
  381. auto act_s = sup2->create_actor<rt::actor_test_t>().timeout(rt::default_timeout).finish();
  382. act_c->configurer = [&](auto &, r::plugin::plugin_base_t &plugin) {
  383. plugin.with_casted<r::plugin::link_client_plugin_t>(
  384. [&](auto &p) { p.link(act_s->get_address(), false, [&](auto &) {}); });
  385. };
  386. process_12();
  387. CHECK(sup1->get_state() == r::state_t::OPERATIONAL);
  388. CHECK(sup2->get_state() == r::state_t::OPERATIONAL);
  389. act_c->do_shutdown();
  390. act_c->access<rt::to::resources>()->acquire();
  391. sup1->do_process();
  392. CHECK(act_c->get_state() == r::state_t::SHUTTING_DOWN);
  393. act_s->do_shutdown();
  394. sup2->do_process();
  395. sup1->do_process();
  396. CHECK(act_c->get_state() == r::state_t::SHUTTING_DOWN);
  397. act_c->access<rt::to::resources>()->release();
  398. process_12();
  399. }
  400. sup1->do_shutdown();
  401. sup2->do_shutdown();
  402. process_12();
  403. CHECK(sup1->get_state() == r::state_t::SHUT_DOWN);
  404. CHECK(sup2->get_state() == r::state_t::SHUT_DOWN);
  405. }
  406. TEST_CASE("proper shutdown order, defined by linkage", "[actor]") {
  407. r::system_context_t system_context;
  408. auto sup = system_context.create_supervisor<rt::supervisor_test_t>().timeout(rt::default_timeout).finish();
  409. auto act_1 = sup->create_actor<tracked_actor_t>().timeout(rt::default_timeout).finish();
  410. auto act_2 = sup->create_actor<tracked_actor_t>().timeout(rt::default_timeout).finish();
  411. auto act_3 = sup->create_actor<tracked_actor_t>().timeout(rt::default_timeout).finish();
  412. /*
  413. printf("a1 = %p(%p), a2 = %p(%p), a3 = %p(%p)\n", act_1.get(), act_1->get_address().get(),
  414. act_2.get(), act_2->get_address().get(), act_3.get(), act_3->get_address().get());
  415. */
  416. std::uint32_t event_id = 1;
  417. auto shutdowner = [&](auto &me) {
  418. auto &self = static_cast<tracked_actor_t &>(me);
  419. self.shutdown_event = event_id++;
  420. };
  421. act_1->shutdowner = act_2->shutdowner = act_3->shutdowner = shutdowner;
  422. act_1->configurer = [&](auto &, r::plugin::plugin_base_t &plugin) {
  423. plugin.with_casted<r::plugin::link_client_plugin_t>([&](auto &p) {
  424. p.link(act_2->get_address(), false);
  425. p.link(act_3->get_address(), false);
  426. });
  427. };
  428. act_2->configurer = [&](auto &, r::plugin::plugin_base_t &plugin) {
  429. plugin.with_casted<r::plugin::link_client_plugin_t>([&](auto &p) { p.link(act_3->get_address(), false); });
  430. };
  431. sup->do_process();
  432. REQUIRE(sup->get_state() == r::state_t::OPERATIONAL);
  433. sup->do_shutdown();
  434. sup->do_process();
  435. REQUIRE(sup->get_state() == r::state_t::SHUT_DOWN);
  436. CHECK(act_1->shutdown_event == 1);
  437. CHECK(act_2->shutdown_event == 2);
  438. CHECK(act_3->shutdown_event == 3);
  439. }