blob: 7d7f6fa952519aac81d545d5e4c6167aa37d0583 [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
51TEST_F(Context, SpawnThrowingTask)
52{
Patrick Williams5e7ef082023-01-05 11:08:53 -060053 ctx->spawn(stdexec::just() |
54 stdexec::then([]() { throw std::logic_error("Oops"); }));
Patrick Williams10483c92022-09-23 11:33:39 -050055
56 EXPECT_THROW(runToStop(), std::logic_error);
57 ctx->run();
58}
59
Patrick Williams9949a162023-05-08 16:32:29 -050060TEST_F(Context, SpawnThrowingCoroutine)
61{
62 struct _
63 {
64 static auto one() -> sdbusplus::async::task<>
65 {
66 throw std::logic_error("Oops");
67 co_return;
68 }
69 };
70
71 ctx->spawn(_::one());
72 EXPECT_THROW(runToStop(), std::logic_error);
73 ctx->run();
74};
75
Patrick Williams115e9b32022-09-23 16:20:59 -050076TEST_F(Context, SpawnManyThrowingTasks)
77{
78 static constexpr size_t count = 100;
79 for (size_t i = 0; i < count; ++i)
80 {
Patrick Williams5e7ef082023-01-05 11:08:53 -060081 ctx->spawn(stdexec::just() |
82 stdexec::then([]() { throw std::logic_error("Oops"); }));
Patrick Williams115e9b32022-09-23 16:20:59 -050083 }
84 spawnStop();
85
86 for (size_t i = 0; i < count; ++i)
87 {
88 EXPECT_THROW(ctx->run(), std::logic_error);
89 }
90 ctx->run();
91}
92
Patrick Williams78e436f2022-09-21 10:06:20 -050093TEST_F(Context, SpawnDelayedTask)
94{
95 using namespace std::literals;
96 static constexpr auto timeout = 500ms;
97
98 auto start = std::chrono::steady_clock::now();
99
100 bool ran = false;
101 ctx->spawn(sdbusplus::async::sleep_for(*ctx, timeout) |
Patrick Williams5e7ef082023-01-05 11:08:53 -0600102 stdexec::then([&ran]() { ran = true; }));
Patrick Williams78e436f2022-09-21 10:06:20 -0500103
Patrick Williams1b7b54c2022-09-21 10:49:45 -0500104 runToStop();
Patrick Williams78e436f2022-09-21 10:06:20 -0500105
106 auto stop = std::chrono::steady_clock::now();
107
108 EXPECT_TRUE(ran);
109 EXPECT_GT(stop - start, timeout);
Patrick Williams6ea246a2022-10-14 07:58:15 -0500110 EXPECT_LT(stop - start, timeout * 3);
Patrick Williams0139cac2022-09-20 17:04:17 -0500111}
Patrick Williams1b7b54c2022-09-21 10:49:45 -0500112
Patrick Williamsd6b05cc2022-09-23 09:38:38 -0500113TEST_F(Context, SpawnRecursiveTask)
114{
115 struct _
116 {
117 static auto one(size_t count, size_t& executed)
118 -> sdbusplus::async::task<size_t>
119 {
120 if (count)
121 {
122 ++executed;
123 co_return (co_await one(count - 1, executed)) + 1;
124 }
Patrick Williams5e7ef082023-01-05 11:08:53 -0600125 co_return co_await stdexec::just(0);
Patrick Williamsd6b05cc2022-09-23 09:38:38 -0500126 }
127 };
128
129 static constexpr size_t count = 100;
130 size_t executed = 0;
131
Patrick Williams5e7ef082023-01-05 11:08:53 -0600132 ctx->spawn(_::one(count, executed) |
133 stdexec::then([=](auto result) { EXPECT_EQ(result, count); }));
Patrick Williamsd6b05cc2022-09-23 09:38:38 -0500134
135 runToStop();
136
137 EXPECT_EQ(executed, count);
138}
139
Patrick Williams1b7b54c2022-09-21 10:49:45 -0500140TEST_F(Context, DestructMatcherWithPendingAwait)
141{
142 using namespace std::literals;
143
144 bool ran = false;
145 auto m = std::make_optional<sdbusplus::async::match>(
146 *ctx, sdbusplus::bus::match::rules::interfacesAdded(
147 "/this/is/a/bogus/path/for/SpawnMatcher"));
148
149 // Await the match completion (which will never happen).
Patrick Williams5e7ef082023-01-05 11:08:53 -0600150 ctx->spawn(m->next() | stdexec::then([&ran](...) { ran = true; }));
Patrick Williams1b7b54c2022-09-21 10:49:45 -0500151
152 // Destruct the match.
153 ctx->spawn(sdbusplus::async::sleep_for(*ctx, 1ms) |
Patrick Williams5e7ef082023-01-05 11:08:53 -0600154 stdexec::then([&m](...) { m.reset(); }));
Patrick Williams1b7b54c2022-09-21 10:49:45 -0500155
Patrick Williams4cfc2842022-09-22 09:53:33 -0500156 EXPECT_THROW(runToStop(), sdbusplus::exception::UnhandledStop);
Patrick Williams10483c92022-09-23 11:33:39 -0500157 EXPECT_NO_THROW(ctx->run());
Patrick Williams1b7b54c2022-09-21 10:49:45 -0500158 EXPECT_FALSE(ran);
159}
160
161TEST_F(Context, DestructMatcherWithPendingAwaitAsTask)
162{
163 using namespace std::literals;
164
165 auto m = std::make_optional<sdbusplus::async::match>(
166 *ctx, sdbusplus::bus::match::rules::interfacesAdded(
167 "/this/is/a/bogus/path/for/SpawnMatcher"));
168
169 struct _
170 {
171 static auto fn(decltype(m->next()) snd, bool& ran)
172 -> sdbusplus::async::task<>
173 {
174 co_await std::move(snd);
175 ran = true;
176 co_return;
177 }
178 };
179
180 bool ran = false;
181 ctx->spawn(_::fn(m->next(), ran));
182 ctx->spawn(sdbusplus::async::sleep_for(*ctx, 1ms) |
Patrick Williams5e7ef082023-01-05 11:08:53 -0600183 stdexec::then([&]() { m.reset(); }));
Patrick Williams1b7b54c2022-09-21 10:49:45 -0500184
Patrick Williams4cfc2842022-09-22 09:53:33 -0500185 EXPECT_THROW(runToStop(), sdbusplus::exception::UnhandledStop);
Patrick Williams10483c92022-09-23 11:33:39 -0500186 EXPECT_NO_THROW(ctx->run());
Patrick Williams1b7b54c2022-09-21 10:49:45 -0500187 EXPECT_FALSE(ran);
188}