blob: f24d45e71e0844a9d67284ad33834c4e5417b9d1 [file] [log] [blame]
Patrick Venture8f6c5152018-09-11 17:45:33 -07001#include "watchdog_test.hpp"
2
William A. Kennington III99c69de2018-03-01 10:59:22 -08003#include <chrono>
William A. Kennington IIId1331082018-02-27 18:47:05 -08004#include <memory>
5#include <utility>
William A. Kennington III99c69de2018-03-01 10:59:22 -08006
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +05307using namespace phosphor::watchdog;
8
William A. Kennington III99c69de2018-03-01 10:59:22 -08009seconds WdogTest::waitForWatchdog(seconds timeLimit)
10{
11 auto previousTimeRemaining = wdog->timeRemaining();
12 auto ret = 0s;
Patrick Venture8f6c5152018-09-11 17:45:33 -070013 while (ret < timeLimit && previousTimeRemaining >= wdog->timeRemaining() &&
William A. Kennington III99c69de2018-03-01 10:59:22 -080014 wdog->timerEnabled())
15 {
16 previousTimeRemaining = wdog->timeRemaining();
17
18 // Returns -0- on timeout and positive number on dispatch
19 auto sleepTime = 1s;
Patrick Venture8f6c5152018-09-11 17:45:33 -070020 if (!sd_event_run(eventP.get(), microseconds(sleepTime).count()))
William A. Kennington III99c69de2018-03-01 10:59:22 -080021 {
22 ret += sleepTime;
23 }
24 }
25
26 return ret;
27}
28
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +053029/** @brief Make sure that watchdog is started and not enabled */
30TEST_F(WdogTest, createWdogAndDontEnable)
31{
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -080032 EXPECT_FALSE(wdog->enabled());
33 EXPECT_EQ(0, wdog->timeRemaining());
34 EXPECT_FALSE(wdog->timerExpired());
William A. Kennington III0650a3f2018-03-01 10:53:25 -080035 EXPECT_FALSE(wdog->timerEnabled());
William A. Kennington III25c1b202018-03-01 11:00:19 -080036
37 // We should be able to configure persistent properties
38 // while disabled
39 auto newAction = Watchdog::Action::PowerOff;
40 EXPECT_EQ(newAction, wdog->expireAction(newAction));
41 auto newIntervalMs = milliseconds(defaultInterval * 2).count();
42 EXPECT_EQ(newIntervalMs, wdog->interval(newIntervalMs));
43
44 EXPECT_EQ(newAction, wdog->expireAction());
45 EXPECT_EQ(newIntervalMs, wdog->interval());
46
47 // We won't be able to configure timeRemaining
48 EXPECT_EQ(0, wdog->timeRemaining(1000));
49 EXPECT_EQ(0, wdog->timeRemaining());
50
51 // Timer should not have become enabled
52 EXPECT_FALSE(wdog->enabled());
53 EXPECT_EQ(0, wdog->timeRemaining());
54 EXPECT_FALSE(wdog->timerExpired());
55 EXPECT_FALSE(wdog->timerEnabled());
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +053056}
57
58/** @brief Make sure that watchdog is started and enabled */
59TEST_F(WdogTest, createWdogAndEnable)
60{
61 // Enable and then verify
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -080062 EXPECT_TRUE(wdog->enabled(true));
63 EXPECT_FALSE(wdog->timerExpired());
William A. Kennington III0650a3f2018-03-01 10:53:25 -080064 EXPECT_TRUE(wdog->timerEnabled());
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +053065
66 // Get the configured interval
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -080067 auto remaining = milliseconds(wdog->timeRemaining());
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +053068
69 // Its possible that we are off by few msecs depending on
70 // how we get scheduled. So checking a range here.
71 EXPECT_TRUE((remaining >= defaultInterval - defaultDrift) &&
72 (remaining <= defaultInterval));
73
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -080074 EXPECT_FALSE(wdog->timerExpired());
William A. Kennington III0650a3f2018-03-01 10:53:25 -080075 EXPECT_TRUE(wdog->timerEnabled());
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +053076}
77
78/** @brief Make sure that watchdog is started and enabled.
79 * Later, disable watchdog
80 */
81TEST_F(WdogTest, createWdogAndEnableThenDisable)
82{
83 // Enable and then verify
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -080084 EXPECT_TRUE(wdog->enabled(true));
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +053085
86 // Disable and then verify
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -080087 EXPECT_FALSE(wdog->enabled(false));
88 EXPECT_FALSE(wdog->enabled());
89 EXPECT_EQ(0, wdog->timeRemaining());
William A. Kennington III0650a3f2018-03-01 10:53:25 -080090 EXPECT_FALSE(wdog->timerExpired());
91 EXPECT_FALSE(wdog->timerEnabled());
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +053092}
93
94/** @brief Make sure that watchdog is started and enabled.
95 * Wait for 5 seconds and make sure that the remaining
96 * time shows 25 seconds.
97 */
98TEST_F(WdogTest, enableWdogAndWait5Seconds)
99{
100 // Enable and then verify
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -0800101 EXPECT_TRUE(wdog->enabled(true));
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530102
103 // Sleep for 5 seconds
William A. Kennington III8cd38392018-03-01 11:07:36 -0800104 auto sleepTime = 5s;
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530105 std::this_thread::sleep_for(sleepTime);
106
107 // Get the remaining time again and expectation is that we get 25s
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -0800108 auto remaining = milliseconds(wdog->timeRemaining());
William A. Kennington III8cd38392018-03-01 11:07:36 -0800109 auto expected = defaultInterval - sleepTime;
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530110
111 // Its possible that we are off by few msecs depending on
112 // how we get scheduled. So checking a range here.
113 EXPECT_TRUE((remaining >= expected - defaultDrift) &&
114 (remaining <= expected));
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -0800115 EXPECT_FALSE(wdog->timerExpired());
William A. Kennington III0650a3f2018-03-01 10:53:25 -0800116 EXPECT_TRUE(wdog->timerEnabled());
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530117}
118
119/** @brief Make sure that watchdog is started and enabled.
120 * Wait 1 second and then reset the timer to 5 seconds
121 * and then expect the watchdog to expire in 5 seconds
122 */
123TEST_F(WdogTest, enableWdogAndResetTo5Seconds)
124{
125 // Enable and then verify
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -0800126 EXPECT_TRUE(wdog->enabled(true));
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530127
128 // Sleep for 1 second
129 std::this_thread::sleep_for(1s);
130
131 // Next timer will expire in 5 seconds from now.
William A. Kennington III8cd38392018-03-01 11:07:36 -0800132 auto expireTime = 5s;
133 auto expireTimeMs = milliseconds(expireTime).count();
134 EXPECT_EQ(expireTimeMs, wdog->timeRemaining(expireTimeMs));
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530135
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530136 // Waiting for expiration
William A. Kennington III99c69de2018-03-01 10:59:22 -0800137 EXPECT_EQ(expireTime - 1s, waitForWatchdog(expireTime));
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -0800138 EXPECT_TRUE(wdog->timerExpired());
William A. Kennington III0650a3f2018-03-01 10:53:25 -0800139 EXPECT_FALSE(wdog->timerEnabled());
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530140
141 // Make sure secondary callback was not called.
William A. Kennington IIId5d14832018-02-28 09:54:08 -0800142 EXPECT_FALSE(expired);
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530143}
144
Gunnar Millsbfe5cb82017-10-25 20:48:50 -0500145/** @brief Make sure the Interval can be updated directly.
Patrick Venture96816342017-08-17 12:32:22 -0700146 */
147TEST_F(WdogTest, verifyIntervalUpdateReceived)
148{
William A. Kennington III8cd38392018-03-01 11:07:36 -0800149 auto expireTime = 5s;
150 auto expireTimeMs = milliseconds(expireTime).count();
151 EXPECT_EQ(expireTimeMs, wdog->interval(expireTimeMs));
Patrick Venture96816342017-08-17 12:32:22 -0700152
153 // Expect an update in the Interval
William A. Kennington III8cd38392018-03-01 11:07:36 -0800154 EXPECT_EQ(expireTimeMs, wdog->interval());
Patrick Venture96816342017-08-17 12:32:22 -0700155}
156
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530157/** @brief Make sure that watchdog is started and enabled.
158 * Wait default interval seconds and make sure that wdog has died
159 */
160TEST_F(WdogTest, enableWdogAndWaitTillEnd)
161{
162 // Enable and then verify
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -0800163 EXPECT_TRUE(wdog->enabled(true));
William A. Kennington III8cd38392018-03-01 11:07:36 -0800164 auto expireTime = duration_cast<seconds>(defaultInterval);
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530165
166 // Waiting default expiration
William A. Kennington III99c69de2018-03-01 10:59:22 -0800167 EXPECT_EQ(expireTime - 1s, waitForWatchdog(expireTime));
168
William A. Kennington III825f4982018-02-27 19:10:56 -0800169 EXPECT_FALSE(wdog->enabled());
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -0800170 EXPECT_EQ(0, wdog->timeRemaining());
171 EXPECT_TRUE(wdog->timerExpired());
William A. Kennington III0650a3f2018-03-01 10:53:25 -0800172 EXPECT_FALSE(wdog->timerEnabled());
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530173}
William A. Kennington IIId1331082018-02-27 18:47:05 -0800174
175/** @brief Make sure the watchdog is started and enabled with a fallback
176 * Wait through the initial trip and ensure the fallback is observed
177 * Make sure that fallback runs to completion and ensure the watchdog
178 * is disabled
179 */
180TEST_F(WdogTest, enableWdogWithFallbackTillEnd)
181{
182 auto primaryInterval = 5s;
183 auto primaryIntervalMs = milliseconds(primaryInterval).count();
184 auto fallbackInterval = primaryInterval * 2;
185 auto fallbackIntervalMs = milliseconds(fallbackInterval).count();
186
187 // We need to make a wdog with the right fallback options
188 // The interval is set to be noticeably different from the default
189 // so we can always tell the difference
190 Watchdog::Fallback fallback{
191 .action = Watchdog::Action::PowerOff,
192 .interval = static_cast<uint64_t>(fallbackIntervalMs),
193 };
194 std::map<Watchdog::Action, Watchdog::TargetName> emptyActionTargets;
195 wdog = std::make_unique<Watchdog>(bus, TEST_PATH, eventP,
Patrick Venture8f6c5152018-09-11 17:45:33 -0700196 std::move(emptyActionTargets),
197 std::move(fallback));
William A. Kennington IIId1331082018-02-27 18:47:05 -0800198 EXPECT_EQ(primaryInterval, milliseconds(wdog->interval(primaryIntervalMs)));
199 EXPECT_FALSE(wdog->enabled());
200 EXPECT_EQ(0, wdog->timeRemaining());
201
202 // Enable and then verify
203 EXPECT_TRUE(wdog->enabled(true));
204
205 // Waiting default expiration
206 EXPECT_EQ(primaryInterval - 1s, waitForWatchdog(primaryInterval));
207
208 // We should now have entered the fallback once the primary expires
209 EXPECT_FALSE(wdog->enabled());
210 auto remaining = milliseconds(wdog->timeRemaining());
211 EXPECT_GE(fallbackInterval, remaining);
212 EXPECT_LT(primaryInterval, remaining);
213 EXPECT_FALSE(wdog->timerExpired());
214 EXPECT_TRUE(wdog->timerEnabled());
215
216 // We should still be ticking in fallback when setting action or interval
217 auto newInterval = primaryInterval - 1s;
218 auto newIntervalMs = milliseconds(newInterval).count();
219 EXPECT_EQ(newInterval, milliseconds(wdog->interval(newIntervalMs)));
220 EXPECT_EQ(Watchdog::Action::None,
Patrick Venture8f6c5152018-09-11 17:45:33 -0700221 wdog->expireAction(Watchdog::Action::None));
William A. Kennington IIId1331082018-02-27 18:47:05 -0800222
223 EXPECT_FALSE(wdog->enabled());
224 EXPECT_GE(remaining, milliseconds(wdog->timeRemaining()));
225 EXPECT_LT(primaryInterval, milliseconds(wdog->timeRemaining()));
226 EXPECT_FALSE(wdog->timerExpired());
227 EXPECT_TRUE(wdog->timerEnabled());
228
229 // Test that setting the timeRemaining always resets the timer to the
230 // fallback interval
231 EXPECT_EQ(fallback.interval, wdog->timeRemaining(primaryInterval.count()));
232 EXPECT_FALSE(wdog->enabled());
233
234 remaining = milliseconds(wdog->timeRemaining());
235 EXPECT_GE(fallbackInterval, remaining);
236 EXPECT_LE(fallbackInterval - defaultDrift, remaining);
237 EXPECT_FALSE(wdog->timerExpired());
238 EXPECT_TRUE(wdog->timerEnabled());
239
240 // Waiting fallback expiration
241 EXPECT_EQ(fallbackInterval - 1s, waitForWatchdog(fallbackInterval));
242
243 // We should now have disabled the watchdog after the fallback expires
244 EXPECT_FALSE(wdog->enabled());
245 EXPECT_EQ(0, wdog->timeRemaining());
246 EXPECT_TRUE(wdog->timerExpired());
247 EXPECT_FALSE(wdog->timerEnabled());
248
249 // Make sure enabling the watchdog again works
250 EXPECT_TRUE(wdog->enabled(true));
251
252 // We should have re-entered the primary
253 EXPECT_TRUE(wdog->enabled());
254 EXPECT_GE(primaryInterval, milliseconds(wdog->timeRemaining()));
255 EXPECT_FALSE(wdog->timerExpired());
256 EXPECT_TRUE(wdog->timerEnabled());
257}
258
259/** @brief Make sure the watchdog is started and enabled with a fallback
260 * Wait through the initial trip and ensure the fallback is observed
261 * Make sure that we can re-enable the watchdog during fallback
262 */
263TEST_F(WdogTest, enableWdogWithFallbackReEnable)
264{
265 auto primaryInterval = 5s;
266 auto primaryIntervalMs = milliseconds(primaryInterval).count();
267 auto fallbackInterval = primaryInterval * 2;
268 auto fallbackIntervalMs = milliseconds(fallbackInterval).count();
269
270 // We need to make a wdog with the right fallback options
271 // The interval is set to be noticeably different from the default
272 // so we can always tell the difference
273 Watchdog::Fallback fallback{
274 .action = Watchdog::Action::PowerOff,
275 .interval = static_cast<uint64_t>(fallbackIntervalMs),
William A. Kennington III22352192018-02-27 18:51:44 -0800276 .always = false,
William A. Kennington IIId1331082018-02-27 18:47:05 -0800277 };
278 std::map<Watchdog::Action, Watchdog::TargetName> emptyActionTargets;
279 wdog = std::make_unique<Watchdog>(bus, TEST_PATH, eventP,
Patrick Venture8f6c5152018-09-11 17:45:33 -0700280 std::move(emptyActionTargets),
281 std::move(fallback));
William A. Kennington IIId1331082018-02-27 18:47:05 -0800282 EXPECT_EQ(primaryInterval, milliseconds(wdog->interval(primaryIntervalMs)));
283 EXPECT_FALSE(wdog->enabled());
284 EXPECT_EQ(0, wdog->timeRemaining());
285 EXPECT_FALSE(wdog->timerExpired());
286 EXPECT_FALSE(wdog->timerEnabled());
287
288 // Enable and then verify
289 EXPECT_TRUE(wdog->enabled(true));
290
291 // Waiting default expiration
292 EXPECT_EQ(primaryInterval - 1s, waitForWatchdog(primaryInterval));
293
294 // We should now have entered the fallback once the primary expires
295 EXPECT_FALSE(wdog->enabled());
296 auto remaining = milliseconds(wdog->timeRemaining());
297 EXPECT_GE(fallbackInterval, remaining);
298 EXPECT_LT(primaryInterval, remaining);
299 EXPECT_FALSE(wdog->timerExpired());
300 EXPECT_TRUE(wdog->timerEnabled());
301
302 EXPECT_TRUE(wdog->enabled(true));
303
304 // We should have re-entered the primary
305 EXPECT_TRUE(wdog->enabled());
306 EXPECT_GE(primaryInterval, milliseconds(wdog->timeRemaining()));
307 EXPECT_FALSE(wdog->timerExpired());
308 EXPECT_TRUE(wdog->timerEnabled());
309}
William A. Kennington III22352192018-02-27 18:51:44 -0800310
311/** @brief Make sure the watchdog is started and with a fallback without
312 * sending an enable
313 * Then enable the watchdog
314 * Wait through the initial trip and ensure the fallback is observed
315 * Make sure that fallback runs to completion and ensure the watchdog
316 * is in the fallback state again
317 */
318TEST_F(WdogTest, enableWdogWithFallbackAlways)
319{
320 auto primaryInterval = 5s;
321 auto primaryIntervalMs = milliseconds(primaryInterval).count();
322 auto fallbackInterval = primaryInterval * 2;
323 auto fallbackIntervalMs = milliseconds(fallbackInterval).count();
324
325 // We need to make a wdog with the right fallback options
326 // The interval is set to be noticeably different from the default
327 // so we can always tell the difference
328 Watchdog::Fallback fallback{
329 .action = Watchdog::Action::PowerOff,
330 .interval = static_cast<uint64_t>(fallbackIntervalMs),
331 .always = true,
332 };
333 std::map<Watchdog::Action, Watchdog::TargetName> emptyActionTargets;
334 wdog = std::make_unique<Watchdog>(bus, TEST_PATH, eventP,
Patrick Venture8f6c5152018-09-11 17:45:33 -0700335 std::move(emptyActionTargets),
336 std::move(fallback));
William A. Kennington III22352192018-02-27 18:51:44 -0800337 EXPECT_EQ(primaryInterval, milliseconds(wdog->interval(primaryIntervalMs)));
338 EXPECT_FALSE(wdog->enabled());
339 auto remaining = milliseconds(wdog->timeRemaining());
340 EXPECT_GE(fallbackInterval, remaining);
341 EXPECT_LT(primaryInterval, remaining);
342 EXPECT_FALSE(wdog->timerExpired());
343 EXPECT_TRUE(wdog->timerEnabled());
344
345 // Enable and then verify
346 EXPECT_TRUE(wdog->enabled(true));
347 EXPECT_GE(primaryInterval, milliseconds(wdog->timeRemaining()));
348
349 // Waiting default expiration
350 EXPECT_EQ(primaryInterval - 1s, waitForWatchdog(primaryInterval));
351
352 // We should now have entered the fallback once the primary expires
353 EXPECT_FALSE(wdog->enabled());
354 remaining = milliseconds(wdog->timeRemaining());
355 EXPECT_GE(fallbackInterval, remaining);
356 EXPECT_LT(primaryInterval, remaining);
357 EXPECT_FALSE(wdog->timerExpired());
358 EXPECT_TRUE(wdog->timerEnabled());
359
360 // Waiting fallback expiration
361 EXPECT_EQ(fallbackInterval - 1s, waitForWatchdog(fallbackInterval));
362
363 // We should now enter the fallback again
364 EXPECT_FALSE(wdog->enabled());
365 remaining = milliseconds(wdog->timeRemaining());
366 EXPECT_GE(fallbackInterval, remaining);
367 EXPECT_LT(primaryInterval, remaining);
368 EXPECT_FALSE(wdog->timerExpired());
369 EXPECT_TRUE(wdog->timerEnabled());
370}