7 #include "caf/test/runnable.hpp" 9 #include "caf/actor_clock.hpp" 10 #include "caf/actor_system.hpp" 11 #include "caf/actor_system_config.hpp" 12 #include "caf/binary_deserializer.hpp" 13 #include "caf/binary_serializer.hpp" 14 #include "caf/detail/source_location.hpp" 15 #include "caf/detail/test_export.hpp" 16 #include "caf/detail/type_traits.hpp" 17 #include "caf/mailbox_element.hpp" 18 #include "caf/resumable.hpp" 40 struct scheduling_event {
41 scheduling_event(
resumable* target, mailbox_element_ptr payload)
42 : target(target), item(std::move(payload)) {
50 mailbox_element_ptr item;
57 class value_predicate {
60 predicate_ = [](
const T&) {
return true; };
63 explicit value_predicate(decltype(std::ignore)) : value_predicate() {
68 explicit value_predicate(
69 U value, std::enable_if_t<detail::is_comparable_v<T, U>>* =
nullptr) {
70 predicate_ = [value](
const T& found) {
return found == value; };
73 explicit value_predicate(std::reference_wrapper<T> ref) {
74 predicate_ = [ref](
const T& found) {
82 class = std::enable_if_t<std::is_same_v<
83 bool, decltype(std::declval<Predicate>()(std::declval<const T&>()))>>>
84 explicit value_predicate(Predicate predicate) {
85 predicate_ = std::move(predicate);
88 value_predicate(value_predicate&&) =
default;
90 value_predicate(
const value_predicate&) =
default;
92 value_predicate& operator=(value_predicate&&) =
default;
94 value_predicate& operator=(
const value_predicate&) =
default;
96 bool operator()(
const T& value) {
97 return predicate_(value);
101 std::function<bool(const T&)> predicate_;
105 using actor_predicate = value_predicate<strong_actor_ptr>;
108 class CAF_TEST_EXPORT abstract_message_predicate {
110 virtual ~abstract_message_predicate();
112 virtual bool operator()(
const message&) = 0;
116 template <
class... Ts>
117 class message_predicate :
public abstract_message_predicate {
119 template <
class U,
class... Us>
120 explicit message_predicate(U x, Us... xs) {
121 predicates_ = std::make_shared<predicates_tuple>(std::move(x),
125 explicit message_predicate(decltype(std::ignore)) {
129 message_predicate() {
130 predicates_ = std::make_shared<predicates_tuple>();
133 message_predicate(message_predicate&&) =
default;
135 message_predicate(
const message_predicate&) =
default;
137 message_predicate& operator=(message_predicate&&) =
default;
139 message_predicate& operator=(
const message_predicate&) =
default;
141 bool operator()(
const message& msg) {
144 if (
auto view = make_const_typed_message_view<Ts...>(msg))
145 return do_check(view, std::index_sequence_for<Ts...>{});
150 template <
size_t... Is>
152 std::index_sequence<Is...>) {
153 return (((std::get<Is>(*predicates_))(get<Is>(view))) && ...);
156 using predicates_tuple = std::tuple<value_predicate<Ts>...>;
158 std::shared_ptr<predicates_tuple> predicates_;
176 void* custom_setup_data);
179 std::map<actor_id, detail::actor_local_printer_ptr> printers_;
197 template <
class... Ts>
202 : fix_(fix), loc_(loc), algo_(algorithm) {
230 template <
class... Us>
232 static_assert(
sizeof...(Ts) ==
sizeof...(Us));
233 static_assert((std::is_constructible_v<value_predicate<Ts>, Us> && ...));
234 with_ = message_predicate<Ts...>(std::move(xs)...);
235 return std::move(*
this);
241 from_ = value_predicate<strong_actor_ptr>{src};
242 return std::move(*
this);
248 from_ = value_predicate<strong_actor_ptr>{src};
249 return std::move(*
this);
254 template <
class... Us>
256 from_ = value_predicate<strong_actor_ptr>{src};
257 return std::move(*
this);
268 from_ = value_predicate<strong_actor_ptr>{src};
269 return std::move(*
this);
272 evaluator&& priority(message_priority priority) && {
273 priority_ = priority;
274 return std::move(*
this);
279 bool to(
const T& dst) && {
282 case evaluator_algorithm::expect:
283 return eval_dispatch(dst_ptr,
true);
284 case evaluator_algorithm::allow:
285 return eval_dispatch(dst_ptr,
false);
286 case evaluator_algorithm::disallow:
287 if (dry_run(dst_ptr)) {
289 ctx.fail({
"disallow message found", loc_});
292 case evaluator_algorithm::prepone:
293 return eval_prepone(dst_ptr);
294 case evaluator_algorithm::prepone_and_expect:
295 eval_prepone(dst_ptr);
296 return eval_dispatch(dst_ptr,
true);
297 case evaluator_algorithm::prepone_and_allow:
298 return eval_prepone(dst_ptr) && eval_dispatch(dst_ptr,
false);
305 using predicates = std::tuple<value_predicate<Ts>...>;
309 auto*
event = fix_->find_event_impl(dst);
311 if (fail_on_mismatch)
312 ctx.fail({
"no matching message found", loc_});
315 if (!from_(event->item->sender) || !with_(event->item->payload)) {
316 if (fail_on_mismatch)
317 ctx.fail({
"no matching message found", loc_});
321 if (event->item->mid.priority() != *priority_) {
322 if (fail_on_mismatch)
323 ctx.fail({
"message priority does not match", loc_});
327 fix_->prepone_event_impl(dst);
328 if (fail_on_mismatch) {
329 if (!fix_->dispatch_message())
330 ctx.fail({
"failed to dispatch message", loc_});
334 return fix_->dispatch_message();
338 auto*
event = fix_->find_event_impl(dst);
341 return from_(event->item->sender) && !with_(event->item->payload);
345 return fix_->prepone_event_impl(dst, from_, with_);
351 actor_predicate from_;
352 message_predicate<Ts...> with_;
353 std::optional<message_priority> priority_;
358 template <
class... Ts>
362 : fix_(fix), loc_(loc), values_(std::move(values)...) {
380 return std::move(*
this);
387 return std::move(*
this);
392 template <
class... Us>
395 return std::move(*
this);
401 void to(
const T& dst) && {
402 to_impl(dst, std::make_index_sequence<
sizeof...(Ts)>{});
406 template <
class T,
size_t... Is>
407 void to_impl(
const T& dst, std::index_sequence<Is...>) {
409 ptr->
enqueue(make_mailbox_element(from_, make_message_id(),
410 std::get<Is>(values_)...),
412 fix_->expect<Ts...>(loc_)
414 .with(std::get<Is>(values_)...)
421 std::tuple<Ts...> values_;
427 template <
class Handle>
441 fix_->inject_exit(dst_, exit_reason::kill);
455 template <
class... Ts>
479 return mail_count(actor_cast<strong_actor_ptr>(receiver));
483 template <
class... Ts>
485 return mail_count(actor_cast<strong_actor_ptr>(receiver));
492 template <
class Handle>
494 return terminated(actor_cast<strong_actor_ptr>(hdl));
500 bool dispatch_message();
503 size_t dispatch_messages();
510 error reason = exit_reason::user_shutdown);
514 template <
class Handle>
517 inject_exit(actor_cast<strong_actor_ptr>(hdl), std::move(reason));
526 = detail::source_location::current());
532 = detail::source_location::current());
537 = detail::source_location::current());
542 = detail::source_location::current());
545 [[nodiscard]]
size_t num_timeouts() noexcept;
549 return num_timeouts() > 0;
555 = detail::source_location::current());
560 = detail::source_location::current());
567 template <
class... Ts>
569 = detail::source_location::current()) {
570 return evaluator<Ts...>{
this, loc, evaluator_algorithm::expect};
575 template <
class... Ts>
577 = detail::source_location::current()) {
578 return evaluator<Ts...>{
this, loc, evaluator_algorithm::allow};
583 template <
class... Ts>
585 = detail::source_location::current()) {
586 return evaluator<Ts...>{
this, loc, evaluator_algorithm::disallow};
594 template <
class... Ts>
595 auto with(Ts... values) {
596 return injector<Ts...>{fix, loc, std::move(values)...};
604 = detail::source_location::current()) {
611 template <
class... Ts>
613 = detail::source_location::current()) {
614 return evaluator<Ts...>{
this, loc, evaluator_algorithm::prepone};
618 template <
class... Ts>
620 = detail::source_location::current()) {
621 return evaluator<Ts...>{
this, loc, evaluator_algorithm::prepone_and_expect};
625 template <
class... Ts>
627 = detail::source_location::current()) {
628 return evaluator<Ts...>{
this, loc, evaluator_algorithm::prepone_and_allow};
634 expected<T> serialization_roundtrip(
const T& value) {
638 if (!sink.apply(value))
639 return sink.get_error();
644 if (!source.apply(result))
645 return source.get_error();
653 template <
class Handle>
664 std::list<std::unique_ptr<scheduling_event>> events_;
684 actor_predicate& sender_pred,
685 abstract_message_predicate& payload_pred);
auto allow(const detail::source_location &loc=detail::source_location::current())
Tries to match a message with types Ts... and executes it if it is the next message in the mailbox of...
Definition: deterministic.hpp:576
evaluator && with(Us... xs) &&
Matches the values of the message.
Definition: deterministic.hpp:231
bool terminated(const Handle &hdl)
Checks whether hdl has terminated.
Definition: deterministic.hpp:493
Utility class for injecting messages into the mailbox of an actor and then checking whether the actor...
Definition: deterministic.hpp:359
A cooperatively scheduled entity.
Definition: resumable.hpp:15
evaluator_algorithm
Configures the algorithm to evaluate for an evaluator instances.
Definition: deterministic.hpp:183
evaluator && from(const strong_actor_ptr &src) &&
Adds a predicate for the sender of the next message that matches only if the sender is src...
Definition: deterministic.hpp:240
actor_scope_guard make_actor_scope_guard(const Handle &hdl)
Creates a new guard for hdl that will kill the actor at scope exit.
Definition: deterministic.hpp:654
Wraps the result of a message handler to represent either a value (wrapped into a message)...
Definition: fwd.hpp:64
Helper class for inject that only provides with.
Definition: deterministic.hpp:590
Provides a fluent interface for matching messages.
Definition: deterministic.hpp:198
Base class for actors running on this node, either living in an own thread or cooperatively scheduled...
Definition: local_actor.hpp:41
auto expect(const detail::source_location &loc=detail::source_location::current())
Expects a message with types Ts... as the next message in the mailbox of the receiver and aborts the ...
Definition: deterministic.hpp:568
A fixture for writing unit tests that require deterministic scheduling.
Definition: deterministic.hpp:29
actor_system_config cfg
Configures the actor system with deterministic scheduling.
Definition: deterministic.hpp:668
Definition: deterministic.cpp:35
size_t mail_count(const actor &receiver)
Returns the number of pending messages for receiver.
Definition: deterministic.hpp:478
auto prepone_and_allow(const detail::source_location &loc=detail::source_location::current())
Shortcut for calling prepone and then allow with the same arguments.
Definition: deterministic.hpp:626
evaluator && from(const actor &src) &&
Adds a predicate for the sender of the next message that matches only if the sender is src...
Definition: deterministic.hpp:247
An intrusive, reference counting smart pointer implementation.
Definition: fwd.hpp:32
size_t mail_count(const typed_actor< Ts... > &receiver)
Returns the number of pending messages for receiver.
Definition: deterministic.hpp:484
Describes a fixed-length, copy-on-write, type-erased tuple with elements of any type.
Definition: message.hpp:32
Actor environment including scheduler, registry, and optional components such as a middleman...
Definition: actor_system.hpp:87
A serializable type for storing error codes with category and optional, human-readable context inform...
Definition: error.hpp:50
Definition: deterministic.cpp:443
Encountered faulty logic in the program.
injector && from(const typed_actor< Us... > &src) &&
Adds a predicate for the sender of the next message that matches only if the sender is src...
Definition: deterministic.hpp:393
typename clock_type::duration duration_type
Time interval.
Definition: actor_clock.hpp:28
T actor_cast(U &&what)
Converts the actor handle what to a different actor handle or raw pointer of type T...
Definition: actor_cast.hpp:148
typename clock_type::time_point time_point
Discrete point in time.
Definition: actor_clock.hpp:25
void inject_exit(const Handle &hdl, error reason=exit_reason::user_shutdown)
Injects an exit message into the mailbox of hdl and dispatches it immediately.
Definition: deterministic.hpp:516
void to(const T &dst) &&
Sets the target actor for this injector, sends the message, and then checks whether the actor handles...
Definition: deterministic.hpp:401
bool has_pending_timeout() noexcept
Returns whether there is at least one pending timeout.
Definition: deterministic.hpp:548
Definition: const_typed_message_view.hpp:18
Serializes C++ objects into a sequence of bytes.
Definition: binary_serializer.hpp:25
A cooperatively scheduled, event-based actor implementation.
Definition: scheduled_actor.hpp:73
auto inject(const detail::source_location &loc=detail::source_location::current())
Starts an inject clause.
Definition: deterministic.hpp:603
system_impl sys
The actor system instance for the tests.
Definition: deterministic.hpp:671
auto prepone_and_expect(const detail::source_location &loc=detail::source_location::current())
Shortcut for calling prepone and then expect with the same arguments.
Definition: deterministic.hpp:619
Represents the result of a computation which can either complete successfully with an instance of typ...
Definition: expected.hpp:45
Definition: deterministic.cpp:207
bool to(const T &dst) &&
Sets the target actor for this evaluator and evaluate the predicate.
Definition: deterministic.hpp:279
evaluator && from(std::reference_wrapper< strong_actor_ptr > src) &&
Causes the evaluator to store the sender of a matched message in src.
Definition: deterministic.hpp:267
Deserializes C++ objects from sequence of bytes.
Definition: binary_deserializer.hpp:26
static runnable & current()
Returns the runnable instance that is currently running.
Definition: runnable.cpp:83
Identifies an untyped actor.
Definition: actor.hpp:28
Base class for all actor implementations.
Definition: abstract_actor.hpp:48
The custom system implementation for this fixture.
Definition: deterministic.hpp:165
evaluator && from(const typed_actor< Us... > &src) &&
Adds a predicate for the sender of the next message that matches only if the sender is src...
Definition: deterministic.hpp:255
injector && from(const strong_actor_ptr &src) &&
Adds a predicate for the sender of the next message that matches only if the sender is src...
Definition: deterministic.hpp:378
injector && from(const actor &src) &&
Adds a predicate for the sender of the next message that matches only if the sender is src...
Definition: deterministic.hpp:385
virtual bool enqueue(mailbox_element_ptr what, scheduler *sched)=0
Enqueues a new message wrapped in a mailbox_element to the actor.
auto disallow(const detail::source_location &loc=detail::source_location::current())
Tries to match a message with types Ts... and executes it if it is the next message in the mailbox of...
Definition: deterministic.hpp:584
auto prepone(const detail::source_location &loc=detail::source_location::current())
Tries to prepone a message, i.e., reorders the messages in the mailbox of the receiver such that the ...
Definition: deterministic.hpp:612
Utility class for unconditionally killing an actor at scope exit.
Definition: deterministic.hpp:425
std::vector< std::byte > byte_buffer
A buffer for storing binary data.
Definition: byte_buffer.hpp:13
Definition: source_location.hpp:12
static reporter & instance()
Returns the registered reporter instance.
Definition: reporter.cpp:546
evaluator && from(std::nullptr_t) &&
Adds a predicate for the sender of the next message that matches only anonymous messages, i.e., messages without a sender.
Definition: deterministic.hpp:262
Definition: deterministic.cpp:115
Configures an actor_system on startup.
Definition: actor_system_config.hpp:28