blob: 8cdd93c03d0953e8bcea9f2a0359bfa48d2cd8fa [file] [log] [blame]
Patrick Williams73e278b2022-09-16 08:31:36 -05001#include <sdbusplus/async.hpp>
2
3#include <gtest/gtest.h>
4
Patrick Williams78e436f2022-09-21 10:06:20 -05005struct Context : public testing::Test
Patrick Williams73e278b2022-09-16 08:31:36 -05006{
Ed Tanous9688ed62023-01-06 13:17:25 -08007 ~Context() noexcept override = default;
Patrick Williams78e436f2022-09-21 10:06:20 -05008
9 void TearDown() override
10 {
11 // Destructing the context can throw, so we have to do it in
12 // the TearDown in order to make our destructor noexcept.
13 ctx.reset();
14 }
15
Patrick Williams115e9b32022-09-23 16:20:59 -050016 void spawnStop()
Patrick Williams1b7b54c2022-09-21 10:49:45 -050017 {
Patrick Williams5e7ef082023-01-05 11:08:53 -060018 ctx->spawn(stdexec::just() |
19 stdexec::then([this]() { ctx->request_stop(); }));
Patrick Williams115e9b32022-09-23 16:20:59 -050020 }
21
22 void runToStop()
23 {
24 spawnStop();
Patrick Williams3c242ba2022-09-23 09:51:55 -050025 ctx->run();
Patrick Williams1b7b54c2022-09-21 10:49:45 -050026 }
27
Patrick Williams78e436f2022-09-21 10:06:20 -050028 std::optional<sdbusplus::async::context> ctx{std::in_place};
29};
30
31TEST_F(Context, RunSimple)
32{
Patrick Williams1b7b54c2022-09-21 10:49:45 -050033 runToStop();
Patrick Williams73e278b2022-09-16 08:31:36 -050034}
Patrick Williams0139cac2022-09-20 17:04:17 -050035
Patrick Williams78e436f2022-09-21 10:06:20 -050036TEST_F(Context, SpawnedTask)
Patrick Williams0139cac2022-09-20 17:04:17 -050037{
Patrick Williams5e7ef082023-01-05 11:08:53 -060038 ctx->spawn(stdexec::just());
Patrick Williams1b7b54c2022-09-21 10:49:45 -050039 runToStop();
Patrick Williams78e436f2022-09-21 10:06:20 -050040}
Patrick Williams0139cac2022-09-20 17:04:17 -050041
Patrick Williams10483c92022-09-23 11:33:39 -050042TEST_F(Context, ReentrantRun)
43{
44 runToStop();
45 for (int i = 0; i < 100; ++i)
46 {
47 ctx->run();
48 }
49}
50
Patrick Williams78e436f2022-09-21 10:06:20 -050051TEST_F(Context, SpawnDelayedTask)
52{
53 using namespace std::literals;
54 static constexpr auto timeout = 500ms;
55
56 auto start = std::chrono::steady_clock::now();
57
58 bool ran = false;
59 ctx->spawn(sdbusplus::async::sleep_for(*ctx, timeout) |
Patrick Williams5e7ef082023-01-05 11:08:53 -060060 stdexec::then([&ran]() { ran = true; }));
Patrick Williams78e436f2022-09-21 10:06:20 -050061
Patrick Williams1b7b54c2022-09-21 10:49:45 -050062 runToStop();
Patrick Williams78e436f2022-09-21 10:06:20 -050063
64 auto stop = std::chrono::steady_clock::now();
65
66 EXPECT_TRUE(ran);
67 EXPECT_GT(stop - start, timeout);
Patrick Williams6ea246a2022-10-14 07:58:15 -050068 EXPECT_LT(stop - start, timeout * 3);
Patrick Williams0139cac2022-09-20 17:04:17 -050069}
Patrick Williams1b7b54c2022-09-21 10:49:45 -050070
Patrick Williamsd6b05cc2022-09-23 09:38:38 -050071TEST_F(Context, SpawnRecursiveTask)
72{
73 struct _
74 {
75 static auto one(size_t count, size_t& executed)
76 -> sdbusplus::async::task<size_t>
77 {
78 if (count)
79 {
80 ++executed;
81 co_return (co_await one(count - 1, executed)) + 1;
82 }
Patrick Williams5e7ef082023-01-05 11:08:53 -060083 co_return co_await stdexec::just(0);
Patrick Williamsd6b05cc2022-09-23 09:38:38 -050084 }
85 };
86
87 static constexpr size_t count = 100;
88 size_t executed = 0;
89
Patrick Williams5e7ef082023-01-05 11:08:53 -060090 ctx->spawn(_::one(count, executed) |
91 stdexec::then([=](auto result) { EXPECT_EQ(result, count); }));
Patrick Williamsd6b05cc2022-09-23 09:38:38 -050092
93 runToStop();
94
95 EXPECT_EQ(executed, count);
96}
97
Patrick Williams1b7b54c2022-09-21 10:49:45 -050098TEST_F(Context, DestructMatcherWithPendingAwait)
99{
100 using namespace std::literals;
101
102 bool ran = false;
103 auto m = std::make_optional<sdbusplus::async::match>(
104 *ctx, sdbusplus::bus::match::rules::interfacesAdded(
105 "/this/is/a/bogus/path/for/SpawnMatcher"));
106
107 // Await the match completion (which will never happen).
Patrick Williams5e7ef082023-01-05 11:08:53 -0600108 ctx->spawn(m->next() | stdexec::then([&ran](...) { ran = true; }));
Patrick Williams1b7b54c2022-09-21 10:49:45 -0500109
110 // Destruct the match.
111 ctx->spawn(sdbusplus::async::sleep_for(*ctx, 1ms) |
Patrick Williams5e7ef082023-01-05 11:08:53 -0600112 stdexec::then([&m](...) { m.reset(); }));
Patrick Williams1b7b54c2022-09-21 10:49:45 -0500113
Patrick Williams97c31c82023-05-25 11:04:46 -0500114 runToStop();
Patrick Williams1b7b54c2022-09-21 10:49:45 -0500115 EXPECT_FALSE(ran);
116}
117
118TEST_F(Context, DestructMatcherWithPendingAwaitAsTask)
119{
120 using namespace std::literals;
121
122 auto m = std::make_optional<sdbusplus::async::match>(
123 *ctx, sdbusplus::bus::match::rules::interfacesAdded(
124 "/this/is/a/bogus/path/for/SpawnMatcher"));
125
126 struct _
127 {
128 static auto fn(decltype(m->next()) snd, bool& ran)
129 -> sdbusplus::async::task<>
130 {
131 co_await std::move(snd);
132 ran = true;
133 co_return;
134 }
135 };
136
137 bool ran = false;
138 ctx->spawn(_::fn(m->next(), ran));
139 ctx->spawn(sdbusplus::async::sleep_for(*ctx, 1ms) |
Patrick Williams5e7ef082023-01-05 11:08:53 -0600140 stdexec::then([&]() { m.reset(); }));
Patrick Williams1b7b54c2022-09-21 10:49:45 -0500141
Patrick Williams97c31c82023-05-25 11:04:46 -0500142 runToStop();
Patrick Williams1b7b54c2022-09-21 10:49:45 -0500143 EXPECT_FALSE(ran);
144}