Initial implementation of HostEpoch
When host time is set, the diff between the BmcTime and the value is
saved to persistent storage;
When host time is retrieved, return the BmcTime plus the diff as
host's time.
Add the unit test cases for HostEpoch.
Change-Id: Ia55b93bfcba4f226ceaed8491136ea7afda7bd77
Signed-off-by: Lei YU <mine260309@gmail.com>
diff --git a/test/TestHostEpoch.cpp b/test/TestHostEpoch.cpp
new file mode 100644
index 0000000..dca8d72
--- /dev/null
+++ b/test/TestHostEpoch.cpp
@@ -0,0 +1,173 @@
+#include <sdbusplus/bus.hpp>
+#include <gtest/gtest.h>
+
+#include "host_epoch.hpp"
+#include "config.h"
+
+namespace phosphor
+{
+namespace time
+{
+
+using namespace std::chrono;
+using namespace std::chrono_literals;
+
+class TestHostEpoch : public testing::Test
+{
+ public:
+ using Mode = EpochBase::Mode;
+ using Owner = EpochBase::Owner;
+
+ sdbusplus::bus::bus bus;
+ HostEpoch hostEpoch;
+
+ static constexpr auto FILE_NOT_EXIST = "path/to/file-not-exist";
+ static constexpr auto FILE_OFFSET = "saved_host_offset";
+ static constexpr auto delta = 2s;
+
+ TestHostEpoch()
+ : bus(sdbusplus::bus::new_default()),
+ hostEpoch(bus, OBJPATH_HOST)
+ {
+ // Make sure the file does not exist
+ std::remove(FILE_NOT_EXIST);
+ }
+ ~TestHostEpoch()
+ {
+ // Cleanup test file
+ std::remove(FILE_OFFSET);
+ }
+
+ // Proxies for HostEpoch's private members and functions
+ Mode getTimeMode()
+ {
+ return hostEpoch.timeMode;
+ }
+ Owner getTimeOwner()
+ {
+ return hostEpoch.timeOwner;
+ }
+ template <typename T>
+ T readData(const char* fileName)
+ {
+ return HostEpoch::readData<T>(fileName);
+ }
+ template <typename T>
+ void writeData(const char* fileName, T&& data)
+ {
+ HostEpoch::writeData<T>(fileName, std::forward<T>(data));
+ }
+ microseconds getOffset()
+ {
+ return hostEpoch.offset;
+ }
+ void setTimeOwner(Owner owner)
+ {
+ hostEpoch.timeOwner = owner;
+ }
+};
+
+TEST_F(TestHostEpoch, empty)
+{
+ EXPECT_EQ(Mode::NTP, getTimeMode());
+ EXPECT_EQ(Owner::BMC, getTimeOwner());
+}
+
+TEST_F(TestHostEpoch, readDataFileNotExist)
+{
+ // When file does not exist, the default offset shall be 0
+ microseconds offset(0);
+ auto value = readData<decltype(offset)::rep>(FILE_NOT_EXIST);
+ EXPECT_EQ(0, value);
+}
+
+TEST_F(TestHostEpoch, writeAndReadData)
+{
+ // Write offset to file
+ microseconds offsetToWrite(1234567);
+ writeData<decltype(offsetToWrite)::rep>(FILE_OFFSET, offsetToWrite.count());
+
+ // Read it back
+ microseconds offsetToRead;
+ offsetToRead = microseconds(
+ readData<decltype(offsetToRead)::rep>(FILE_OFFSET));
+ EXPECT_EQ(offsetToWrite, offsetToRead);
+}
+
+TEST_F(TestHostEpoch, setElapsedNotAllowed)
+{
+ // By default offset shall be 0
+ EXPECT_EQ(0, getOffset().count());
+
+ // Set time in BMC mode is not allowed,
+ // so verify offset is still 0 after set time
+ microseconds diff = 1min;
+ hostEpoch.elapsed(hostEpoch.elapsed() + diff.count());
+ EXPECT_EQ(0, getOffset().count());
+}
+
+TEST_F(TestHostEpoch, setElapsedInFutureAndGet)
+{
+ // Set to HOST owner so that we can set elapsed
+ setTimeOwner(Owner::HOST);
+
+ // Get current time, and set future +1min time
+ auto t1 = hostEpoch.elapsed();
+ EXPECT_NE(0, t1);
+ microseconds diff = 1min;
+ auto t2 = t1 + diff.count();
+ hostEpoch.elapsed(t2);
+
+ // Verify that the offset shall be positive,
+ // and less or equal to diff, and shall be not too less.
+ auto offset = getOffset();
+ EXPECT_GT(offset, microseconds(0));
+ EXPECT_LE(offset, diff);
+ diff -= delta;
+ EXPECT_GE(offset, diff);
+
+ // Now get time shall be around future +1min time
+ auto epochNow = duration_cast<microseconds>(
+ system_clock::now().time_since_epoch()).count();
+ auto elapsedGot = hostEpoch.elapsed();
+ EXPECT_LT(epochNow, elapsedGot);
+ auto epochDiff = elapsedGot - epochNow;
+ diff = 1min;
+ EXPECT_GT(epochDiff, (diff - delta).count());
+ EXPECT_LT(epochDiff, (diff + delta).count());
+}
+
+TEST_F(TestHostEpoch, setElapsedInPastAndGet)
+{
+ // Set to HOST owner so that we can set elapsed
+ setTimeOwner(Owner::HOST);
+
+ // Get current time, and set past -1min time
+ auto t1 = hostEpoch.elapsed();
+ EXPECT_NE(0, t1);
+ microseconds diff = 1min;
+ auto t2 = t1 - diff.count();
+ hostEpoch.elapsed(t2);
+
+ // Verify that the offset shall be negative, and the absolute value
+ // shall be equal or greater than diff, and shall not be too greater
+ auto offset = getOffset();
+ EXPECT_LT(offset, microseconds(0));
+ offset = -offset;
+ EXPECT_GE(offset, diff);
+ diff += 10s;
+ EXPECT_LE(offset, diff);
+
+ // Now get time shall be around past -1min time
+ auto epochNow = duration_cast<microseconds>(
+ system_clock::now().time_since_epoch()).count();
+ auto elapsedGot = hostEpoch.elapsed();
+ EXPECT_LT(elapsedGot, epochNow);
+ auto epochDiff = epochNow - elapsedGot;
+ diff = 1min;
+ EXPECT_GT(epochDiff, (diff - delta).count());
+ EXPECT_LT(epochDiff, (diff + delta).count());
+}
+
+}
+}