022-supervisor-tree.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. //
  2. // Copyright (c) 2019-2021 Ivan Baidakou (basiliscos) (the dot dmol at gmail dot com)
  3. //
  4. // Distributed under the MIT Software License
  5. //
  6. #include "rotor.hpp"
  7. #include "supervisor_test.h"
  8. #include "access.h"
  9. namespace r = rotor;
  10. namespace rt = r::test;
  11. static std::uint32_t ping_received = 0;
  12. static std::uint32_t ping_sent = 0;
  13. struct ping_t {};
  14. struct pinger_t : public r::actor_base_t {
  15. using r::actor_base_t::actor_base_t;
  16. void set_ponger_addr(const r::address_ptr_t &addr) { ponger_addr = addr; }
  17. void configure(r::plugin::plugin_base_t &plugin) noexcept override {
  18. plugin.with_casted<rotor::plugin::registry_plugin_t>(
  19. [&](auto &p) { p.discover_name("ponger", ponger_addr, true).link(true); });
  20. }
  21. void on_start() noexcept override {
  22. r::actor_base_t::on_start();
  23. send<ping_t>(ponger_addr);
  24. ping_sent++;
  25. }
  26. r::address_ptr_t ponger_addr;
  27. };
  28. struct ponger_t : public r::actor_base_t {
  29. using r::actor_base_t::actor_base_t;
  30. void configure(r::plugin::plugin_base_t &plugin) noexcept override {
  31. plugin.with_casted<rotor::plugin::registry_plugin_t>(
  32. [&](auto &p) { p.register_name("ponger", get_address()); });
  33. plugin.with_casted<r::plugin::starter_plugin_t>([](auto &p) { p.subscribe_actor(&ponger_t::on_ping); });
  34. }
  35. void on_ping(r::message_t<ping_t> &) noexcept {
  36. ping_received++;
  37. do_shutdown();
  38. }
  39. };
  40. struct custom_sup : rt::supervisor_test_t {
  41. using rt::supervisor_test_t::supervisor_test_t;
  42. void on_child_init(actor_base_t *, const r::extended_error_ptr_t &ee_) noexcept override { ee = ee_; }
  43. r::extended_error_ptr_t ee;
  44. };
  45. /*
  46. * Let's have the following tree of supervisors
  47. *
  48. * S_root
  49. * | |
  50. * S_A1 S_B1
  51. * | |
  52. * S_A2 S_B2
  53. * / \
  54. * pinger ponger
  55. *
  56. * 1. Pinger should be able to send ping message to ponger. The message should
  57. * be processed by S_1, still it have to be delivered to ponger
  58. *
  59. * 2. Ponger should receive the message, and initiate it's own shutdown procedure
  60. *
  61. * 3. As all supervisors have the same locality, the S_2 supervisor should
  62. * receive ponger shutdown request and spawn a new ponger.
  63. *
  64. * 4. All messaging (except initialization) should happen in single do_process
  65. * pass
  66. *
  67. */
  68. TEST_CASE("supervisor/locality tree ", "[supervisor]") {
  69. r::system_context_t system_context;
  70. const void *locality = &system_context;
  71. auto sup_root = system_context.create_supervisor<rt::supervisor_test_t>()
  72. .locality(locality)
  73. .timeout(rt::default_timeout)
  74. .create_registry()
  75. .finish();
  76. auto sup_A1 =
  77. sup_root->create_actor<rt::supervisor_test_t>().locality(locality).timeout(rt::default_timeout).finish();
  78. auto sup_A2 =
  79. sup_A1->create_actor<rt::supervisor_test_t>().locality(locality).timeout(rt::default_timeout).finish();
  80. auto sup_B1 =
  81. sup_root->create_actor<rt::supervisor_test_t>().locality(locality).timeout(rt::default_timeout).finish();
  82. auto sup_B2 =
  83. sup_B1->create_actor<rt::supervisor_test_t>().locality(locality).timeout(rt::default_timeout).finish();
  84. auto pinger = sup_A2->create_actor<pinger_t>().timeout(rt::default_timeout).finish();
  85. auto ponger = sup_B2->create_actor<ponger_t>().timeout(rt::default_timeout).finish();
  86. pinger->set_ponger_addr(ponger->get_address());
  87. sup_A2->do_process();
  88. CHECK(sup_A2->get_children_count() == 1);
  89. CHECK(sup_B2->get_children_count() == 1);
  90. CHECK(ping_sent == 1);
  91. CHECK(ping_received == 1);
  92. sup_root->do_shutdown();
  93. sup_root->do_process();
  94. REQUIRE(sup_A2->get_state() == r::state_t::SHUT_DOWN);
  95. REQUIRE(sup_B2->get_state() == r::state_t::SHUT_DOWN);
  96. REQUIRE(sup_A1->get_state() == r::state_t::SHUT_DOWN);
  97. REQUIRE(sup_B1->get_state() == r::state_t::SHUT_DOWN);
  98. REQUIRE(sup_root->get_state() == r::state_t::SHUT_DOWN);
  99. }
  100. TEST_CASE("failure escalation") {
  101. r::system_context_t system_context;
  102. auto sup_root =
  103. system_context.create_supervisor<custom_sup>().timeout(rt::default_timeout).create_registry().finish();
  104. auto sup_child = sup_root->create_actor<rt::supervisor_test_t>().timeout(rt::default_timeout).finish();
  105. r::address_ptr_t dummy_addr;
  106. auto act = sup_child->create_actor<rt::actor_test_t>().timeout(rt::default_timeout).finish();
  107. act->configurer = [&](auto &, r::plugin::plugin_base_t &plugin) {
  108. plugin.with_casted<r::plugin::registry_plugin_t>([&](auto &p) { p.discover_name("service-name", dummy_addr); });
  109. };
  110. sup_root->do_process();
  111. CHECK(act->get_state() == r::state_t::SHUT_DOWN);
  112. CHECK(sup_child->get_state() == r::state_t::SHUT_DOWN);
  113. CHECK(sup_root->get_state() == r::state_t::SHUT_DOWN);
  114. auto &ee = sup_root->ee;
  115. REQUIRE(ee);
  116. CHECK(ee->ec.message() == "failure escalation");
  117. }