blob: fd8988f12a4aa94321da6cc33c5193a680d13bd8 [file] [log] [blame]
William A. Kennington IIIaf60e632019-01-16 15:00:18 -08001#include "watchdog.hpp"
Patrick Venture8f6c5152018-09-11 17:45:33 -07002
William A. Kennington IIId1331082018-02-27 18:47:05 -08003#include <memory>
William A. Kennington IIIf505fc02018-09-12 18:30:09 -07004#include <thread>
William A. Kennington IIId1331082018-02-27 18:47:05 -08005#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
William A. Kennington IIIf505fc02018-09-12 18:30:09 -070018 constexpr auto sleepTime = 1s;
19 if (event.run(sleepTime) == 0)
William A. Kennington III99c69de2018-03-01 10:59:22 -080020 {
21 ret += sleepTime;
22 }
23 }
24
25 return ret;
26}
27
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +053028/** @brief Make sure that watchdog is started and not enabled */
29TEST_F(WdogTest, createWdogAndDontEnable)
30{
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -080031 EXPECT_FALSE(wdog->enabled());
32 EXPECT_EQ(0, wdog->timeRemaining());
33 EXPECT_FALSE(wdog->timerExpired());
William A. Kennington III0650a3f2018-03-01 10:53:25 -080034 EXPECT_FALSE(wdog->timerEnabled());
William A. Kennington III25c1b202018-03-01 11:00:19 -080035
36 // We should be able to configure persistent properties
37 // while disabled
38 auto newAction = Watchdog::Action::PowerOff;
39 EXPECT_EQ(newAction, wdog->expireAction(newAction));
40 auto newIntervalMs = milliseconds(defaultInterval * 2).count();
41 EXPECT_EQ(newIntervalMs, wdog->interval(newIntervalMs));
42
43 EXPECT_EQ(newAction, wdog->expireAction());
44 EXPECT_EQ(newIntervalMs, wdog->interval());
45
46 // We won't be able to configure timeRemaining
47 EXPECT_EQ(0, wdog->timeRemaining(1000));
48 EXPECT_EQ(0, wdog->timeRemaining());
49
50 // Timer should not have become enabled
51 EXPECT_FALSE(wdog->enabled());
52 EXPECT_EQ(0, wdog->timeRemaining());
53 EXPECT_FALSE(wdog->timerExpired());
54 EXPECT_FALSE(wdog->timerEnabled());
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +053055}
56
57/** @brief Make sure that watchdog is started and enabled */
58TEST_F(WdogTest, createWdogAndEnable)
59{
60 // Enable and then verify
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -080061 EXPECT_TRUE(wdog->enabled(true));
62 EXPECT_FALSE(wdog->timerExpired());
William A. Kennington III0650a3f2018-03-01 10:53:25 -080063 EXPECT_TRUE(wdog->timerEnabled());
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +053064
65 // Get the configured interval
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -080066 auto remaining = milliseconds(wdog->timeRemaining());
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +053067
68 // Its possible that we are off by few msecs depending on
69 // how we get scheduled. So checking a range here.
70 EXPECT_TRUE((remaining >= defaultInterval - defaultDrift) &&
71 (remaining <= defaultInterval));
72
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -080073 EXPECT_FALSE(wdog->timerExpired());
William A. Kennington III0650a3f2018-03-01 10:53:25 -080074 EXPECT_TRUE(wdog->timerEnabled());
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +053075}
76
77/** @brief Make sure that watchdog is started and enabled.
78 * Later, disable watchdog
79 */
80TEST_F(WdogTest, createWdogAndEnableThenDisable)
81{
82 // Enable and then verify
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -080083 EXPECT_TRUE(wdog->enabled(true));
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +053084
85 // Disable and then verify
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -080086 EXPECT_FALSE(wdog->enabled(false));
87 EXPECT_FALSE(wdog->enabled());
88 EXPECT_EQ(0, wdog->timeRemaining());
William A. Kennington III0650a3f2018-03-01 10:53:25 -080089 EXPECT_FALSE(wdog->timerExpired());
90 EXPECT_FALSE(wdog->timerEnabled());
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +053091}
92
93/** @brief Make sure that watchdog is started and enabled.
94 * Wait for 5 seconds and make sure that the remaining
95 * time shows 25 seconds.
96 */
97TEST_F(WdogTest, enableWdogAndWait5Seconds)
98{
99 // Enable and then verify
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -0800100 EXPECT_TRUE(wdog->enabled(true));
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530101
102 // Sleep for 5 seconds
William A. Kennington III8cd38392018-03-01 11:07:36 -0800103 auto sleepTime = 5s;
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530104 std::this_thread::sleep_for(sleepTime);
105
106 // Get the remaining time again and expectation is that we get 25s
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -0800107 auto remaining = milliseconds(wdog->timeRemaining());
William A. Kennington III8cd38392018-03-01 11:07:36 -0800108 auto expected = defaultInterval - sleepTime;
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530109
110 // Its possible that we are off by few msecs depending on
111 // how we get scheduled. So checking a range here.
112 EXPECT_TRUE((remaining >= expected - defaultDrift) &&
113 (remaining <= expected));
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -0800114 EXPECT_FALSE(wdog->timerExpired());
William A. Kennington III0650a3f2018-03-01 10:53:25 -0800115 EXPECT_TRUE(wdog->timerEnabled());
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530116}
117
118/** @brief Make sure that watchdog is started and enabled.
119 * Wait 1 second and then reset the timer to 5 seconds
120 * and then expect the watchdog to expire in 5 seconds
121 */
122TEST_F(WdogTest, enableWdogAndResetTo5Seconds)
123{
124 // Enable and then verify
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -0800125 EXPECT_TRUE(wdog->enabled(true));
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530126
127 // Sleep for 1 second
128 std::this_thread::sleep_for(1s);
129
William A. Kennington IIIf505fc02018-09-12 18:30:09 -0700130 // Timer should still be running unexpired
131 EXPECT_FALSE(wdog->timerExpired());
132 EXPECT_TRUE(wdog->timerEnabled());
133
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530134 // Next timer will expire in 5 seconds from now.
William A. Kennington III8cd38392018-03-01 11:07:36 -0800135 auto expireTime = 5s;
136 auto expireTimeMs = milliseconds(expireTime).count();
137 EXPECT_EQ(expireTimeMs, wdog->timeRemaining(expireTimeMs));
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530138
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530139 // Waiting for expiration
William A. Kennington III99c69de2018-03-01 10:59:22 -0800140 EXPECT_EQ(expireTime - 1s, waitForWatchdog(expireTime));
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -0800141 EXPECT_TRUE(wdog->timerExpired());
William A. Kennington III0650a3f2018-03-01 10:53:25 -0800142 EXPECT_FALSE(wdog->timerEnabled());
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
William A. Kennington IIId4cbc5a2018-09-24 14:23:05 -0700157/** @brief Make sure the Interval can be updated while the timer is running.
158 */
159TEST_F(WdogTest, verifyIntervalUpdateRunning)
160{
161 const auto oldInterval = milliseconds(wdog->interval());
162 const auto newInterval = 5s;
163
164 EXPECT_TRUE(wdog->enabled(true));
165 auto remaining = milliseconds(wdog->timeRemaining());
166 EXPECT_GE(oldInterval, remaining);
167 EXPECT_LE(oldInterval - defaultDrift, remaining);
168 EXPECT_EQ(newInterval,
169 milliseconds(wdog->interval(milliseconds(newInterval).count())));
170
171 // Expect only the interval to update
172 remaining = milliseconds(wdog->timeRemaining());
173 EXPECT_GE(oldInterval, remaining);
174 EXPECT_LE(oldInterval - defaultDrift, remaining);
175 EXPECT_EQ(newInterval, milliseconds(wdog->interval()));
176
177 // Expect reset to use the new interval
178 wdog->resetTimeRemaining(false);
179 remaining = milliseconds(wdog->timeRemaining());
180 EXPECT_GE(newInterval, remaining);
181 EXPECT_LE(newInterval - defaultDrift, remaining);
182}
183
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530184/** @brief Make sure that watchdog is started and enabled.
185 * Wait default interval seconds and make sure that wdog has died
186 */
187TEST_F(WdogTest, enableWdogAndWaitTillEnd)
188{
189 // Enable and then verify
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -0800190 EXPECT_TRUE(wdog->enabled(true));
William A. Kennington III8cd38392018-03-01 11:07:36 -0800191 auto expireTime = duration_cast<seconds>(defaultInterval);
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530192
193 // Waiting default expiration
William A. Kennington III99c69de2018-03-01 10:59:22 -0800194 EXPECT_EQ(expireTime - 1s, waitForWatchdog(expireTime));
195
William A. Kennington III825f4982018-02-27 19:10:56 -0800196 EXPECT_FALSE(wdog->enabled());
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -0800197 EXPECT_EQ(0, wdog->timeRemaining());
198 EXPECT_TRUE(wdog->timerExpired());
William A. Kennington III0650a3f2018-03-01 10:53:25 -0800199 EXPECT_FALSE(wdog->timerEnabled());
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530200}
William A. Kennington IIId1331082018-02-27 18:47:05 -0800201
202/** @brief Make sure the watchdog is started and enabled with a fallback
203 * Wait through the initial trip and ensure the fallback is observed
204 * Make sure that fallback runs to completion and ensure the watchdog
205 * is disabled
206 */
207TEST_F(WdogTest, enableWdogWithFallbackTillEnd)
208{
209 auto primaryInterval = 5s;
210 auto primaryIntervalMs = milliseconds(primaryInterval).count();
211 auto fallbackInterval = primaryInterval * 2;
212 auto fallbackIntervalMs = milliseconds(fallbackInterval).count();
213
214 // We need to make a wdog with the right fallback options
215 // The interval is set to be noticeably different from the default
216 // so we can always tell the difference
William A. Kennington III8cf5f642019-01-16 16:58:14 -0800217 Watchdog::Fallback fallback;
218 fallback.action = Watchdog::Action::PowerOff;
219 fallback.interval = static_cast<uint64_t>(fallbackIntervalMs);
220 fallback.always = false;
William A. Kennington IIIf505fc02018-09-12 18:30:09 -0700221 wdog = std::make_unique<Watchdog>(bus, TEST_PATH, event,
William A. Kennington III3bb2f402018-09-13 00:35:47 -0700222 Watchdog::ActionTargetMap(),
Patrick Venture8f6c5152018-09-11 17:45:33 -0700223 std::move(fallback));
William A. Kennington IIId1331082018-02-27 18:47:05 -0800224 EXPECT_EQ(primaryInterval, milliseconds(wdog->interval(primaryIntervalMs)));
225 EXPECT_FALSE(wdog->enabled());
226 EXPECT_EQ(0, wdog->timeRemaining());
227
228 // Enable and then verify
229 EXPECT_TRUE(wdog->enabled(true));
230
231 // Waiting default expiration
232 EXPECT_EQ(primaryInterval - 1s, waitForWatchdog(primaryInterval));
233
234 // We should now have entered the fallback once the primary expires
235 EXPECT_FALSE(wdog->enabled());
236 auto remaining = milliseconds(wdog->timeRemaining());
237 EXPECT_GE(fallbackInterval, remaining);
238 EXPECT_LT(primaryInterval, remaining);
239 EXPECT_FALSE(wdog->timerExpired());
240 EXPECT_TRUE(wdog->timerEnabled());
241
242 // We should still be ticking in fallback when setting action or interval
243 auto newInterval = primaryInterval - 1s;
244 auto newIntervalMs = milliseconds(newInterval).count();
245 EXPECT_EQ(newInterval, milliseconds(wdog->interval(newIntervalMs)));
246 EXPECT_EQ(Watchdog::Action::None,
Patrick Venture8f6c5152018-09-11 17:45:33 -0700247 wdog->expireAction(Watchdog::Action::None));
William A. Kennington IIId1331082018-02-27 18:47:05 -0800248
249 EXPECT_FALSE(wdog->enabled());
250 EXPECT_GE(remaining, milliseconds(wdog->timeRemaining()));
251 EXPECT_LT(primaryInterval, milliseconds(wdog->timeRemaining()));
252 EXPECT_FALSE(wdog->timerExpired());
253 EXPECT_TRUE(wdog->timerEnabled());
254
255 // Test that setting the timeRemaining always resets the timer to the
256 // fallback interval
257 EXPECT_EQ(fallback.interval, wdog->timeRemaining(primaryInterval.count()));
258 EXPECT_FALSE(wdog->enabled());
259
260 remaining = milliseconds(wdog->timeRemaining());
261 EXPECT_GE(fallbackInterval, remaining);
262 EXPECT_LE(fallbackInterval - defaultDrift, remaining);
263 EXPECT_FALSE(wdog->timerExpired());
264 EXPECT_TRUE(wdog->timerEnabled());
265
266 // Waiting fallback expiration
267 EXPECT_EQ(fallbackInterval - 1s, waitForWatchdog(fallbackInterval));
268
269 // We should now have disabled the watchdog after the fallback expires
270 EXPECT_FALSE(wdog->enabled());
271 EXPECT_EQ(0, wdog->timeRemaining());
272 EXPECT_TRUE(wdog->timerExpired());
273 EXPECT_FALSE(wdog->timerEnabled());
274
275 // Make sure enabling the watchdog again works
276 EXPECT_TRUE(wdog->enabled(true));
277
278 // We should have re-entered the primary
279 EXPECT_TRUE(wdog->enabled());
280 EXPECT_GE(primaryInterval, milliseconds(wdog->timeRemaining()));
281 EXPECT_FALSE(wdog->timerExpired());
282 EXPECT_TRUE(wdog->timerEnabled());
283}
284
285/** @brief Make sure the watchdog is started and enabled with a fallback
286 * Wait through the initial trip and ensure the fallback is observed
287 * Make sure that we can re-enable the watchdog during fallback
288 */
289TEST_F(WdogTest, enableWdogWithFallbackReEnable)
290{
291 auto primaryInterval = 5s;
292 auto primaryIntervalMs = milliseconds(primaryInterval).count();
293 auto fallbackInterval = primaryInterval * 2;
294 auto fallbackIntervalMs = milliseconds(fallbackInterval).count();
295
296 // We need to make a wdog with the right fallback options
297 // The interval is set to be noticeably different from the default
298 // so we can always tell the difference
William A. Kennington III8cf5f642019-01-16 16:58:14 -0800299 Watchdog::Fallback fallback;
300 fallback.action = Watchdog::Action::PowerOff;
301 fallback.interval = static_cast<uint64_t>(fallbackIntervalMs);
302 fallback.always = false;
William A. Kennington IIIf505fc02018-09-12 18:30:09 -0700303 wdog = std::make_unique<Watchdog>(bus, TEST_PATH, event,
William A. Kennington III3bb2f402018-09-13 00:35:47 -0700304 Watchdog::ActionTargetMap(),
Patrick Venture8f6c5152018-09-11 17:45:33 -0700305 std::move(fallback));
William A. Kennington IIId1331082018-02-27 18:47:05 -0800306 EXPECT_EQ(primaryInterval, milliseconds(wdog->interval(primaryIntervalMs)));
307 EXPECT_FALSE(wdog->enabled());
308 EXPECT_EQ(0, wdog->timeRemaining());
309 EXPECT_FALSE(wdog->timerExpired());
310 EXPECT_FALSE(wdog->timerEnabled());
311
312 // Enable and then verify
313 EXPECT_TRUE(wdog->enabled(true));
314
315 // Waiting default expiration
316 EXPECT_EQ(primaryInterval - 1s, waitForWatchdog(primaryInterval));
317
318 // We should now have entered the fallback once the primary expires
319 EXPECT_FALSE(wdog->enabled());
320 auto remaining = milliseconds(wdog->timeRemaining());
321 EXPECT_GE(fallbackInterval, remaining);
322 EXPECT_LT(primaryInterval, remaining);
323 EXPECT_FALSE(wdog->timerExpired());
324 EXPECT_TRUE(wdog->timerEnabled());
325
326 EXPECT_TRUE(wdog->enabled(true));
327
328 // We should have re-entered the primary
329 EXPECT_TRUE(wdog->enabled());
330 EXPECT_GE(primaryInterval, milliseconds(wdog->timeRemaining()));
331 EXPECT_FALSE(wdog->timerExpired());
332 EXPECT_TRUE(wdog->timerEnabled());
333}
William A. Kennington III22352192018-02-27 18:51:44 -0800334
335/** @brief Make sure the watchdog is started and with a fallback without
336 * sending an enable
337 * Then enable the watchdog
338 * Wait through the initial trip and ensure the fallback is observed
339 * Make sure that fallback runs to completion and ensure the watchdog
340 * is in the fallback state again
341 */
342TEST_F(WdogTest, enableWdogWithFallbackAlways)
343{
344 auto primaryInterval = 5s;
345 auto primaryIntervalMs = milliseconds(primaryInterval).count();
346 auto fallbackInterval = primaryInterval * 2;
347 auto fallbackIntervalMs = milliseconds(fallbackInterval).count();
348
349 // We need to make a wdog with the right fallback options
350 // The interval is set to be noticeably different from the default
351 // so we can always tell the difference
William A. Kennington III8cf5f642019-01-16 16:58:14 -0800352 Watchdog::Fallback fallback;
353 fallback.action = Watchdog::Action::PowerOff;
354 fallback.interval = static_cast<uint64_t>(fallbackIntervalMs);
355 fallback.always = true;
William A. Kennington IIIf505fc02018-09-12 18:30:09 -0700356 wdog = std::make_unique<Watchdog>(bus, TEST_PATH, event,
William A. Kennington III3bb2f402018-09-13 00:35:47 -0700357 Watchdog::ActionTargetMap(),
Patrick Venture8f6c5152018-09-11 17:45:33 -0700358 std::move(fallback));
William A. Kennington III22352192018-02-27 18:51:44 -0800359 EXPECT_EQ(primaryInterval, milliseconds(wdog->interval(primaryIntervalMs)));
360 EXPECT_FALSE(wdog->enabled());
361 auto remaining = milliseconds(wdog->timeRemaining());
362 EXPECT_GE(fallbackInterval, remaining);
363 EXPECT_LT(primaryInterval, remaining);
364 EXPECT_FALSE(wdog->timerExpired());
365 EXPECT_TRUE(wdog->timerEnabled());
366
367 // Enable and then verify
368 EXPECT_TRUE(wdog->enabled(true));
369 EXPECT_GE(primaryInterval, milliseconds(wdog->timeRemaining()));
370
371 // Waiting default expiration
372 EXPECT_EQ(primaryInterval - 1s, waitForWatchdog(primaryInterval));
373
374 // We should now have entered the fallback once the primary expires
375 EXPECT_FALSE(wdog->enabled());
376 remaining = milliseconds(wdog->timeRemaining());
377 EXPECT_GE(fallbackInterval, remaining);
378 EXPECT_LT(primaryInterval, remaining);
379 EXPECT_FALSE(wdog->timerExpired());
380 EXPECT_TRUE(wdog->timerEnabled());
381
382 // Waiting fallback expiration
383 EXPECT_EQ(fallbackInterval - 1s, waitForWatchdog(fallbackInterval));
384
385 // We should now enter the fallback again
386 EXPECT_FALSE(wdog->enabled());
387 remaining = milliseconds(wdog->timeRemaining());
388 EXPECT_GE(fallbackInterval, remaining);
389 EXPECT_LT(primaryInterval, remaining);
390 EXPECT_FALSE(wdog->timerExpired());
391 EXPECT_TRUE(wdog->timerEnabled());
392}