Implement a flag to enable fallback always

On some machines we want our watchdog running as long as the
phosphor-watchdog daemon is alive. This patch adds an option to enter
fallback mode any time the watchdog expires or is set to be disabled.

Change-Id: Ic96d2f15c761aeb4e25158c5bd861076cca6497d
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/test/watchdog_test.cpp b/test/watchdog_test.cpp
index af7c3ed..34d1d24 100644
--- a/test/watchdog_test.cpp
+++ b/test/watchdog_test.cpp
@@ -273,6 +273,7 @@
     Watchdog::Fallback fallback{
         .action = Watchdog::Action::PowerOff,
         .interval = static_cast<uint64_t>(fallbackIntervalMs),
+        .always = false,
     };
     std::map<Watchdog::Action, Watchdog::TargetName> emptyActionTargets;
     wdog = std::make_unique<Watchdog>(bus, TEST_PATH, eventP,
@@ -305,3 +306,63 @@
     EXPECT_FALSE(wdog->timerExpired());
     EXPECT_TRUE(wdog->timerEnabled());
 }
+
+/** @brief Make sure the watchdog is started and with a fallback without
+ *         sending an enable
+ *         Then enable the watchdog
+ *         Wait through the initial trip and ensure the fallback is observed
+ *         Make sure that fallback runs to completion and ensure the watchdog
+ *         is in the fallback state again
+ */
+TEST_F(WdogTest, enableWdogWithFallbackAlways)
+{
+    auto primaryInterval = 5s;
+    auto primaryIntervalMs = milliseconds(primaryInterval).count();
+    auto fallbackInterval = primaryInterval * 2;
+    auto fallbackIntervalMs = milliseconds(fallbackInterval).count();
+
+    // We need to make a wdog with the right fallback options
+    // The interval is set to be noticeably different from the default
+    // so we can always tell the difference
+    Watchdog::Fallback fallback{
+        .action = Watchdog::Action::PowerOff,
+        .interval = static_cast<uint64_t>(fallbackIntervalMs),
+        .always = true,
+    };
+    std::map<Watchdog::Action, Watchdog::TargetName> emptyActionTargets;
+    wdog = std::make_unique<Watchdog>(bus, TEST_PATH, eventP,
+                    std::move(emptyActionTargets), std::move(fallback));
+    EXPECT_EQ(primaryInterval, milliseconds(wdog->interval(primaryIntervalMs)));
+    EXPECT_FALSE(wdog->enabled());
+    auto remaining = milliseconds(wdog->timeRemaining());
+    EXPECT_GE(fallbackInterval, remaining);
+    EXPECT_LT(primaryInterval, remaining);
+    EXPECT_FALSE(wdog->timerExpired());
+    EXPECT_TRUE(wdog->timerEnabled());
+
+    // Enable and then verify
+    EXPECT_TRUE(wdog->enabled(true));
+    EXPECT_GE(primaryInterval, milliseconds(wdog->timeRemaining()));
+
+    // Waiting default expiration
+    EXPECT_EQ(primaryInterval - 1s, waitForWatchdog(primaryInterval));
+
+    // We should now have entered the fallback once the primary expires
+    EXPECT_FALSE(wdog->enabled());
+    remaining = milliseconds(wdog->timeRemaining());
+    EXPECT_GE(fallbackInterval, remaining);
+    EXPECT_LT(primaryInterval, remaining);
+    EXPECT_FALSE(wdog->timerExpired());
+    EXPECT_TRUE(wdog->timerEnabled());
+
+    // Waiting fallback expiration
+    EXPECT_EQ(fallbackInterval - 1s, waitForWatchdog(fallbackInterval));
+
+    // We should now enter the fallback again
+    EXPECT_FALSE(wdog->enabled());
+    remaining = milliseconds(wdog->timeRemaining());
+    EXPECT_GE(fallbackInterval, remaining);
+    EXPECT_LT(primaryInterval, remaining);
+    EXPECT_FALSE(wdog->timerExpired());
+    EXPECT_TRUE(wdog->timerEnabled());
+}