blob: 34d1d247fd4105121bc44906eea118106457b4c3 [file] [log] [blame]
William A. Kennington III99c69de2018-03-01 10:59:22 -08001#include <chrono>
William A. Kennington IIId1331082018-02-27 18:47:05 -08002#include <memory>
3#include <utility>
William A. Kennington III99c69de2018-03-01 10:59:22 -08004
5#include "watchdog_test.hpp"
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +05306
7using 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;
13 while (ret < timeLimit &&
14 previousTimeRemaining >= wdog->timeRemaining() &&
15 wdog->timerEnabled())
16 {
17 previousTimeRemaining = wdog->timeRemaining();
18
19 // Returns -0- on timeout and positive number on dispatch
20 auto sleepTime = 1s;
21 if(!sd_event_run(eventP.get(), microseconds(sleepTime).count()))
22 {
23 ret += sleepTime;
24 }
25 }
26
27 return ret;
28}
29
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +053030/** @brief Make sure that watchdog is started and not enabled */
31TEST_F(WdogTest, createWdogAndDontEnable)
32{
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -080033 EXPECT_FALSE(wdog->enabled());
34 EXPECT_EQ(0, wdog->timeRemaining());
35 EXPECT_FALSE(wdog->timerExpired());
William A. Kennington III0650a3f2018-03-01 10:53:25 -080036 EXPECT_FALSE(wdog->timerEnabled());
William A. Kennington III25c1b202018-03-01 11:00:19 -080037
38 // We should be able to configure persistent properties
39 // while disabled
40 auto newAction = Watchdog::Action::PowerOff;
41 EXPECT_EQ(newAction, wdog->expireAction(newAction));
42 auto newIntervalMs = milliseconds(defaultInterval * 2).count();
43 EXPECT_EQ(newIntervalMs, wdog->interval(newIntervalMs));
44
45 EXPECT_EQ(newAction, wdog->expireAction());
46 EXPECT_EQ(newIntervalMs, wdog->interval());
47
48 // We won't be able to configure timeRemaining
49 EXPECT_EQ(0, wdog->timeRemaining(1000));
50 EXPECT_EQ(0, wdog->timeRemaining());
51
52 // Timer should not have become enabled
53 EXPECT_FALSE(wdog->enabled());
54 EXPECT_EQ(0, wdog->timeRemaining());
55 EXPECT_FALSE(wdog->timerExpired());
56 EXPECT_FALSE(wdog->timerEnabled());
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +053057}
58
59/** @brief Make sure that watchdog is started and enabled */
60TEST_F(WdogTest, createWdogAndEnable)
61{
62 // Enable and then verify
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -080063 EXPECT_TRUE(wdog->enabled(true));
64 EXPECT_FALSE(wdog->timerExpired());
William A. Kennington III0650a3f2018-03-01 10:53:25 -080065 EXPECT_TRUE(wdog->timerEnabled());
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +053066
67 // Get the configured interval
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -080068 auto remaining = milliseconds(wdog->timeRemaining());
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +053069
70 // Its possible that we are off by few msecs depending on
71 // how we get scheduled. So checking a range here.
72 EXPECT_TRUE((remaining >= defaultInterval - defaultDrift) &&
73 (remaining <= defaultInterval));
74
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -080075 EXPECT_FALSE(wdog->timerExpired());
William A. Kennington III0650a3f2018-03-01 10:53:25 -080076 EXPECT_TRUE(wdog->timerEnabled());
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +053077}
78
79/** @brief Make sure that watchdog is started and enabled.
80 * Later, disable watchdog
81 */
82TEST_F(WdogTest, createWdogAndEnableThenDisable)
83{
84 // Enable and then verify
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -080085 EXPECT_TRUE(wdog->enabled(true));
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +053086
87 // Disable and then verify
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -080088 EXPECT_FALSE(wdog->enabled(false));
89 EXPECT_FALSE(wdog->enabled());
90 EXPECT_EQ(0, wdog->timeRemaining());
William A. Kennington III0650a3f2018-03-01 10:53:25 -080091 EXPECT_FALSE(wdog->timerExpired());
92 EXPECT_FALSE(wdog->timerEnabled());
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +053093}
94
95/** @brief Make sure that watchdog is started and enabled.
96 * Wait for 5 seconds and make sure that the remaining
97 * time shows 25 seconds.
98 */
99TEST_F(WdogTest, enableWdogAndWait5Seconds)
100{
101 // Enable and then verify
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -0800102 EXPECT_TRUE(wdog->enabled(true));
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530103
104 // Sleep for 5 seconds
William A. Kennington III8cd38392018-03-01 11:07:36 -0800105 auto sleepTime = 5s;
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530106 std::this_thread::sleep_for(sleepTime);
107
108 // Get the remaining time again and expectation is that we get 25s
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -0800109 auto remaining = milliseconds(wdog->timeRemaining());
William A. Kennington III8cd38392018-03-01 11:07:36 -0800110 auto expected = defaultInterval - sleepTime;
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530111
112 // Its possible that we are off by few msecs depending on
113 // how we get scheduled. So checking a range here.
114 EXPECT_TRUE((remaining >= expected - defaultDrift) &&
115 (remaining <= expected));
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -0800116 EXPECT_FALSE(wdog->timerExpired());
William A. Kennington III0650a3f2018-03-01 10:53:25 -0800117 EXPECT_TRUE(wdog->timerEnabled());
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530118}
119
120/** @brief Make sure that watchdog is started and enabled.
121 * Wait 1 second and then reset the timer to 5 seconds
122 * and then expect the watchdog to expire in 5 seconds
123 */
124TEST_F(WdogTest, enableWdogAndResetTo5Seconds)
125{
126 // Enable and then verify
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -0800127 EXPECT_TRUE(wdog->enabled(true));
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530128
129 // Sleep for 1 second
130 std::this_thread::sleep_for(1s);
131
132 // Next timer will expire in 5 seconds from now.
William A. Kennington III8cd38392018-03-01 11:07:36 -0800133 auto expireTime = 5s;
134 auto expireTimeMs = milliseconds(expireTime).count();
135 EXPECT_EQ(expireTimeMs, wdog->timeRemaining(expireTimeMs));
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530136
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530137 // Waiting for expiration
William A. Kennington III99c69de2018-03-01 10:59:22 -0800138 EXPECT_EQ(expireTime - 1s, waitForWatchdog(expireTime));
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -0800139 EXPECT_TRUE(wdog->timerExpired());
William A. Kennington III0650a3f2018-03-01 10:53:25 -0800140 EXPECT_FALSE(wdog->timerEnabled());
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530141
142 // Make sure secondary callback was not called.
William A. Kennington IIId5d14832018-02-28 09:54:08 -0800143 EXPECT_FALSE(expired);
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530144}
145
Gunnar Millsbfe5cb82017-10-25 20:48:50 -0500146/** @brief Make sure the Interval can be updated directly.
Patrick Venture96816342017-08-17 12:32:22 -0700147 */
148TEST_F(WdogTest, verifyIntervalUpdateReceived)
149{
William A. Kennington III8cd38392018-03-01 11:07:36 -0800150 auto expireTime = 5s;
151 auto expireTimeMs = milliseconds(expireTime).count();
152 EXPECT_EQ(expireTimeMs, wdog->interval(expireTimeMs));
Patrick Venture96816342017-08-17 12:32:22 -0700153
154 // Expect an update in the Interval
William A. Kennington III8cd38392018-03-01 11:07:36 -0800155 EXPECT_EQ(expireTimeMs, wdog->interval());
Patrick Venture96816342017-08-17 12:32:22 -0700156}
157
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530158/** @brief Make sure that watchdog is started and enabled.
159 * Wait default interval seconds and make sure that wdog has died
160 */
161TEST_F(WdogTest, enableWdogAndWaitTillEnd)
162{
163 // Enable and then verify
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -0800164 EXPECT_TRUE(wdog->enabled(true));
William A. Kennington III8cd38392018-03-01 11:07:36 -0800165 auto expireTime = duration_cast<seconds>(defaultInterval);
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530166
167 // Waiting default expiration
William A. Kennington III99c69de2018-03-01 10:59:22 -0800168 EXPECT_EQ(expireTime - 1s, waitForWatchdog(expireTime));
169
William A. Kennington III825f4982018-02-27 19:10:56 -0800170 EXPECT_FALSE(wdog->enabled());
William A. Kennington IIIf0fe2d62018-02-28 15:20:16 -0800171 EXPECT_EQ(0, wdog->timeRemaining());
172 EXPECT_TRUE(wdog->timerExpired());
William A. Kennington III0650a3f2018-03-01 10:53:25 -0800173 EXPECT_FALSE(wdog->timerEnabled());
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +0530174}
William A. Kennington IIId1331082018-02-27 18:47:05 -0800175
176/** @brief Make sure the watchdog is started and enabled with a fallback
177 * Wait through the initial trip and ensure the fallback is observed
178 * Make sure that fallback runs to completion and ensure the watchdog
179 * is disabled
180 */
181TEST_F(WdogTest, enableWdogWithFallbackTillEnd)
182{
183 auto primaryInterval = 5s;
184 auto primaryIntervalMs = milliseconds(primaryInterval).count();
185 auto fallbackInterval = primaryInterval * 2;
186 auto fallbackIntervalMs = milliseconds(fallbackInterval).count();
187
188 // We need to make a wdog with the right fallback options
189 // The interval is set to be noticeably different from the default
190 // so we can always tell the difference
191 Watchdog::Fallback fallback{
192 .action = Watchdog::Action::PowerOff,
193 .interval = static_cast<uint64_t>(fallbackIntervalMs),
194 };
195 std::map<Watchdog::Action, Watchdog::TargetName> emptyActionTargets;
196 wdog = std::make_unique<Watchdog>(bus, TEST_PATH, eventP,
197 std::move(emptyActionTargets), std::move(fallback));
198 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,
221 wdog->expireAction(Watchdog::Action::None));
222
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,
280 std::move(emptyActionTargets), std::move(fallback));
281 EXPECT_EQ(primaryInterval, milliseconds(wdog->interval(primaryIntervalMs)));
282 EXPECT_FALSE(wdog->enabled());
283 EXPECT_EQ(0, wdog->timeRemaining());
284 EXPECT_FALSE(wdog->timerExpired());
285 EXPECT_FALSE(wdog->timerEnabled());
286
287 // Enable and then verify
288 EXPECT_TRUE(wdog->enabled(true));
289
290 // Waiting default expiration
291 EXPECT_EQ(primaryInterval - 1s, waitForWatchdog(primaryInterval));
292
293 // We should now have entered the fallback once the primary expires
294 EXPECT_FALSE(wdog->enabled());
295 auto remaining = milliseconds(wdog->timeRemaining());
296 EXPECT_GE(fallbackInterval, remaining);
297 EXPECT_LT(primaryInterval, remaining);
298 EXPECT_FALSE(wdog->timerExpired());
299 EXPECT_TRUE(wdog->timerEnabled());
300
301 EXPECT_TRUE(wdog->enabled(true));
302
303 // We should have re-entered the primary
304 EXPECT_TRUE(wdog->enabled());
305 EXPECT_GE(primaryInterval, milliseconds(wdog->timeRemaining()));
306 EXPECT_FALSE(wdog->timerExpired());
307 EXPECT_TRUE(wdog->timerEnabled());
308}
William A. Kennington III22352192018-02-27 18:51:44 -0800309
310/** @brief Make sure the watchdog is started and with a fallback without
311 * sending an enable
312 * Then enable the watchdog
313 * Wait through the initial trip and ensure the fallback is observed
314 * Make sure that fallback runs to completion and ensure the watchdog
315 * is in the fallback state again
316 */
317TEST_F(WdogTest, enableWdogWithFallbackAlways)
318{
319 auto primaryInterval = 5s;
320 auto primaryIntervalMs = milliseconds(primaryInterval).count();
321 auto fallbackInterval = primaryInterval * 2;
322 auto fallbackIntervalMs = milliseconds(fallbackInterval).count();
323
324 // We need to make a wdog with the right fallback options
325 // The interval is set to be noticeably different from the default
326 // so we can always tell the difference
327 Watchdog::Fallback fallback{
328 .action = Watchdog::Action::PowerOff,
329 .interval = static_cast<uint64_t>(fallbackIntervalMs),
330 .always = true,
331 };
332 std::map<Watchdog::Action, Watchdog::TargetName> emptyActionTargets;
333 wdog = std::make_unique<Watchdog>(bus, TEST_PATH, eventP,
334 std::move(emptyActionTargets), std::move(fallback));
335 EXPECT_EQ(primaryInterval, milliseconds(wdog->interval(primaryIntervalMs)));
336 EXPECT_FALSE(wdog->enabled());
337 auto remaining = milliseconds(wdog->timeRemaining());
338 EXPECT_GE(fallbackInterval, remaining);
339 EXPECT_LT(primaryInterval, remaining);
340 EXPECT_FALSE(wdog->timerExpired());
341 EXPECT_TRUE(wdog->timerEnabled());
342
343 // Enable and then verify
344 EXPECT_TRUE(wdog->enabled(true));
345 EXPECT_GE(primaryInterval, milliseconds(wdog->timeRemaining()));
346
347 // Waiting default expiration
348 EXPECT_EQ(primaryInterval - 1s, waitForWatchdog(primaryInterval));
349
350 // We should now have entered the fallback once the primary expires
351 EXPECT_FALSE(wdog->enabled());
352 remaining = milliseconds(wdog->timeRemaining());
353 EXPECT_GE(fallbackInterval, remaining);
354 EXPECT_LT(primaryInterval, remaining);
355 EXPECT_FALSE(wdog->timerExpired());
356 EXPECT_TRUE(wdog->timerEnabled());
357
358 // Waiting fallback expiration
359 EXPECT_EQ(fallbackInterval - 1s, waitForWatchdog(fallbackInterval));
360
361 // We should now enter the fallback again
362 EXPECT_FALSE(wdog->enabled());
363 remaining = milliseconds(wdog->timeRemaining());
364 EXPECT_GE(fallbackInterval, remaining);
365 EXPECT_LT(primaryInterval, remaining);
366 EXPECT_FALSE(wdog->timerExpired());
367 EXPECT_TRUE(wdog->timerEnabled());
368}