1 #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 8 namespace sdbusplus::async 9 { 10 struct 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 29 struct 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 53 TEST_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 81 TEST_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 101