update_engine: Add Update Time Restrictions

Implementation for the update time restrictions policy where the admin
is allowed to choose time interval in which updates will not be checked.

- Adds WeeklyTime and WeeklyTimeInterval classes to update_engine to be
able to easily do interval range checking and time operations easily in
the policy. Added the wiring so the classes can be used as Values and
BoxedValues.
- Adds disallowed_intervals member to device_policy_provider, since this
contains the policy dictated disallowed intervals. The intervals are
obtained from libpolicy, a function was added to convert them to the
new WeeklyTime classes. Added the corresponding changes to the device
policy provider header and interface.
- Added the policy to chromeos_policy.cc so that it's taken into account
in UpdateCheckAllowed.

BUG=chromium:852860
TEST=cros_workon_make update_engine --test

Change-Id: If62a2b3650adf149ba87790345e1eb62f0e1bb1f
Reviewed-on: https://chromium-review.googlesource.com/1119397
Commit-Ready: Adolfo Higueros <adokar@google.com>
Tested-by: Adolfo Higueros <adokar@google.com>
Reviewed-by: Amin Hassani <ahassani@chromium.org>
diff --git a/update_manager/chromeos_policy_unittest.cc b/update_manager/chromeos_policy_unittest.cc
index 524779f..184c241 100644
--- a/update_manager/chromeos_policy_unittest.cc
+++ b/update_manager/chromeos_policy_unittest.cc
@@ -21,6 +21,7 @@
 
 #include "update_engine/update_manager/next_update_check_policy_impl.h"
 #include "update_engine/update_manager/policy_test_utils.h"
+#include "update_engine/update_manager/weekly_time.h"
 
 using base::Time;
 using base::TimeDelta;
@@ -83,6 +84,9 @@
         new bool(false));
     fake_state_.device_policy_provider()->var_release_channel_delegated()->
         reset(new bool(true));
+    fake_state_.device_policy_provider()
+        ->var_disallowed_time_intervals()
+        ->reset(new WeeklyTimeIntervalVector());
   }
 
   // Configures the policy to return a desired value from UpdateCheckAllowed by
@@ -142,6 +146,26 @@
         EvalStatus::kSucceeded, &Policy::UpdateCheckAllowed, &result);
     return result.rollback_allowed;
   }
+
+  // Sets up a test with the given intervals and the current fake wallclock
+  // time.
+  void TestDisallowedTimeIntervals(const WeeklyTimeIntervalVector& intervals,
+                                   const EvalStatus& expected_status,
+                                   bool is_forced_update) {
+    SetUpDefaultTimeProvider();
+    SetUpdateCheckAllowed(true);
+
+    if (is_forced_update)
+      fake_state_.updater_provider()->var_forced_update_requested()->reset(
+          new UpdateRequestStatus(UpdateRequestStatus::kInteractive));
+    fake_state_.device_policy_provider()
+        ->var_disallowed_time_intervals()
+        ->reset(new WeeklyTimeIntervalVector(intervals));
+
+    // Check that |expected_status| matches the value of UpdateCheckAllowed
+    UpdateCheckParams result;
+    ExpectPolicyStatus(expected_status, &Policy::UpdateCheckAllowed, &result);
+  }
 };
 
 TEST_F(UmChromeOSPolicyTest, UpdateCheckAllowedWaitsForTheTimeout) {
@@ -304,6 +328,43 @@
 }
 
 TEST_F(UmChromeOSPolicyTest,
+       UpdateCheckAllowedWaitsForEndOfDisallowedInterval) {
+  // Check that the policy blocks during the disallowed checking intervals.
+  Time curr_time = fake_clock_.GetWallclockTime();
+  TestDisallowedTimeIntervals(
+      {WeeklyTimeInterval(
+          WeeklyTime::FromTime(curr_time),
+          WeeklyTime::FromTime(curr_time + TimeDelta::FromMinutes(1)))},
+      EvalStatus::kAskMeAgainLater,
+      false);
+}
+
+TEST_F(UmChromeOSPolicyTest,
+       UpdateCheckAllowedNoBlockOutsideDisallowedInterval) {
+  // Check that updates are allowed outside interval.
+  Time curr_time = fake_clock_.GetWallclockTime();
+  TestDisallowedTimeIntervals(
+      {WeeklyTimeInterval(
+          WeeklyTime::FromTime(curr_time - TimeDelta::FromMinutes(2)),
+          WeeklyTime::FromTime(curr_time - TimeDelta::FromMinutes(1)))},
+      EvalStatus::kSucceeded,
+      false);
+}
+
+TEST_F(UmChromeOSPolicyTest,
+       UpdateCheckAllowedDisallowedIntervalNoBlockWhenForced) {
+  // Check that updates are not blocked by this policy when an update is forced.
+  Time curr_time = fake_clock_.GetWallclockTime();
+  // Really big interval so that current time definitely falls in it.
+  TestDisallowedTimeIntervals(
+      {WeeklyTimeInterval(
+          WeeklyTime::FromTime(curr_time - TimeDelta::FromMinutes(1234)),
+          WeeklyTime::FromTime(curr_time + TimeDelta::FromMinutes(1234)))},
+      EvalStatus::kSucceeded,
+      true);
+}
+
+TEST_F(UmChromeOSPolicyTest,
        UpdateCheckAllowedUpdatesDisabledWhenNotEnoughSlotsAbUpdates) {
   // UpdateCheckAllowed should return false (kSucceeded) if the image booted
   // without enough slots to do A/B updates.