Add Gtest to test watchdog

Change-Id: Ia0268b6b18999b6dd6cfd26bcadcff25734306f0
Signed-off-by: Vishwanatha Subbanna <vishwa@linux.vnet.ibm.com>
diff --git a/test/Makefile.am b/test/Makefile.am
new file mode 100644
index 0000000..654f0f1
--- /dev/null
+++ b/test/Makefile.am
@@ -0,0 +1,39 @@
+AM_CPPFLAGS = -I$(top_srcdir)
+
+# Run all 'check' test programs
+TESTS = $(check_PROGRAMS)
+
+# Build/add utest to test suite
+check_PROGRAMS = timer_test \
+                 watchdog_test
+
+utestCPPFLAGS = -Igtest \
+                 $(GTEST_CPPFLAGS) \
+                 $(AM_CPPFLAGS) \
+                 $(SDBUSPLUS_CFLAGS) \
+                 $(PHOSPHOR_LOGGING_CFLAGS) \
+                 $(PHOSPHOR_DBUS_INTERFACES_CFLAGS)
+
+utestCXXFLAGS = $(PTHREAD_CFLAGS)
+
+utestLDFLAGS = -lgtest_main -lgtest \
+                $(PTHREAD_LIBS) \
+                $(OESDK_TESTCASE_FLAGS) \
+                $(SDBUSPLUS_LIBS) \
+                $(PHOSPHOR_LOGGING_LIBS) \
+                $(PHOSPHOR_DBUS_INTERFACES_LIBS)
+
+timer_test_CPPFLAGS = ${utestCPPFLAGS}
+timer_test_CXXFLAGS = ${utestCXXFLAGS}
+timer_test_LDFLAGS = ${utestLDFLAGS}
+
+watchdog_test_CPPFLAGS = ${utestCPPFLAGS}
+watchdog_test_CXXFLAGS = ${utestCXXFLAGS}
+watchdog_test_LDFLAGS = ${utestLDFLAGS}
+
+timer_test_SOURCES = timer_test.cpp
+watchdog_test_SOURCES = watchdog_test.cpp
+
+timer_test_LDADD = $(top_builddir)/timer.o
+watchdog_test_LDADD = $(top_builddir)/timer.o \
+                      $(top_builddir)/watchdog.o
diff --git a/test/timer_test.cpp b/test/timer_test.cpp
new file mode 100644
index 0000000..e9f323b
--- /dev/null
+++ b/test/timer_test.cpp
@@ -0,0 +1,72 @@
+#include <chrono>
+#include <timer_test.hpp>
+
+using namespace std::chrono;
+using namespace std::chrono_literals;
+
+/** @brief Starts the timer and expects it to
+ *         expire in configured time and expects the
+ *         deault callback handler to kick-in
+ */
+TEST_F(TimerTest, testTimerForExpirationDefaultTimeoutHandler)
+{
+    // Expect timer to expire in 2 seconds
+    auto expireTime = seconds(2s);
+
+    phosphor::watchdog::Timer timer(eventP);
+
+    // Set the expiration and enable the timer
+    timer.start(duration_cast<milliseconds>(expireTime));
+    timer.setEnabled<std::true_type>();
+
+    // Waiting 2 seconds to expect expiration
+    int count = 0;
+    while(count < expireTime.count() && !timer.expired())
+    {
+        // Returns -0- on timeout and positive number on dispatch
+        auto sleepTime = duration_cast<microseconds>(seconds(1));
+        if(!sd_event_run(eventP.get(), sleepTime.count()))
+        {
+            count++;
+        }
+    }
+    EXPECT_EQ(true, timer.expired());
+    EXPECT_EQ(expireTime.count() - 1, count);
+
+    // Make sure secondary callback was not called.
+    EXPECT_EQ(false, expired);
+}
+
+/** @brief Starts the timer and expects it to expire
+ *         in configured time and expects the secondary
+ *         callback to be called into along with default.
+ */
+TEST_F(TimerTest, testTimerForExpirationSecondCallBack)
+{
+    // Expect timer to expire in 2 seconds
+    auto expireTime = seconds(2s);
+
+    phosphor::watchdog::Timer timer(eventP,
+                    std::bind(&TimerTest::timeOutHandler, this));
+
+    // Set the expiration and enable the timer
+    timer.start(duration_cast<milliseconds>(expireTime));
+    timer.setEnabled<std::true_type>();
+
+    // Waiting 2 seconds to expect expiration
+    int count = 0;
+    while(count < expireTime.count() && !timer.expired())
+    {
+        // Returns -0- on timeout and positive number on dispatch
+        auto sleepTime = duration_cast<microseconds>(seconds(1));
+        if(!sd_event_run(eventP.get(), sleepTime.count()))
+        {
+            count++;
+        }
+    }
+    EXPECT_EQ(true, timer.expired());
+    EXPECT_EQ(expireTime.count() - 1, count);
+
+    // This gets set as part of secondary callback
+    EXPECT_EQ(true, expired);
+}
diff --git a/test/timer_test.hpp b/test/timer_test.hpp
new file mode 100644
index 0000000..3f6ffea
--- /dev/null
+++ b/test/timer_test.hpp
@@ -0,0 +1,40 @@
+#include <iostream>
+#include <gtest/gtest.h>
+#include <timer.hpp>
+
+// Base class for testing Timer
+class TimerTest : public testing::Test
+{
+    public:
+        // systemd event handler
+        sd_event* events;
+
+        // Need this so that events can be initialized.
+        int rc;
+
+        // Tells if the watchdog timer expired.
+        bool expired = false;
+
+        // Gets called as part of each TEST_F construction
+        TimerTest()
+            : rc(sd_event_default(&events)),
+              eventP(events)
+        {
+            // Check for successful creation of
+            // event handler and bus handler
+            EXPECT_GE(rc, 0);
+
+            // Its already wrapped in eventP
+            events = nullptr;
+        }
+
+        // unique_ptr for sd_event
+        phosphor::watchdog::EventPtr eventP;
+
+        // Handler called by timer expiration
+        inline void timeOutHandler()
+        {
+            std::cout << "Time out handler called" << std::endl;
+            expired = true;
+        }
+};
diff --git a/test/watchdog_test.cpp b/test/watchdog_test.cpp
new file mode 100644
index 0000000..4e77528
--- /dev/null
+++ b/test/watchdog_test.cpp
@@ -0,0 +1,130 @@
+#include <watchdog_test.hpp>
+
+using namespace phosphor::watchdog;
+
+/** @brief Make sure that watchdog is started and not enabled */
+TEST_F(WdogTest, createWdogAndDontEnable)
+{
+    EXPECT_EQ(false, wdog.enabled());
+    EXPECT_EQ(0, wdog.timeRemaining());
+    EXPECT_EQ(false, wdog.timerExpired());
+}
+
+/** @brief Make sure that watchdog is started and enabled */
+TEST_F(WdogTest, createWdogAndEnable)
+{
+    // Enable and then verify
+    EXPECT_EQ(true, wdog.enabled(true));
+    EXPECT_EQ(false, wdog.timerExpired());
+
+    // Get the configured interval
+    auto remaining = milliseconds(wdog.timeRemaining());
+
+    // Its possible that we are off by few msecs depending on
+    // how we get scheduled. So checking a range here.
+    EXPECT_TRUE((remaining >= defaultInterval - defaultDrift) &&
+                (remaining <= defaultInterval));
+
+    EXPECT_EQ(false, wdog.timerExpired());
+}
+
+/** @brief Make sure that watchdog is started and enabled.
+ *         Later, disable watchdog
+ */
+TEST_F(WdogTest, createWdogAndEnableThenDisable)
+{
+    // Enable and then verify
+    EXPECT_EQ(true, wdog.enabled(true));
+
+    // Disable and then verify
+    EXPECT_EQ(false, wdog.enabled(false));
+    EXPECT_EQ(false, wdog.enabled());
+    EXPECT_EQ(0, wdog.timeRemaining());
+}
+
+/** @brief Make sure that watchdog is started and enabled.
+ *         Wait for 5 seconds and make sure that the remaining
+ *         time shows 25 seconds.
+ */
+TEST_F(WdogTest, enableWdogAndWait5Seconds)
+{
+    // Enable and then verify
+    EXPECT_EQ(true, wdog.enabled(true));
+
+    // Sleep for 5 seconds
+    auto sleepTime = seconds(5s);
+    std::this_thread::sleep_for(sleepTime);
+
+    // Get the remaining time again and expectation is that we get 25s
+    auto remaining = milliseconds(wdog.timeRemaining());
+    auto expected = defaultInterval -
+                    duration_cast<milliseconds>(sleepTime);
+
+    // Its possible that we are off by few msecs depending on
+    // how we get scheduled. So checking a range here.
+    EXPECT_TRUE((remaining >= expected - defaultDrift) &&
+                (remaining <= expected));
+    EXPECT_EQ(false, wdog.timerExpired());
+}
+
+/** @brief Make sure that watchdog is started and enabled.
+ *         Wait 1 second and then reset the timer to 5 seconds
+ *         and then expect the watchdog to expire in 5 seconds
+ */
+TEST_F(WdogTest, enableWdogAndResetTo5Seconds)
+{
+    // Enable and then verify
+    EXPECT_EQ(true, wdog.enabled(true));
+
+    // Sleep for 1 second
+    std::this_thread::sleep_for(1s);
+
+    // Next timer will expire in 5 seconds from now.
+    auto expireTime = seconds(5s);
+    auto newTime = duration_cast<milliseconds>(expireTime);
+    wdog.timeRemaining(newTime.count());
+
+    // Waiting for expiration
+    int count = 0;
+    while(count < expireTime.count() && !wdog.timerExpired())
+    {
+        // Returns -0- on timeout and positive number on dispatch
+        auto sleepTime = duration_cast<microseconds>(seconds(1s));
+        if(!sd_event_run(eventP.get(), sleepTime.count()))
+        {
+            count++;
+        }
+    }
+    EXPECT_EQ(true, wdog.timerExpired());
+    EXPECT_EQ(expireTime.count() - 1 , count);
+
+    // Make sure secondary callback was not called.
+    EXPECT_EQ(false, expired);
+}
+
+/** @brief Make sure that watchdog is started and enabled.
+ *         Wait default interval seconds and make sure that wdog has died
+ */
+TEST_F(WdogTest, enableWdogAndWaitTillEnd)
+{
+    // Enable and then verify
+    EXPECT_EQ(true, wdog.enabled(true));
+    auto expireTime = duration_cast<seconds>(
+                        milliseconds(defaultInterval));
+
+    // Waiting default expiration
+    int count = 0;
+    while(count < expireTime.count() && !wdog.timerExpired())
+    {
+        // Returns -0- on timeout and positive number on dispatch
+        auto sleepTime = duration_cast<microseconds>(seconds(1s));
+        if(!sd_event_run(eventP.get(), sleepTime.count()))
+        {
+            count++;
+        }
+    }
+    EXPECT_EQ(true, wdog.enabled());
+    EXPECT_EQ(0, wdog.timeRemaining());
+    EXPECT_EQ(true, wdog.timerExpired());
+    EXPECT_EQ(expireTime.count() - 1, count);
+}
diff --git a/test/watchdog_test.hpp b/test/watchdog_test.hpp
new file mode 100644
index 0000000..0d1d628
--- /dev/null
+++ b/test/watchdog_test.hpp
@@ -0,0 +1,46 @@
+#include <timer_test.hpp>
+#include <chrono>
+#include <watchdog.hpp>
+
+using namespace std::chrono;
+using namespace std::chrono_literals;
+
+// Test Watchdog functionality
+class WdogTest : public TimerTest
+{
+    public:
+        // Gets called as part of each TEST_F construction
+        WdogTest()
+            : bus(sdbusplus::bus::new_default()),
+              wdog(bus, TEST_PATH, eventP),
+              defaultInterval(milliseconds(wdog.interval())),
+              defaultDrift(30)
+        {
+            // Check for successful creation of
+            // event handler and bus handler
+            EXPECT_GE(rc, 0);
+
+            // Initially the watchdog would be disabled
+            EXPECT_EQ(false, wdog.enabled());
+        }
+
+        //sdbusplus handle
+        sdbusplus::bus::bus bus;
+
+        // Watchdog object
+        phosphor::watchdog::Watchdog wdog;
+
+        // This is the default interval as given in Interface definition
+        milliseconds defaultInterval;
+
+        // Acceptable drift when we compare the interval to timeRemaining.
+        // This is needed since it depends on when do we get scheduled and it
+        // has happened that remaining time was off by few msecs.
+        milliseconds defaultDrift;
+
+    private:
+        // Dummy name for object path
+        // This is just to satisfy the constructor. Does not have
+        // a need to check if the objects paths have been created.
+        static constexpr auto TEST_PATH = "/test/path";
+};