File: actor_clock.cpp

package info (click to toggle)
actor-framework 0.18.7-1~exp1
  • links: PTS
  • area: main
  • in suites: experimental
  • size: 8,740 kB
  • sloc: cpp: 85,162; sh: 491; python: 187; makefile: 11
file content (144 lines) | stat: -rw-r--r-- 4,177 bytes parent folder | download
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()