blob: b60cc3869660f0796e36a07702afd215be4a837f [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{
Patrick Williams78e436f2022-09-21 10:06:20 -05007 ~Context() noexcept = default;
8
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 Williams1b7b54c2022-09-21 10:49:45 -050016 void runToStop()
17 {
Patrick Williams3c242ba2022-09-23 09:51:55 -050018 ctx->spawn(std::execution::just() |
19 std::execution::then([this]() { ctx->request_stop(); }));
20 ctx->run();
Patrick Williams1b7b54c2022-09-21 10:49:45 -050021 }
22
Patrick Williams78e436f2022-09-21 10:06:20 -050023 std::optional<sdbusplus::async::context> ctx{std::in_place};
24};
25
26TEST_F(Context, RunSimple)
27{
Patrick Williams1b7b54c2022-09-21 10:49:45 -050028 runToStop();
Patrick Williams73e278b2022-09-16 08:31:36 -050029}
Patrick Williams0139cac2022-09-20 17:04:17 -050030
Patrick Williams78e436f2022-09-21 10:06:20 -050031TEST_F(Context, SpawnedTask)
Patrick Williams0139cac2022-09-20 17:04:17 -050032{
Patrick Williams78e436f2022-09-21 10:06:20 -050033 ctx->spawn(std::execution::just());
Patrick Williams1b7b54c2022-09-21 10:49:45 -050034 runToStop();
Patrick Williams78e436f2022-09-21 10:06:20 -050035}
Patrick Williams0139cac2022-09-20 17:04:17 -050036
Patrick Williams10483c92022-09-23 11:33:39 -050037TEST_F(Context, ReentrantRun)
38{
39 runToStop();
40 for (int i = 0; i < 100; ++i)
41 {
42 ctx->run();
43 }
44}
45
46TEST_F(Context, SpawnThrowingTask)
47{
48 ctx->spawn(std::execution::just() |
49 std::execution::then([]() { throw std::logic_error("Oops"); }));
50
51 EXPECT_THROW(runToStop(), std::logic_error);
52 ctx->run();
53}
54
Patrick Williams78e436f2022-09-21 10:06:20 -050055TEST_F(Context, SpawnDelayedTask)
56{
57 using namespace std::literals;
58 static constexpr auto timeout = 500ms;
59
60 auto start = std::chrono::steady_clock::now();
61
62 bool ran = false;
63 ctx->spawn(sdbusplus::async::sleep_for(*ctx, timeout) |
64 std::execution::then([&ran]() { ran = true; }));
65
Patrick Williams1b7b54c2022-09-21 10:49:45 -050066 runToStop();
Patrick Williams78e436f2022-09-21 10:06:20 -050067
68 auto stop = std::chrono::steady_clock::now();
69
70 EXPECT_TRUE(ran);
71 EXPECT_GT(stop - start, timeout);
72 EXPECT_LT(stop - start, timeout * 2);
Patrick Williams0139cac2022-09-20 17:04:17 -050073}
Patrick Williams1b7b54c2022-09-21 10:49:45 -050074
Patrick Williamsd6b05cc2022-09-23 09:38:38 -050075TEST_F(Context, SpawnRecursiveTask)
76{
77 struct _
78 {
79 static auto one(size_t count, size_t& executed)
80 -> sdbusplus::async::task<size_t>
81 {
82 if (count)
83 {
84 ++executed;
85 co_return (co_await one(count - 1, executed)) + 1;
86 }
87 co_return co_await std::execution::just(0);
88 }
89 };
90
91 static constexpr size_t count = 100;
92 size_t executed = 0;
93
94 ctx->spawn(_::one(count, executed) | std::execution::then([=](auto result) {
95 EXPECT_EQ(result, count);
96 }));
97
98 runToStop();
99
100 EXPECT_EQ(executed, count);
101}
102
Patrick Williams1b7b54c2022-09-21 10:49:45 -0500103TEST_F(Context, DestructMatcherWithPendingAwait)
104{
105 using namespace std::literals;
106
107 bool ran = false;
108 auto m = std::make_optional<sdbusplus::async::match>(
109 *ctx, sdbusplus::bus::match::rules::interfacesAdded(
110 "/this/is/a/bogus/path/for/SpawnMatcher"));
111
112 // Await the match completion (which will never happen).
113 ctx->spawn(m->next() | std::execution::then([&ran](...) { ran = true; }));
114
115 // Destruct the match.
116 ctx->spawn(sdbusplus::async::sleep_for(*ctx, 1ms) |
117 std::execution::then([&m](...) { m.reset(); }));
118
Patrick Williams4cfc2842022-09-22 09:53:33 -0500119 EXPECT_THROW(runToStop(), sdbusplus::exception::UnhandledStop);
Patrick Williams10483c92022-09-23 11:33:39 -0500120 EXPECT_NO_THROW(ctx->run());
Patrick Williams1b7b54c2022-09-21 10:49:45 -0500121 EXPECT_FALSE(ran);
122}
123
124TEST_F(Context, DestructMatcherWithPendingAwaitAsTask)
125{
126 using namespace std::literals;
127
128 auto m = std::make_optional<sdbusplus::async::match>(
129 *ctx, sdbusplus::bus::match::rules::interfacesAdded(
130 "/this/is/a/bogus/path/for/SpawnMatcher"));
131
132 struct _
133 {
134 static auto fn(decltype(m->next()) snd, bool& ran)
135 -> sdbusplus::async::task<>
136 {
137 co_await std::move(snd);
138 ran = true;
139 co_return;
140 }
141 };
142
143 bool ran = false;
144 ctx->spawn(_::fn(m->next(), ran));
145 ctx->spawn(sdbusplus::async::sleep_for(*ctx, 1ms) |
146 std::execution::then([&]() { m.reset(); }));
147
Patrick Williams4cfc2842022-09-22 09:53:33 -0500148 EXPECT_THROW(runToStop(), sdbusplus::exception::UnhandledStop);
Patrick Williams10483c92022-09-23 11:33:39 -0500149 EXPECT_NO_THROW(ctx->run());
Patrick Williams1b7b54c2022-09-21 10:49:45 -0500150 EXPECT_FALSE(ran);
151}