1 #include "watchdog.hpp"
2 
3 #include <sdbusplus/bus.hpp>
4 #include <sdeventplus/event.hpp>
5 
6 #include <chrono>
7 #include <memory>
8 #include <thread>
9 #include <utility>
10 
11 #include <gtest/gtest.h>
12 
13 namespace phosphor
14 {
15 namespace watchdog
16 {
17 
18 using namespace std::chrono;
19 using namespace std::chrono_literals;
20 
21 constexpr auto TEST_MIN_INTERVAL = duration<uint64_t, std::deci>(2);
22 
23 // Test Watchdog functionality
24 class WdogTest : public ::testing::Test
25 {
26   public:
27     // The unit time used to measure the timer
28     // This should be large enough to accomodate drift
29     using Quantum = duration<uint64_t, std::deci>;
30 
31     // Gets called as part of each TEST_F construction
WdogTest()32     WdogTest() :
33         event(sdeventplus::Event::get_default()),
34         bus(sdbusplus::bus::new_default()),
35         wdog(std::make_unique<Watchdog>(
36             bus, TEST_PATH, event, Watchdog::ActionTargetMap(), std::nullopt,
37             milliseconds(TEST_MIN_INTERVAL).count())),
38 
39         defaultInterval(Quantum(3))
40 
41     {
42         wdog->interval(milliseconds(defaultInterval).count());
43         // Initially the watchdog would be disabled
44         EXPECT_FALSE(wdog->enabled());
45     }
46 
47     // sdevent Event handle
48     sdeventplus::Event event;
49 
50     // sdbusplus handle
51     sdbusplus::bus_t bus;
52 
53     // Watchdog object
54     std::unique_ptr<Watchdog> wdog;
55 
56     // This is the default interval as given in Interface definition
57     Quantum defaultInterval;
58 
59   protected:
60     // Dummy name for object path
61     // This is just to satisfy the constructor. Does not have
62     // a need to check if the objects paths have been created.
63     static constexpr auto TEST_PATH = "/test/path";
64 
65     // Returns how long it took for the current watchdog timer to be
66     // disabled or have its timeRemaining reset.
waitForWatchdog(Quantum timeLimit)67     Quantum waitForWatchdog(Quantum timeLimit)
68     {
69         auto previousTimeRemaining = wdog->timeRemaining();
70         auto ret = Quantum(0);
71         while (ret < timeLimit &&
72                previousTimeRemaining >= wdog->timeRemaining() &&
73                wdog->timerEnabled())
74         {
75             previousTimeRemaining = wdog->timeRemaining();
76 
77             constexpr auto sleepTime = Quantum(1);
78             if (event.run(sleepTime) == 0)
79             {
80                 ret += sleepTime;
81             }
82         }
83 
84         return ret;
85     }
86 };
87 
88 /** @brief Make sure that watchdog is started and not enabled */
TEST_F(WdogTest,createWdogAndDontEnable)89 TEST_F(WdogTest, createWdogAndDontEnable)
90 {
91     EXPECT_FALSE(wdog->enabled());
92     EXPECT_EQ(0, wdog->timeRemaining());
93     EXPECT_FALSE(wdog->timerExpired());
94     EXPECT_FALSE(wdog->timerEnabled());
95 
96     // We should be able to configure persistent properties
97     // while disabled
98     auto newAction = Watchdog::Action::PowerOff;
99     EXPECT_EQ(newAction, wdog->expireAction(newAction));
100     auto newIntervalMs = milliseconds(defaultInterval * 2).count();
101     EXPECT_EQ(newIntervalMs, wdog->interval(newIntervalMs));
102 
103     EXPECT_EQ(newAction, wdog->expireAction());
104     EXPECT_EQ(newIntervalMs, wdog->interval());
105 
106     // We won't be able to configure timeRemaining
107     EXPECT_EQ(0, wdog->timeRemaining(1000));
108     EXPECT_EQ(0, wdog->timeRemaining());
109 
110     // Timer should not have become enabled
111     EXPECT_FALSE(wdog->enabled());
112     EXPECT_EQ(0, wdog->timeRemaining());
113     EXPECT_FALSE(wdog->timerExpired());
114     EXPECT_FALSE(wdog->timerEnabled());
115 }
116 
117 /** @brief Make sure that watchdog is started and enabled */
TEST_F(WdogTest,createWdogAndEnable)118 TEST_F(WdogTest, createWdogAndEnable)
119 {
120     // Enable and then verify
121     EXPECT_TRUE(wdog->enabled(true));
122     EXPECT_FALSE(wdog->timerExpired());
123     EXPECT_TRUE(wdog->timerEnabled());
124 
125     // Get the configured interval
126     auto remaining = milliseconds(wdog->timeRemaining());
127 
128     // Its possible that we are off by few msecs depending on
129     // how we get scheduled. So checking a range here.
130     EXPECT_TRUE((remaining >= defaultInterval - Quantum(1)) &&
131                 (remaining <= defaultInterval));
132 
133     EXPECT_FALSE(wdog->timerExpired());
134     EXPECT_TRUE(wdog->timerEnabled());
135 }
136 
137 /** @brief Make sure that watchdog is started and enabled.
138  *         Later, disable watchdog
139  */
TEST_F(WdogTest,createWdogAndEnableThenDisable)140 TEST_F(WdogTest, createWdogAndEnableThenDisable)
141 {
142     // Enable and then verify
143     EXPECT_TRUE(wdog->enabled(true));
144 
145     // Disable and then verify
146     EXPECT_FALSE(wdog->enabled(false));
147     EXPECT_FALSE(wdog->enabled());
148     EXPECT_EQ(0, wdog->timeRemaining());
149     EXPECT_FALSE(wdog->timerExpired());
150     EXPECT_FALSE(wdog->timerEnabled());
151 }
152 
153 /** @brief Make sure that watchdog is started and enabled.
154  *         Wait for 5 quantums and make sure that the remaining
155  *         time shows 5 fewer quantums.
156  */
TEST_F(WdogTest,enableWdogAndWait5Quantums)157 TEST_F(WdogTest, enableWdogAndWait5Quantums)
158 {
159     // Enable and then verify
160     EXPECT_TRUE(wdog->enabled(true));
161 
162     // Sleep for 5 quantums
163     auto sleepTime = Quantum(2);
164     ASSERT_LT(sleepTime, defaultInterval);
165     std::this_thread::sleep_for(sleepTime);
166 
167     // Get the remaining time again and expectation is that we get fewer
168     auto remaining = milliseconds(wdog->timeRemaining());
169     auto expected = defaultInterval - sleepTime;
170 
171     // Its possible that we are off by few msecs depending on
172     // how we get scheduled. So checking a range here.
173     EXPECT_TRUE((remaining >= expected - Quantum(1)) &&
174                 (remaining <= expected));
175     EXPECT_FALSE(wdog->timerExpired());
176     EXPECT_TRUE(wdog->timerEnabled());
177 }
178 
179 /** @brief Make sure that watchdog is started and enabled.
180  *         Wait 1 quantum and then reset the timer to 5 quantums
181  *         and then expect the watchdog to expire in 5 quantums
182  */
TEST_F(WdogTest,enableWdogAndResetTo5Quantums)183 TEST_F(WdogTest, enableWdogAndResetTo5Quantums)
184 {
185     // Enable and then verify
186     EXPECT_TRUE(wdog->enabled(true));
187 
188     // Sleep for 1 second
189     std::this_thread::sleep_for(Quantum(1));
190 
191     // Timer should still be running unexpired
192     EXPECT_FALSE(wdog->timerExpired());
193     EXPECT_TRUE(wdog->timerEnabled());
194 
195     // Next timer will expire in 5 quantums from now.
196     auto expireTime = Quantum(5);
197     auto expireTimeMs = milliseconds(expireTime).count();
198     EXPECT_EQ(expireTimeMs, wdog->timeRemaining(expireTimeMs));
199 
200     // Waiting for expiration
201     EXPECT_EQ(expireTime - Quantum(1), waitForWatchdog(expireTime));
202     EXPECT_TRUE(wdog->timerExpired());
203     EXPECT_FALSE(wdog->timerEnabled());
204 }
205 
206 /** @brief Make sure the Interval can be updated directly.
207  */
TEST_F(WdogTest,verifyIntervalUpdateReceived)208 TEST_F(WdogTest, verifyIntervalUpdateReceived)
209 {
210     auto expireTime = Quantum(5);
211     auto expireTimeMs = milliseconds(expireTime).count();
212     EXPECT_EQ(expireTimeMs, wdog->interval(expireTimeMs));
213 
214     // Expect an update in the Interval
215     EXPECT_EQ(expireTimeMs, wdog->interval());
216 }
217 
218 /** @brief Make sure the Interval can be updated while the timer is running.
219  */
TEST_F(WdogTest,verifyIntervalUpdateRunning)220 TEST_F(WdogTest, verifyIntervalUpdateRunning)
221 {
222     const auto oldInterval = milliseconds(wdog->interval());
223     const auto newInterval = 5s;
224 
225     EXPECT_TRUE(wdog->enabled(true));
226     auto remaining = milliseconds(wdog->timeRemaining());
227     EXPECT_GE(oldInterval, remaining);
228     EXPECT_LE(oldInterval - Quantum(1), remaining);
229     EXPECT_EQ(newInterval,
230               milliseconds(wdog->interval(milliseconds(newInterval).count())));
231 
232     // Expect only the interval to update
233     remaining = milliseconds(wdog->timeRemaining());
234     EXPECT_GE(oldInterval, remaining);
235     EXPECT_LE(oldInterval - Quantum(1), remaining);
236     EXPECT_EQ(newInterval, milliseconds(wdog->interval()));
237 
238     // Expect reset to use the new interval
239     wdog->resetTimeRemaining(false);
240     remaining = milliseconds(wdog->timeRemaining());
241     EXPECT_GE(newInterval, remaining);
242     EXPECT_LE(newInterval - Quantum(1), remaining);
243 }
244 
245 /** @brief Make sure that watchdog is started and enabled.
246  *         Wait default interval quantums and make sure that wdog has died
247  */
TEST_F(WdogTest,enableWdogAndWaitTillEnd)248 TEST_F(WdogTest, enableWdogAndWaitTillEnd)
249 {
250     // Enable and then verify
251     EXPECT_TRUE(wdog->enabled(true));
252 
253     // Waiting default expiration
254     EXPECT_EQ(defaultInterval - Quantum(1), waitForWatchdog(defaultInterval));
255 
256     EXPECT_FALSE(wdog->enabled());
257     EXPECT_EQ(0, wdog->timeRemaining());
258     EXPECT_TRUE(wdog->timerExpired());
259     EXPECT_FALSE(wdog->timerEnabled());
260 }
261 
262 /** @brief Make sure the watchdog is started and enabled with a fallback
263  *         Wait through the initial trip and ensure the fallback is observed
264  *         Make sure that fallback runs to completion and ensure the watchdog
265  *         is disabled
266  */
TEST_F(WdogTest,enableWdogWithFallbackTillEnd)267 TEST_F(WdogTest, enableWdogWithFallbackTillEnd)
268 {
269     auto primaryInterval = Quantum(5);
270     auto primaryIntervalMs = milliseconds(primaryInterval).count();
271     auto fallbackInterval = primaryInterval * 2;
272     auto fallbackIntervalMs = milliseconds(fallbackInterval).count();
273 
274     // We need to make a wdog with the right fallback options
275     // The interval is set to be noticeably different from the default
276     // so we can always tell the difference
277     Watchdog::Fallback fallback;
278     fallback.action = Watchdog::Action::PowerOff;
279     fallback.interval = static_cast<uint64_t>(fallbackIntervalMs);
280     fallback.always = false;
281     wdog.reset();
282     wdog = std::make_unique<Watchdog>(bus, TEST_PATH, event,
283                                       Watchdog::ActionTargetMap(), fallback);
284     EXPECT_EQ(primaryInterval, milliseconds(wdog->interval(primaryIntervalMs)));
285     EXPECT_FALSE(wdog->enabled());
286     EXPECT_EQ(0, wdog->timeRemaining());
287 
288     // Enable and then verify
289     EXPECT_TRUE(wdog->enabled(true));
290 
291     // Waiting default expiration
292     EXPECT_EQ(primaryInterval - Quantum(1), 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     // We should still be ticking in fallback when setting action or interval
303     auto newInterval = primaryInterval - Quantum(1);
304     auto newIntervalMs = milliseconds(newInterval).count();
305     EXPECT_EQ(newInterval, milliseconds(wdog->interval(newIntervalMs)));
306     EXPECT_EQ(Watchdog::Action::None,
307               wdog->expireAction(Watchdog::Action::None));
308 
309     EXPECT_FALSE(wdog->enabled());
310     EXPECT_GE(remaining, milliseconds(wdog->timeRemaining()));
311     EXPECT_LT(primaryInterval, milliseconds(wdog->timeRemaining()));
312     EXPECT_FALSE(wdog->timerExpired());
313     EXPECT_TRUE(wdog->timerEnabled());
314 
315     // Test that setting the timeRemaining always resets the timer to the
316     // fallback interval
317     EXPECT_EQ(fallback.interval, wdog->timeRemaining(primaryInterval.count()));
318     EXPECT_FALSE(wdog->enabled());
319 
320     remaining = milliseconds(wdog->timeRemaining());
321     EXPECT_GE(fallbackInterval, remaining);
322     EXPECT_LE(fallbackInterval - Quantum(1), remaining);
323     EXPECT_FALSE(wdog->timerExpired());
324     EXPECT_TRUE(wdog->timerEnabled());
325 
326     // Waiting fallback expiration
327     EXPECT_EQ(fallbackInterval - Quantum(1), waitForWatchdog(fallbackInterval));
328 
329     // We should now have disabled the watchdog after the fallback expires
330     EXPECT_FALSE(wdog->enabled());
331     EXPECT_EQ(0, wdog->timeRemaining());
332     EXPECT_TRUE(wdog->timerExpired());
333     EXPECT_FALSE(wdog->timerEnabled());
334 
335     // Make sure enabling the watchdog again works
336     EXPECT_TRUE(wdog->enabled(true));
337 
338     // We should have re-entered the primary
339     EXPECT_TRUE(wdog->enabled());
340     EXPECT_GE(primaryInterval, milliseconds(wdog->timeRemaining()));
341     EXPECT_FALSE(wdog->timerExpired());
342     EXPECT_TRUE(wdog->timerEnabled());
343 }
344 
345 /** @brief Make sure the watchdog is started and enabled with a fallback
346  *         Wait through the initial trip and ensure the fallback is observed
347  *         Make sure that we can re-enable the watchdog during fallback
348  */
TEST_F(WdogTest,enableWdogWithFallbackReEnable)349 TEST_F(WdogTest, enableWdogWithFallbackReEnable)
350 {
351     auto primaryInterval = Quantum(5);
352     auto primaryIntervalMs = milliseconds(primaryInterval).count();
353     auto fallbackInterval = primaryInterval * 2;
354     auto fallbackIntervalMs = milliseconds(fallbackInterval).count();
355 
356     // We need to make a wdog with the right fallback options
357     // The interval is set to be noticeably different from the default
358     // so we can always tell the difference
359     Watchdog::Fallback fallback;
360     fallback.action = Watchdog::Action::PowerOff;
361     fallback.interval = static_cast<uint64_t>(fallbackIntervalMs);
362     fallback.always = false;
363     wdog.reset();
364     wdog = std::make_unique<Watchdog>(bus, TEST_PATH, event,
365                                       Watchdog::ActionTargetMap(), fallback);
366     EXPECT_EQ(primaryInterval, milliseconds(wdog->interval(primaryIntervalMs)));
367     EXPECT_FALSE(wdog->enabled());
368     EXPECT_EQ(0, wdog->timeRemaining());
369     EXPECT_FALSE(wdog->timerExpired());
370     EXPECT_FALSE(wdog->timerEnabled());
371 
372     // Enable and then verify
373     EXPECT_TRUE(wdog->enabled(true));
374 
375     // Waiting default expiration
376     EXPECT_EQ(primaryInterval - Quantum(1), waitForWatchdog(primaryInterval));
377 
378     // We should now have entered the fallback once the primary expires
379     EXPECT_FALSE(wdog->enabled());
380     auto remaining = milliseconds(wdog->timeRemaining());
381     EXPECT_GE(fallbackInterval, remaining);
382     EXPECT_LT(primaryInterval, remaining);
383     EXPECT_FALSE(wdog->timerExpired());
384     EXPECT_TRUE(wdog->timerEnabled());
385 
386     EXPECT_TRUE(wdog->enabled(true));
387 
388     // We should have re-entered the primary
389     EXPECT_TRUE(wdog->enabled());
390     EXPECT_GE(primaryInterval, milliseconds(wdog->timeRemaining()));
391     EXPECT_FALSE(wdog->timerExpired());
392     EXPECT_TRUE(wdog->timerEnabled());
393 }
394 
395 /** @brief Make sure the watchdog is started and enabled with a fallback
396  *         Wait through the initial trip and ensure the fallback is observed
397  *         Make sure that changing the primary interval and calling reset timer
398  *         will enable the primary watchdog with primary interval.
399  */
TEST_F(WdogTest,enableWdogWithFallbackResetTimerEnable)400 TEST_F(WdogTest, enableWdogWithFallbackResetTimerEnable)
401 {
402     auto primaryInterval = Quantum(5);
403     auto primaryIntervalMs = milliseconds(primaryInterval).count();
404     auto fallbackInterval = primaryInterval * 2;
405     auto fallbackIntervalMs = milliseconds(fallbackInterval).count();
406     auto newInterval = fallbackInterval * 2;
407     auto newIntervalMs = milliseconds(newInterval).count();
408 
409     // We need to make a wdog with the right fallback options
410     // The interval is set to be noticeably different from the default
411     // so we can always tell the difference
412     Watchdog::Fallback fallback;
413     fallback.action = Watchdog::Action::PowerOff;
414     fallback.interval = static_cast<uint64_t>(fallbackIntervalMs);
415     fallback.always = false;
416     wdog.reset();
417     wdog = std::make_unique<Watchdog>(bus, TEST_PATH, event,
418                                       Watchdog::ActionTargetMap(), fallback);
419     EXPECT_EQ(primaryInterval, milliseconds(wdog->interval(primaryIntervalMs)));
420     EXPECT_FALSE(wdog->enabled());
421     EXPECT_EQ(0, wdog->timeRemaining());
422     EXPECT_FALSE(wdog->timerExpired());
423     EXPECT_FALSE(wdog->timerEnabled());
424 
425     // Enable and then verify
426     EXPECT_TRUE(wdog->enabled(true));
427 
428     // Waiting default expiration
429     EXPECT_EQ(primaryInterval - Quantum(1), waitForWatchdog(primaryInterval));
430 
431     // We should now have entered the fallback once the primary expires
432     EXPECT_FALSE(wdog->enabled());
433     auto remaining = milliseconds(wdog->timeRemaining());
434     EXPECT_GE(fallbackInterval, remaining);
435     EXPECT_LT(primaryInterval, remaining);
436     EXPECT_FALSE(wdog->timerExpired());
437     EXPECT_TRUE(wdog->timerEnabled());
438 
439     // Setting the interval should take effect once resetTimer re-enables wdog
440     EXPECT_EQ(newIntervalMs, wdog->interval(newIntervalMs));
441     wdog->resetTimeRemaining(true);
442 
443     // We should have re-entered the primary
444     EXPECT_TRUE(wdog->enabled());
445     remaining = milliseconds(wdog->timeRemaining());
446     EXPECT_GE(newInterval, remaining);
447     EXPECT_LE(newInterval - Quantum(1), remaining);
448     EXPECT_FALSE(wdog->timerExpired());
449     EXPECT_TRUE(wdog->timerEnabled());
450 }
451 
452 /** @brief Make sure the watchdog is started and with a fallback without
453  *         sending an enable
454  *         Then enable the watchdog
455  *         Wait through the initial trip and ensure the fallback is observed
456  *         Make sure that fallback runs to completion and ensure the watchdog
457  *         is in the fallback state again
458  */
TEST_F(WdogTest,enableWdogWithFallbackAlways)459 TEST_F(WdogTest, enableWdogWithFallbackAlways)
460 {
461     auto primaryInterval = Quantum(5);
462     auto primaryIntervalMs = milliseconds(primaryInterval).count();
463     auto fallbackInterval = primaryInterval * 2;
464     auto fallbackIntervalMs = milliseconds(fallbackInterval).count();
465 
466     // We need to make a wdog with the right fallback options
467     // The interval is set to be noticeably different from the default
468     // so we can always tell the difference
469     Watchdog::Fallback fallback;
470     fallback.action = Watchdog::Action::PowerOff;
471     fallback.interval = static_cast<uint64_t>(fallbackIntervalMs);
472     fallback.always = true;
473     wdog.reset();
474     wdog = std::make_unique<Watchdog>(bus, TEST_PATH, event,
475                                       Watchdog::ActionTargetMap(), fallback,
476                                       milliseconds(TEST_MIN_INTERVAL).count());
477 
478     // Make sure defualt interval is biggger than min interval
479     EXPECT_LT(milliseconds((TEST_MIN_INTERVAL).count()),
480               milliseconds(wdog->interval()));
481 
482     EXPECT_EQ(primaryInterval, milliseconds(wdog->interval(primaryIntervalMs)));
483     EXPECT_FALSE(wdog->enabled());
484     auto remaining = milliseconds(wdog->timeRemaining());
485     EXPECT_GE(fallbackInterval, remaining);
486     EXPECT_LT(primaryInterval, remaining);
487     EXPECT_FALSE(wdog->timerExpired());
488     EXPECT_TRUE(wdog->timerEnabled());
489 
490     // Enable and then verify
491     EXPECT_TRUE(wdog->enabled(true));
492     EXPECT_GE(primaryInterval, milliseconds(wdog->timeRemaining()));
493 
494     // Waiting default expiration
495     EXPECT_EQ(primaryInterval - Quantum(1), waitForWatchdog(primaryInterval));
496 
497     // We should now have entered the fallback once the primary expires
498     EXPECT_FALSE(wdog->enabled());
499     remaining = milliseconds(wdog->timeRemaining());
500     EXPECT_GE(fallbackInterval, remaining);
501     EXPECT_LT(primaryInterval, remaining);
502     EXPECT_FALSE(wdog->timerExpired());
503     EXPECT_TRUE(wdog->timerEnabled());
504 
505     // Waiting fallback expiration
506     EXPECT_EQ(fallbackInterval - Quantum(1), waitForWatchdog(fallbackInterval));
507 
508     // We should now enter the fallback again
509     EXPECT_FALSE(wdog->enabled());
510     remaining = milliseconds(wdog->timeRemaining());
511     EXPECT_GE(fallbackInterval, remaining);
512     EXPECT_LT(primaryInterval, remaining);
513     EXPECT_FALSE(wdog->timerExpired());
514     EXPECT_TRUE(wdog->timerEnabled());
515 }
516 
517 /** @brief Test minimal interval
518  *  The minimal interval was set 2 seconds
519  *  Test that when setting interval to 1s , it is still returning 2s
520  */
TEST_F(WdogTest,verifyMinIntervalSetting)521 TEST_F(WdogTest, verifyMinIntervalSetting)
522 {
523     auto newInterval = Quantum(1);
524     auto newIntervalMs = milliseconds(newInterval).count();
525     auto minIntervalMs = milliseconds(TEST_MIN_INTERVAL).count();
526 
527     // Check first that the current interval is greater than minInterval
528     EXPECT_LT(minIntervalMs, wdog->interval());
529     // Check that the interval was not set to smaller value than minInterval
530     EXPECT_EQ(minIntervalMs, wdog->interval(newIntervalMs));
531     // Check that the interval was not set to smaller value than minInterval
532     EXPECT_EQ(minIntervalMs, wdog->interval());
533 }
534 
535 /** @brief Test minimal interval
536  *  Initiate default Watchdog in order to get the default
537  *  interval.
538  *  Initiate watchdog with minInterval greater than default
539  *  interval, and make sure the default interval was set to the
540  *  minInterval.
541  */
TEST_F(WdogTest,verifyConstructorMinIntervalSetting)542 TEST_F(WdogTest, verifyConstructorMinIntervalSetting)
543 {
544     // Initiate default Watchdog and get the default interval value.
545     wdog.reset();
546     wdog = std::make_unique<Watchdog>(bus, TEST_PATH, event);
547     auto defaultIntervalMs = wdog->interval();
548     auto defaultInterval = milliseconds(defaultIntervalMs);
549     auto minInterval = defaultInterval + Quantum(30);
550     auto minIntervalMs = milliseconds(minInterval).count();
551 
552     // We initiate a new Watchdog with min interval greater than the default
553     // intrval
554     wdog.reset();
555     wdog = std::make_unique<Watchdog>(bus, TEST_PATH, event,
556                                       Watchdog::ActionTargetMap(), std::nullopt,
557                                       minIntervalMs);
558     // Check that the interval was set to the minInterval
559     EXPECT_EQ(minIntervalMs, wdog->interval());
560 
561     // Enable and then verify
562     EXPECT_TRUE(wdog->enabled(true));
563     EXPECT_FALSE(wdog->timerExpired());
564     EXPECT_TRUE(wdog->timerEnabled());
565 
566     // Set remaining time shorter than minInterval will actually set it to
567     // minInterval
568     auto remaining = milliseconds(wdog->timeRemaining(defaultIntervalMs));
569 
570     // Its possible that we are off by few msecs depending on
571     // how we get scheduled. So checking a range here.
572     EXPECT_TRUE((remaining >= minInterval - Quantum(1)) &&
573                 (remaining <= minInterval));
574 
575     EXPECT_FALSE(wdog->timerExpired());
576     EXPECT_TRUE(wdog->timerEnabled());
577 }
578 
579 } // namespace watchdog
580 } // namespace phosphor
581