1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#define CAF_SUITE actor_clock
#include "caf/actor_clock.hpp"
#include "core-test.hpp"
#include <chrono>
#include <memory>
#include "caf/all.hpp"
#include "caf/detail/test_actor_clock.hpp"
using namespace caf;
using namespace std::chrono_literals;
namespace {
struct testee_state {
event_based_actor* self;
disposable pending;
bool run_delayed_called = false;
testee_state(event_based_actor* self) : self(self) {
// nop
}
behavior make_behavior() {
self->set_exit_handler([this](exit_msg& x) { self->quit(x.reason); });
self->set_error_handler([](scheduled_actor*, error&) {});
return {
[this](ok_atom) {
CAF_LOG_TRACE("" << self->current_mailbox_element()->content());
pending = self->run_delayed(10s, [this] { run_delayed_called = true; });
},
[](const std::string&) { CAF_LOG_TRACE(""); },
[this](group& grp) {
CAF_LOG_TRACE("");
self->join(grp);
},
};
}
};
using testee_actor = stateful_actor<testee_state>;
struct fixture : test_coordinator_fixture<> {
detail::test_actor_clock& t;
actor aut;
fixture() : t(sched.clock()), aut(sys.spawn<testee_actor, lazy_init>()) {
// nop
}
auto& state() {
return deref<testee_actor>(aut).state;
}
};
} // namespace
BEGIN_FIXTURE_SCOPE(fixture)
CAF_TEST(run_delayed without dispose) {
// Have AUT call self->run_delayed().
self->send(aut, ok_atom_v);
expect((ok_atom), from(self).to(aut).with(_));
CHECK_EQ(t.schedule.size(), 1u);
// Advance time to trigger timeout.
t.advance_time(10s);
CHECK_EQ(t.schedule.size(), 0u);
// Have AUT receive the action.
expect((action), to(aut));
CHECK(state().run_delayed_called);
}
CAF_TEST(run_delayed with dispose before expire) {
// Have AUT call self->run_delayed().
self->send(aut, ok_atom_v);
expect((ok_atom), from(self).to(aut).with(_));
state().pending.dispose();
CHECK_EQ(t.schedule.size(), 1u);
// Advance time, but the clock drops the disposed callback.
t.advance_time(10s);
CHECK_EQ(t.schedule.size(), 0u);
// Have AUT receive the timeout.
disallow((action), to(aut));
CHECK(!state().run_delayed_called);
}
CAF_TEST(run_delayed with dispose after expire) {
// Have AUT call self->run_delayed().
self->send(aut, ok_atom_v);
expect((ok_atom), from(self).to(aut).with(_));
CHECK_EQ(t.schedule.size(), 1u);
// Advance time to send timeout message.
t.advance_time(10s);
CHECK_EQ(t.schedule.size(), 0u);
// Have AUT receive the timeout but dispose it: turns into a nop.
state().pending.dispose();
expect((action), to(aut));
CHECK(!state().run_delayed_called);
}
CAF_TEST(delay_actor_message) {
// Schedule a message for now + 10s.
auto n = t.now() + 10s;
auto autptr = actor_cast<strong_actor_ptr>(aut);
t.schedule_message(n, autptr,
make_mailbox_element(autptr, make_message_id(), no_stages,
"foo"));
CHECK_EQ(t.schedule.size(), 1u);
// Advance time to send the message.
t.advance_time(10s);
CHECK_EQ(t.schedule.size(), 0u);
// Have AUT receive the message.
expect((std::string), from(aut).to(aut).with("foo"));
}
CAF_TEST(delay_group_message) {
// Have AUT join the group.
auto grp = sys.groups().anonymous();
self->send(aut, grp);
expect((group), from(self).to(aut).with(_));
// Schedule a message for now + 10s.
auto n = t.now() + 10s;
auto autptr = actor_cast<strong_actor_ptr>(aut);
t.schedule_message(n, std::move(grp), autptr, make_message("foo"));
CHECK_EQ(t.schedule.size(), 1u);
// Advance time to send the message.
t.advance_time(10s);
CHECK_EQ(t.schedule.size(), 0u);
// Have AUT receive the message.
expect((std::string), from(aut).to(aut).with("foo"));
// Kill AUT (necessary because the group keeps a reference around).
self->send_exit(aut, exit_reason::kill);
expect((exit_msg), from(self).to(aut).with(_));
}
END_FIXTURE_SCOPE()
|