1 // This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
2 // the main distribution directory for license terms and copyright or visit
3 // https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
4 
5 #define CAF_SUITE decorator.sequencer
6 
7 #include "caf/decorator/sequencer.hpp"
8 
9 #include "caf/test/unit_test.hpp"
10 
11 #include "caf/all.hpp"
12 
13 #define ERROR_HANDLER [&](error& err) { CAF_FAIL(err); }
14 
15 using namespace caf;
16 
17 namespace {
18 
testee(event_based_actor * self)19 behavior testee(event_based_actor* self) {
20   return {
21     [](int v) { return 2 * v; },
22     [=] { self->quit(); },
23   };
24 }
25 
26 using first_stage = typed_actor<replies_to<int>::with<double, double>>;
27 using second_stage = typed_actor<replies_to<double, double>::with<double>>;
28 
typed_first_stage()29 first_stage::behavior_type typed_first_stage() {
30   return {
31     [](int i) -> result<double, double> {
32       return {i * 2.0, i * 4.0};
33     },
34   };
35 }
36 
typed_second_stage()37 second_stage::behavior_type typed_second_stage() {
38   return {
39     [](double x, double y) { return x * y; },
40   };
41 }
42 
43 struct fixture {
fixture__anone3270d710111::fixture44   fixture() : system(cfg), self(system, true) {
45     // nop
46   }
47 
48   template <class Actor>
exited__anone3270d710111::fixture49   static bool exited(const Actor& handle) {
50     auto ptr = actor_cast<abstract_actor*>(handle);
51     auto dptr = dynamic_cast<monitorable_actor*>(ptr);
52     CAF_REQUIRE(dptr != nullptr);
53     return dptr->getf(abstract_actor::is_terminated_flag);
54   }
55 
56   actor_system_config cfg;
57   actor_system system;
58   scoped_actor self;
59 };
60 
61 } // namespace
62 
CAF_TEST_FIXTURE_SCOPE(sequencer_tests,fixture)63 CAF_TEST_FIXTURE_SCOPE(sequencer_tests, fixture)
64 
65 CAF_TEST(identity) {
66   actor_system_config cfg_g;
67   actor_system system_of_g{cfg_g};
68   actor_system_config cfg_f;
69   actor_system system_of_f{cfg_f};
70   auto g = system_of_g.spawn(typed_first_stage);
71   auto f = system_of_f.spawn(typed_second_stage);
72   CAF_CHECK_EQUAL(system_of_g.registry().running(), 1u);
73   auto h = f * g;
74   CAF_CHECK_EQUAL(system_of_g.registry().running(), 1u);
75   CAF_CHECK_EQUAL(&h->home_system(), &g->home_system());
76   CAF_CHECK_EQUAL(h->node(), g->node());
77   CAF_CHECK_NOT_EQUAL(h->id(), g->id());
78   CAF_CHECK_NOT_EQUAL(h.address(), g.address());
79   CAF_CHECK_EQUAL(h->message_types(), g->home_system().message_types(h));
80 }
81 
82 // spawned dead if `g` is already dead upon spawning
CAF_TEST(lifetime_1a)83 CAF_TEST(lifetime_1a) {
84   auto g = system.spawn(testee);
85   auto f = system.spawn(testee);
86   anon_send_exit(g, exit_reason::kill);
87   self->wait_for(g);
88   auto h = f * g;
89   CAF_CHECK(exited(h));
90 }
91 
92 // spawned dead if `f` is already dead upon spawning
CAF_TEST(lifetime_1b)93 CAF_TEST(lifetime_1b) {
94   auto g = system.spawn(testee);
95   auto f = system.spawn(testee);
96   anon_send_exit(f, exit_reason::kill);
97   self->wait_for(f);
98   auto h = f * g;
99   CAF_CHECK(exited(h));
100 }
101 
102 // `f.g` exits when `g` exits
CAF_TEST(lifetime_2a)103 CAF_TEST(lifetime_2a) {
104   auto g = system.spawn(testee);
105   auto f = system.spawn(testee);
106   auto h = f * g;
107   self->monitor(h);
108   anon_send(g, message{});
109 }
110 
111 // `f.g` exits when `f` exits
CAF_TEST(lifetime_2b)112 CAF_TEST(lifetime_2b) {
113   auto g = system.spawn(testee);
114   auto f = system.spawn(testee);
115   auto h = f * g;
116   self->monitor(h);
117   anon_send(f, message{});
118 }
119 
CAF_TEST(request_response_promise)120 CAF_TEST(request_response_promise) {
121   auto g = system.spawn(testee);
122   auto f = system.spawn(testee);
123   auto h = f * g;
124   anon_send_exit(h, exit_reason::kill);
125   CAF_CHECK(exited(h));
126   self->request(h, infinite, 1)
127     .receive([](int) { CAF_CHECK(false); },
128              [](error err) {
129                CAF_CHECK_EQUAL(err.code(), static_cast<uint8_t>(
130                                              sec::request_receiver_down));
131              });
132 }
133 
134 // single composition of distinct actors
CAF_TEST(dot_composition_1)135 CAF_TEST(dot_composition_1) {
136   auto first = system.spawn(typed_first_stage);
137   auto second = system.spawn(typed_second_stage);
138   auto first_then_second = second * first;
139   self->request(first_then_second, infinite, 42)
140     .receive([](double res) { CAF_CHECK_EQUAL(res, (42 * 2.0) * (42 * 4.0)); },
141              ERROR_HANDLER);
142 }
143 
144 // multiple self composition
CAF_TEST(dot_composition_2)145 CAF_TEST(dot_composition_2) {
146   auto dbl_actor = system.spawn(testee);
147   auto dbl_x4_actor = dbl_actor * dbl_actor * dbl_actor * dbl_actor;
148   self->request(dbl_x4_actor, infinite, 1)
149     .receive([](int v) { CAF_CHECK_EQUAL(v, 16); }, ERROR_HANDLER);
150 }
151 
152 CAF_TEST_FIXTURE_SCOPE_END()
153