blob: 9ab96047cc11cc2f6f3a620d43f9e91fbfbbc58a [file] [log] [blame]
Patrick Williamsbc139972025-07-08 16:46:50 -04001#include <sdbusplus/async.hpp>
2#include <sdbusplus/bus.hpp>
3#include <sdbusplus/test/sdbus_mock.hpp>
4
5#include <gmock/gmock.h>
6#include <gtest/gtest.h>
7
8namespace sdbusplus::async
9{
10struct WatchdogMock : public sdbusplus::SdBusImpl
11{
12 WatchdogMock() : sdbusplus::SdBusImpl()
13 {
14 sd_bus_open(&busp);
15 }
16
17 ~WatchdogMock()
18 {
19 sd_bus_unref(busp);
20 }
21
22 MOCK_METHOD(int, sd_notify, (int, const char*), (override));
23
24 MOCK_METHOD(int, sd_watchdog_enabled, (int, uint64_t* usec), (override));
25
26 sdbusplus::bus::busp_t busp = nullptr;
27};
28
29struct WatchdogContext : public testing::Test
30{
31 WatchdogMock sdbusMock;
32 sdbusplus::async::context ctx;
33
34 WatchdogContext() : ctx(sdbusplus::bus_t(sdbusMock.busp, &sdbusMock)) {}
35
36 ~WatchdogContext() noexcept override = default;
37
38 void TearDown() override {}
39
40 void spawnStop()
41 {
42 ctx.spawn(stdexec::just() |
43 stdexec::then([this]() { ctx.request_stop(); }));
44 }
45
46 void runToStop()
47 {
48 spawnStop();
49 ctx.run();
50 }
51};
52
53TEST_F(WatchdogContext, WatchdogEnabledAndHeartbeat)
54{
55 using namespace testing;
56 using namespace std::literals;
57
58 // Expect sd_watchdog_enabled to be called once and return .1 second
59 EXPECT_CALL(sdbusMock, sd_watchdog_enabled(_, _))
60 .WillOnce([](int, uint64_t* usec) {
61 *usec = 100000; // .1 second
62 return 0;
63 });
64
65 // Expect sd_notify to be called at least once for heartbeat
66 // The watchdog_loop divides the time by 2, so it should be
67 // called every 0.05 seconds.
68 EXPECT_CALL(sdbusMock, sd_notify(_, StrEq("WATCHDOG=1")))
69 .WillRepeatedly(Return(0));
70
71 // Run the context for a short period to allow watchdog_loop to execute
72 // and send a handful of heartbeats.
73 ctx.spawn(sdbusplus::async::sleep_for(ctx, 1s));
74 runToStop();
75
76 // The EXPECT_CALL for sd_notify will verify if it was called as expected.
77 // If the test passes, it means sd_watchdog_enabled was called,
78 // and sd_notify was called for heartbeats.
79}
80
81TEST_F(WatchdogContext, WatchdogDisabled)
82{
83 using namespace testing;
84 using namespace std::literals;
85
86 // Expect sd_watchdog_enabled to be called once and return 0 (disabled)
87 EXPECT_CALL(sdbusMock, sd_watchdog_enabled(_, _))
88 .WillOnce([](int, uint64_t* usec) {
89 *usec = 0; // Watchdog disabled
90 return 0;
91 });
92
93 // Expect sd_notify will NOT be called
94 EXPECT_CALL(sdbusMock, sd_notify(_, _)).Times(0);
95
96 // Run the context. No sleep is needed as watchdog should exit immediately.
97 runToStop();
98}
99
100} // namespace sdbusplus::async