PolicyManager: UpdateCheckAllowed policy initial implementation.
This patch implements the UpdateCheckAllowed policy for ChromeOS
using the same logic we had on update_check_scheduler.cc. It checks
for updates onces every 45 minutes and does an exponential backoff
up to 4 hours when the update check fails. Some other parts of the
policy are not implemented, such as retry an update check with a
short delay on certain failures.
BUG=chromium:358269
TEST=Unittests added to the policy.
Change-Id: Ief8deff47fd6490bd70a22ba20abed05fcc37ab4
Reviewed-on: https://chromium-review.googlesource.com/197595
Reviewed-by: Alex Deymo <deymo@chromium.org>
Tested-by: Alex Deymo <deymo@chromium.org>
Commit-Queue: Alex Deymo <deymo@chromium.org>
diff --git a/policy_manager/chromeos_policy_unittest.cc b/policy_manager/chromeos_policy_unittest.cc
new file mode 100644
index 0000000..c4968ad
--- /dev/null
+++ b/policy_manager/chromeos_policy_unittest.cc
@@ -0,0 +1,136 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "update_engine/policy_manager/chromeos_policy.h"
+
+#include <string>
+
+#include <base/time/time.h>
+#include <gtest/gtest.h>
+
+#include "update_engine/fake_clock.h"
+#include "update_engine/policy_manager/evaluation_context.h"
+#include "update_engine/policy_manager/fake_state.h"
+#include "update_engine/policy_manager/pmtest_utils.h"
+
+using base::Time;
+using base::TimeDelta;
+using chromeos_update_engine::FakeClock;
+using std::string;
+
+namespace chromeos_policy_manager {
+
+class PmChromeOSPolicyTest : public ::testing::Test {
+ protected:
+ virtual void SetUp() {
+ SetUpDefaultClock();
+ eval_ctx_ = new EvaluationContext(&fake_clock_);
+ }
+
+ // Sets the clock to fixed values.
+ void SetUpDefaultClock() {
+ fake_clock_.SetMonotonicTime(Time::FromInternalValue(12345678L));
+ fake_clock_.SetWallclockTime(Time::FromInternalValue(12345678901234L));
+ }
+
+ void SetUpDefaultState() {
+ fake_state_.updater_provider()->var_updater_started_time()->reset(
+ new Time(fake_clock_.GetWallclockTime()));
+ fake_state_.updater_provider()->var_last_checked_time()->reset(
+ new Time(fake_clock_.GetWallclockTime()));
+ fake_state_.updater_provider()->var_consecutive_failed_update_checks()->
+ reset(new unsigned int(0));
+
+ fake_state_.random_provider()->var_seed()->reset(
+ new uint64_t(4)); // chosen by fair dice roll.
+ // guaranteed to be random.
+ }
+
+ // Runs the passed |policy_method| policy and expects it to return the
+ // |expected| return value.
+ template<typename T, typename R, typename... Args>
+ void ExpectPolicyStatus(
+ EvalStatus expected,
+ T policy_method,
+ R* result, Args... args) {
+ string error = "<None>";
+ eval_ctx_->ResetEvaluation();
+ EXPECT_EQ(expected,
+ (policy_.*policy_method)(eval_ctx_, &fake_state_, &error, result))
+ << "Returned error: " << error;
+ // TODO(deymo): Dump the context of the EvaluationContext on failure.
+ }
+
+ FakeClock fake_clock_;
+ FakeState fake_state_;
+ scoped_refptr<EvaluationContext> eval_ctx_;
+ ChromeOSPolicy policy_; // ChromeOSPolicy under test.
+};
+
+TEST_F(PmChromeOSPolicyTest, FirstCheckIsAtMostInitialIntervalAfterStart) {
+ Time next_update_check;
+
+ SetUpDefaultState();
+ ExpectPolicyStatus(EvalStatus::kSucceeded,
+ &ChromeOSPolicy::NextUpdateCheckTime, &next_update_check);
+
+ EXPECT_LE(fake_clock_.GetWallclockTime(), next_update_check);
+ EXPECT_GE(fake_clock_.GetWallclockTime() + TimeDelta::FromSeconds(
+ ChromeOSPolicy::kTimeoutInitialInterval +
+ ChromeOSPolicy::kTimeoutRegularFuzz), next_update_check);
+}
+
+TEST_F(PmChromeOSPolicyTest, ExponentialBackoffIsCapped) {
+ Time next_update_check;
+
+ SetUpDefaultState();
+ fake_state_.updater_provider()->var_consecutive_failed_update_checks()->
+ reset(new unsigned int(100));
+ ExpectPolicyStatus(EvalStatus::kSucceeded,
+ &ChromeOSPolicy::NextUpdateCheckTime, &next_update_check);
+
+ EXPECT_LE(fake_clock_.GetWallclockTime() + TimeDelta::FromSeconds(
+ ChromeOSPolicy::kTimeoutMaxBackoffInterval -
+ ChromeOSPolicy::kTimeoutRegularFuzz - 1), next_update_check);
+ EXPECT_GE(fake_clock_.GetWallclockTime() + TimeDelta::FromSeconds(
+ ChromeOSPolicy::kTimeoutMaxBackoffInterval +
+ ChromeOSPolicy::kTimeoutRegularFuzz), next_update_check);
+}
+
+TEST_F(PmChromeOSPolicyTest, UpdateCheckAllowedWaitsForTheTimeout) {
+ // We get the next update_check timestamp from the policy's private method
+ // and then we check the public method respects that value on the normal
+ // case.
+ Time next_update_check;
+ Time last_checked_time =
+ fake_clock_.GetWallclockTime() + TimeDelta::FromMinutes(1234);
+
+ SetUpDefaultClock();
+ SetUpDefaultState();
+ fake_state_.updater_provider()->var_last_checked_time()->reset(
+ new Time(last_checked_time));
+ ExpectPolicyStatus(EvalStatus::kSucceeded,
+ &ChromeOSPolicy::NextUpdateCheckTime, &next_update_check);
+
+ UpdateCheckParams result;
+
+ // Check that the policy blocks until the next_update_check is reached.
+ SetUpDefaultClock();
+ SetUpDefaultState();
+ fake_state_.updater_provider()->var_last_checked_time()->reset(
+ new Time(last_checked_time));
+ fake_clock_.SetWallclockTime(next_update_check - TimeDelta::FromSeconds(1));
+ ExpectPolicyStatus(EvalStatus::kAskMeAgainLater,
+ &Policy::UpdateCheckAllowed, &result);
+
+ SetUpDefaultClock();
+ SetUpDefaultState();
+ fake_state_.updater_provider()->var_last_checked_time()->reset(
+ new Time(last_checked_time));
+ fake_clock_.SetWallclockTime(next_update_check + TimeDelta::FromSeconds(1));
+ ExpectPolicyStatus(EvalStatus::kSucceeded,
+ &Policy::UpdateCheckAllowed, &result);
+}
+
+} // namespace chromeos_policy_manager