sched-host-tran: handle with BMC time changing

Handle with different processes when BMC time is changed after scheduled time
is set.

Tested:
Case1: BMC time is changed to be later than current time but still earlier than
scheduled time
1. Get current time
 # date
   Tue Feb 25 07:07:44 UTC 2020
 # date +%s
   1582614271
2. Schedule time, do host transition after at 07:20:00 around
 # busctl get-property xyz.openbmc_project.State.ScheduledHostTransition \
   /xyz/openbmc_project/state/host0 \
   xyz.openbmc_project.State.ScheduledHostTransition ScheduledTime
   t 1582615256
3. Change BMC time to 07:19:00 around
 # busctl set-property xyz.openbmc_project.Time.Manager \
   /xyz/openbmc_project/time/bmc xyz.openbmc_project.Time.EpochTime Elapsed \
   t 1582615136000000
 # date
   Tue Feb 25 07:19:20 UTC 2020
 # date +%s
   1582615187
4. Host transition is done after 1 minute around,
   instead of waiting 13 mins around.

Case2: BMC time is changed after scheduled time is reached
Following Case1, the scheduled time is reached already,
1. Change BMC time to 07:10:00 around
 # busctl set-property xyz.openbmc_project.Time.Manager \
   /xyz/openbmc_project/time/bmc xyz.openbmc_project.Time.EpochTime Elapsed \
   t 1582614600000000
2. APP shows "The function Scheduled Host Transition is disabled", because
   the scheduled time is reached already and the scheduled time has been set
   to 0 after host transition is triggered.

Case3: BMC time is changed to be bigger than scheduled time before scheduled
time is reached
1. Set scheduled time 07:08:00 around
 # busctl set-property xyz.openbmc_project.State.ScheduledHostTransition \
   /xyz/openbmc_project/state/host0 \
   xyz.openbmc_project.State.ScheduledHostTransition ScheduledTime t 1582787314
2. Change BMC time to 07:10:00 around
 # busctl set-property xyz.openbmc_project.Time.Manager \
   /xyz/openbmc_project/time/bmc xyz.openbmc_project.Time.EpochTime Elapsed \
   t 1582787434000000
3. It will do host transition as requested.

Case4: BMC time is changed to be earlier than current time
1. Set scheduled time 07:10:00 around
 # busctl set-property xyz.openbmc_project.State.ScheduledHostTransition \
   /xyz/openbmc_project/state/host0 \
   xyz.openbmc_project.State.ScheduledHostTransition ScheduledTime t 1582787434
2. Change BMC time to 07:08:00 around
 # busctl set-property xyz.openbmc_project.Time.Manager \
   /xyz/openbmc_project/time/bmc xyz.openbmc_project.Time.EpochTime Elapsed \
   t 1582787314000000
3. App will wait 2 minutes more to do host transition.

Change-Id: I23228be944d1b2f71161317228c8b16d7f5ca4eb
Signed-off-by: Carol Wang <wangkair@cn.ibm.com>
diff --git a/test/test_scheduled_host_transition.cpp b/test/test_scheduled_host_transition.cpp
index 58e7aea..f148b59 100644
--- a/test/test_scheduled_host_transition.cpp
+++ b/test/test_scheduled_host_transition.cpp
@@ -17,6 +17,8 @@
 using namespace std::chrono;
 using InvalidTimeError =
     sdbusplus::xyz::openbmc_project::ScheduledTime::Error::InvalidTime;
+using HostTransition =
+    sdbusplus::xyz::openbmc_project::State::server::ScheduledHostTransition;
 
 class TestScheduledHostTransition : public testing::Test
 {
@@ -42,6 +44,11 @@
     {
         return scheduledHostTransition.timer.isEnabled();
     }
+
+    void bmcTimeChange()
+    {
+        scheduledHostTransition.handleTimeUpdates();
+    }
 };
 
 TEST_F(TestScheduledHostTransition, disableHostTransition)
@@ -78,6 +85,32 @@
     EXPECT_EQ(scheduledHostTransition.scheduledTransition(), Transition::Off);
 }
 
+TEST_F(TestScheduledHostTransition, bmcTimeChangeWithDisabledHostTransition)
+{
+    // Disable host transition
+    scheduledHostTransition.scheduledTime(0);
+    bmcTimeChange();
+    // Check timer
+    EXPECT_FALSE(isTimerEnabled());
+    // Check scheduled time
+    EXPECT_EQ(scheduledHostTransition.HostTransition::scheduledTime(), 0);
+}
+
+TEST_F(TestScheduledHostTransition, bmcTimeChangeBackward)
+{
+    // Current time is earlier than scheduled time due to BMC time changing
+    uint64_t schTime =
+        static_cast<uint64_t>((getCurrentTime() + seconds(60)).count());
+    // Set scheduled time, which is the same as bmc time is changed.
+    // But can't use this method to write another case like
+    // bmcTimeChangeForward, because set a scheduled time earlier than current
+    // time will throw an error.
+    scheduledHostTransition.scheduledTime(schTime);
+    bmcTimeChange();
+    // Check timer
+    EXPECT_TRUE(isTimerEnabled());
+}
+
 } // namespace manager
 } // namespace state
 } // namespace phosphor