| // Copyright (c) 2012 The Chromium 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 "components/policy/core/common/cloud/cloud_policy_refresh_scheduler.h" |
| |
| #include <stdint.h> |
| |
| #include <memory> |
| |
| #include "base/callback.h" |
| #include "base/compiler_specific.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/run_loop.h" |
| #include "base/test/scoped_task_environment.h" |
| #include "base/test/test_simple_task_runner.h" |
| #include "build/build_config.h" |
| #include "components/policy/core/common/cloud/cloud_policy_constants.h" |
| #include "components/policy/core/common/cloud/mock_cloud_policy_client.h" |
| #include "components/policy/core/common/cloud/mock_cloud_policy_service.h" |
| #include "components/policy/core/common/cloud/mock_cloud_policy_store.h" |
| #include "services/network/test/test_network_connection_tracker.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace em = enterprise_management; |
| |
| using testing::Mock; |
| using testing::_; |
| |
| namespace policy { |
| |
| namespace { |
| |
| const int64_t kPolicyRefreshRate = 4 * 60 * 60 * 1000; |
| |
| const int64_t kInitialCacheAgeMinutes = 1; |
| |
| } // namespace |
| |
| class CloudPolicyRefreshSchedulerTest : public testing::Test { |
| protected: |
| CloudPolicyRefreshSchedulerTest() |
| : service_(std::make_unique<MockCloudPolicyService>(&client_, &store_)), |
| task_runner_(new base::TestSimpleTaskRunner()) {} |
| |
| void SetUp() override { |
| client_.SetDMToken("token"); |
| |
| // Set up the protobuf timestamp to be one minute in the past. Since the |
| // protobuf field only has millisecond precision, we convert the actual |
| // value back to get a millisecond-clamped time stamp for the checks below. |
| store_.policy_.reset(new em::PolicyData()); |
| base::Time now = base::Time::NowFromSystemTime(); |
| base::TimeDelta initial_age = |
| base::TimeDelta::FromMinutes(kInitialCacheAgeMinutes); |
| store_.policy_->set_timestamp((now - initial_age).ToJavaTime()); |
| last_update_ = base::Time::FromJavaTime(store_.policy_->timestamp()); |
| last_update_ticks_ = base::TimeTicks::Now() + |
| (last_update_ - base::Time::NowFromSystemTime()); |
| } |
| |
| CloudPolicyRefreshScheduler* CreateRefreshScheduler() { |
| EXPECT_EQ(0u, task_runner_->NumPendingTasks()); |
| CloudPolicyRefreshScheduler* scheduler = new CloudPolicyRefreshScheduler( |
| &client_, &store_, service_.get(), task_runner_, |
| network::TestNetworkConnectionTracker::CreateGetter()); |
| // Make sure the NetworkConnectionTracker has been set up. |
| base::RunLoop().RunUntilIdle(); |
| scheduler->SetDesiredRefreshDelay(kPolicyRefreshRate); |
| return scheduler; |
| } |
| |
| void NotifyConnectionChanged() { |
| network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType( |
| network::mojom::ConnectionType::CONNECTION_WIFI); |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| void EmulateSleepThroughLastRefreshTime( |
| CloudPolicyRefreshScheduler* const scheduler) { |
| // Simulate a sleep of the device by decreasing the wall clock based refresh |
| // timestamp, so that the next refresh time point, calculated from it, turns |
| // out to be earlier than the next refresh time point, calculated from the |
| // ticks count clock. |
| scheduler->set_last_refresh_for_testing(base::Time::NowFromSystemTime() - |
| base::TimeDelta::FromDays(1)); |
| } |
| |
| base::TimeDelta GetLastDelay() const { |
| if (!task_runner_->HasPendingTask()) |
| return base::TimeDelta(); |
| return task_runner_->FinalPendingTaskDelay(); |
| } |
| |
| void CheckTiming(int64_t expected_delay_ms) const { |
| CheckTimingWithAge(base::TimeDelta::FromMilliseconds(expected_delay_ms), |
| base::TimeDelta()); |
| } |
| |
| // Checks that the latest refresh scheduled used an offset of |
| // |offset_from_last_refresh| from the time of the previous refresh. |
| // |cache_age| is how old the cache was when the refresh was issued. |
| void CheckTimingWithAge(const base::TimeDelta& offset_from_last_refresh, |
| const base::TimeDelta& cache_age) const { |
| EXPECT_TRUE(task_runner_->HasPendingTask()); |
| base::Time now(base::Time::NowFromSystemTime()); |
| base::TimeTicks now_ticks(base::TimeTicks::Now()); |
| // |last_update_| was updated and then a refresh was scheduled at time S, |
| // so |last_update_| is a bit before that. |
| // Now is a bit later, N. |
| // GetLastDelay() + S is the time when the refresh will run, T. |
| // |cache_age| is the age of the cache at time S. It was thus created at |
| // S - cache_age. |
| // |
| // Schematically: |
| // |
| // . S . N . . . . . . . T . . . . |
| // | | | |
| // set "last_refresh_" and then scheduled the next refresh; the cache |
| // was "cache_age" old at this point. |
| // | | |
| // some time elapsed on the test execution since then; |
| // this is the current time, "now" |
| // | |
| // the refresh will execute at this time |
| // |
| // So the exact delay is T - S - |cache_age|, but we don't have S here. |
| // |
| // |last_update_| was a bit before S, so if |
| // elapsed = now - |last_update_| then the delay is more than |
| // |offset_from_last_refresh| - elapsed. |
| // |
| // The delay is also less than offset_from_last_refresh, because some time |
| // already elapsed. Additionally, if the cache was already considered old |
| // when the schedule was performed then its age at that time has been |
| // discounted from the delay. So the delay is a bit less than |
| // |offset_from_last_refresh - cache_age|. |
| // The logic of time based on TimeTicks is added to be on the safe side, |
| // since CloudPolicyRefreshScheduler implementation is based on both, the |
| // system time and the time in TimeTicks. |
| base::TimeDelta system_delta = (now - last_update_); |
| base::TimeDelta ticks_delta = (now_ticks - last_update_ticks_); |
| EXPECT_GE(GetLastDelay(), |
| offset_from_last_refresh - std::max(system_delta, ticks_delta)); |
| EXPECT_LE(GetLastDelay(), offset_from_last_refresh - cache_age); |
| } |
| |
| void CheckInitialRefresh(bool with_invalidations) const { |
| #if defined(OS_ANDROID) || defined(OS_IOS) |
| // The mobile platforms take the cache age into account for the initial |
| // fetch. Usually the cache age is ignored for the initial refresh, but on |
| // mobile it's used to restrain from refreshing on every startup. |
| base::TimeDelta rate = base::TimeDelta::FromMilliseconds( |
| with_invalidations |
| ? CloudPolicyRefreshScheduler::kWithInvalidationsRefreshDelayMs |
| : kPolicyRefreshRate); |
| CheckTimingWithAge(rate, |
| base::TimeDelta::FromMinutes(kInitialCacheAgeMinutes)); |
| #else |
| // Other platforms refresh immediately. |
| EXPECT_EQ(base::TimeDelta(), GetLastDelay()); |
| #endif |
| } |
| |
| void SetLastUpdateToNow() { |
| last_update_ = base::Time::NowFromSystemTime(); |
| last_update_ticks_ = base::TimeTicks::Now(); |
| } |
| |
| base::test::ScopedTaskEnvironment task_environment_; |
| MockCloudPolicyClient client_; |
| MockCloudPolicyStore store_; |
| std::unique_ptr<MockCloudPolicyService> service_; |
| scoped_refptr<base::TestSimpleTaskRunner> task_runner_; |
| |
| // Base time for the refresh that the scheduler should be using. |
| base::Time last_update_; |
| base::TimeTicks last_update_ticks_; |
| }; |
| |
| TEST_F(CloudPolicyRefreshSchedulerTest, InitialRefreshNoPolicy) { |
| store_.policy_.reset(); |
| std::unique_ptr<CloudPolicyRefreshScheduler> scheduler( |
| CreateRefreshScheduler()); |
| EXPECT_TRUE(task_runner_->HasPendingTask()); |
| EXPECT_EQ(GetLastDelay(), base::TimeDelta()); |
| EXPECT_CALL(*service_.get(), RefreshPolicy(_)).Times(1); |
| EXPECT_CALL(client_, FetchPolicy()).Times(1); |
| task_runner_->RunUntilIdle(); |
| } |
| |
| TEST_F(CloudPolicyRefreshSchedulerTest, InitialRefreshUnmanaged) { |
| store_.policy_->set_state(em::PolicyData::UNMANAGED); |
| std::unique_ptr<CloudPolicyRefreshScheduler> scheduler( |
| CreateRefreshScheduler()); |
| CheckTiming(CloudPolicyRefreshScheduler::kUnmanagedRefreshDelayMs); |
| EXPECT_CALL(*service_.get(), RefreshPolicy(_)).Times(1); |
| EXPECT_CALL(client_, FetchPolicy()).Times(1); |
| task_runner_->RunUntilIdle(); |
| } |
| |
| TEST_F(CloudPolicyRefreshSchedulerTest, InitialRefreshManagedNotYetFetched) { |
| std::unique_ptr<CloudPolicyRefreshScheduler> scheduler( |
| CreateRefreshScheduler()); |
| EXPECT_TRUE(task_runner_->HasPendingTask()); |
| CheckInitialRefresh(false); |
| EXPECT_CALL(*service_.get(), RefreshPolicy(_)).Times(1); |
| EXPECT_CALL(client_, FetchPolicy()).Times(1); |
| task_runner_->RunUntilIdle(); |
| } |
| |
| TEST_F(CloudPolicyRefreshSchedulerTest, InitialRefreshManagedAlreadyFetched) { |
| SetLastUpdateToNow(); |
| client_.SetPolicy(dm_protocol::kChromeUserPolicyType, std::string(), |
| em::PolicyFetchResponse()); |
| std::unique_ptr<CloudPolicyRefreshScheduler> scheduler( |
| CreateRefreshScheduler()); |
| CheckTiming(kPolicyRefreshRate); |
| EXPECT_CALL(*service_.get(), RefreshPolicy(_)).Times(1); |
| EXPECT_CALL(client_, FetchPolicy()).Times(1); |
| task_runner_->RunUntilIdle(); |
| } |
| |
| TEST_F(CloudPolicyRefreshSchedulerTest, Unregistered) { |
| client_.SetDMToken(std::string()); |
| std::unique_ptr<CloudPolicyRefreshScheduler> scheduler( |
| CreateRefreshScheduler()); |
| client_.NotifyPolicyFetched(); |
| client_.NotifyRegistrationStateChanged(); |
| client_.NotifyClientError(); |
| scheduler->SetDesiredRefreshDelay(12 * 60 * 60 * 1000); |
| store_.NotifyStoreLoaded(); |
| store_.NotifyStoreError(); |
| EXPECT_FALSE(task_runner_->HasPendingTask()); |
| } |
| |
| TEST_F(CloudPolicyRefreshSchedulerTest, RefreshSoon) { |
| std::unique_ptr<CloudPolicyRefreshScheduler> scheduler( |
| CreateRefreshScheduler()); |
| EXPECT_CALL(*service_.get(), RefreshPolicy(_)).Times(1); |
| EXPECT_CALL(client_, FetchPolicy()).Times(1); |
| scheduler->RefreshSoon(); |
| task_runner_->RunUntilIdle(); |
| Mock::VerifyAndClearExpectations(&client_); |
| } |
| |
| TEST_F(CloudPolicyRefreshSchedulerTest, RefreshSoonOverriding) { |
| std::unique_ptr<CloudPolicyRefreshScheduler> scheduler( |
| CreateRefreshScheduler()); |
| |
| // The refresh scheduled for soon overrides the previously scheduled refresh. |
| scheduler->RefreshSoon(); |
| CheckTiming(0); |
| |
| // The refresh scheduled for soon is not overridden by the change of the |
| // desired refresh delay. |
| const int64_t kNewPolicyRefreshRate = 12 * 60 * 60 * 1000; |
| scheduler->SetDesiredRefreshDelay(kNewPolicyRefreshRate); |
| CheckTiming(0); |
| |
| // The refresh scheduled for soon is not overridden by the notification on the |
| // already fetched policy. |
| client_.SetPolicy(dm_protocol::kChromeUserPolicyType, std::string(), |
| em::PolicyFetchResponse()); |
| store_.NotifyStoreLoaded(); |
| CheckTiming(0); |
| |
| EXPECT_CALL(*service_.get(), RefreshPolicy(_)).Times(1); |
| EXPECT_CALL(client_, FetchPolicy()).Times(1); |
| task_runner_->RunUntilIdle(); |
| Mock::VerifyAndClearExpectations(&client_); |
| |
| // The next refresh is scheduled according to the normal rate. |
| client_.NotifyPolicyFetched(); |
| CheckTiming(kNewPolicyRefreshRate); |
| } |
| |
| TEST_F(CloudPolicyRefreshSchedulerTest, InvalidationsAvailable) { |
| std::unique_ptr<CloudPolicyRefreshScheduler> scheduler( |
| new CloudPolicyRefreshScheduler( |
| &client_, &store_, service_.get(), task_runner_, |
| network::TestNetworkConnectionTracker::CreateGetter())); |
| scheduler->SetDesiredRefreshDelay(kPolicyRefreshRate); |
| |
| // The scheduler has scheduled refreshes at the initial refresh rate. |
| EXPECT_EQ(2u, task_runner_->NumPendingTasks()); |
| |
| // Signal that invalidations are available. |
| scheduler->SetInvalidationServiceAvailability(true); |
| EXPECT_EQ(CloudPolicyRefreshScheduler::kWithInvalidationsRefreshDelayMs, |
| scheduler->GetActualRefreshDelay()); |
| EXPECT_EQ(3u, task_runner_->NumPendingTasks()); |
| |
| CheckInitialRefresh(true); |
| |
| EXPECT_CALL(*service_.get(), RefreshPolicy(_)).Times(1); |
| EXPECT_CALL(client_, FetchPolicy()).Times(1); |
| task_runner_->RunPendingTasks(); |
| Mock::VerifyAndClearExpectations(&client_); |
| |
| // Complete that fetch. |
| SetLastUpdateToNow(); |
| client_.NotifyPolicyFetched(); |
| |
| // The next refresh has been scheduled using a lower refresh rate. |
| EXPECT_EQ(1u, task_runner_->NumPendingTasks()); |
| CheckTiming(CloudPolicyRefreshScheduler::kWithInvalidationsRefreshDelayMs); |
| } |
| |
| TEST_F(CloudPolicyRefreshSchedulerTest, InvalidationsNotAvailable) { |
| std::unique_ptr<CloudPolicyRefreshScheduler> scheduler( |
| new CloudPolicyRefreshScheduler( |
| &client_, &store_, service_.get(), task_runner_, |
| network::TestNetworkConnectionTracker::CreateGetter())); |
| scheduler->SetDesiredRefreshDelay(kPolicyRefreshRate); |
| |
| // Signal that invalidations are not available. The scheduler will not |
| // schedule refreshes since the available state is not changed. |
| for (int i = 0; i < 10; ++i) { |
| scheduler->SetInvalidationServiceAvailability(false); |
| EXPECT_EQ(2u, task_runner_->NumPendingTasks()); |
| } |
| |
| // This scheduled the initial refresh. |
| CheckInitialRefresh(false); |
| EXPECT_EQ(kPolicyRefreshRate, scheduler->GetActualRefreshDelay()); |
| |
| // Perform that fetch now. |
| EXPECT_CALL(*service_.get(), RefreshPolicy(_)).Times(1); |
| EXPECT_CALL(client_, FetchPolicy()).Times(1); |
| task_runner_->RunPendingTasks(); |
| Mock::VerifyAndClearExpectations(&client_); |
| |
| // Complete that fetch. |
| SetLastUpdateToNow(); |
| client_.NotifyPolicyFetched(); |
| |
| // The next refresh has been scheduled at the normal rate. |
| EXPECT_EQ(1u, task_runner_->NumPendingTasks()); |
| CheckTiming(kPolicyRefreshRate); |
| } |
| |
| TEST_F(CloudPolicyRefreshSchedulerTest, InvalidationsOffAndOn) { |
| std::unique_ptr<CloudPolicyRefreshScheduler> scheduler( |
| new CloudPolicyRefreshScheduler( |
| &client_, &store_, service_.get(), task_runner_, |
| network::TestNetworkConnectionTracker::CreateGetter())); |
| scheduler->SetDesiredRefreshDelay(kPolicyRefreshRate); |
| scheduler->SetInvalidationServiceAvailability(true); |
| // Initial fetch. |
| EXPECT_CALL(*service_.get(), RefreshPolicy(_)).Times(1); |
| EXPECT_CALL(client_, FetchPolicy()).Times(1); |
| task_runner_->RunUntilIdle(); |
| Mock::VerifyAndClearExpectations(&client_); |
| SetLastUpdateToNow(); |
| client_.NotifyPolicyFetched(); |
| |
| // The next refresh has been scheduled using a lower refresh rate. |
| CheckTiming(CloudPolicyRefreshScheduler::kWithInvalidationsRefreshDelayMs); |
| |
| // If the service goes down and comes back up before the timeout then a |
| // refresh is rescheduled at the lower rate again; after executing all |
| // pending tasks only 1 fetch is performed. |
| scheduler->SetInvalidationServiceAvailability(false); |
| scheduler->SetInvalidationServiceAvailability(true); |
| // The next refresh has been scheduled using a lower refresh rate. |
| EXPECT_CALL(*service_.get(), RefreshPolicy(_)).Times(1); |
| EXPECT_CALL(client_, FetchPolicy()).Times(1); |
| CheckTiming(CloudPolicyRefreshScheduler::kWithInvalidationsRefreshDelayMs); |
| task_runner_->RunPendingTasks(); |
| Mock::VerifyAndClearExpectations(&client_); |
| } |
| |
| TEST_F(CloudPolicyRefreshSchedulerTest, InvalidationsDisconnected) { |
| std::unique_ptr<CloudPolicyRefreshScheduler> scheduler( |
| new CloudPolicyRefreshScheduler( |
| &client_, &store_, service_.get(), task_runner_, |
| network::TestNetworkConnectionTracker::CreateGetter())); |
| scheduler->SetDesiredRefreshDelay(kPolicyRefreshRate); |
| scheduler->SetInvalidationServiceAvailability(true); |
| // Initial fetch. |
| EXPECT_CALL(*service_.get(), RefreshPolicy(_)).Times(1); |
| EXPECT_CALL(client_, FetchPolicy()).Times(1); |
| task_runner_->RunUntilIdle(); |
| Mock::VerifyAndClearExpectations(&client_); |
| SetLastUpdateToNow(); |
| client_.NotifyPolicyFetched(); |
| |
| // The next refresh has been scheduled using a lower refresh rate. |
| // Flush that task. |
| CheckTiming(CloudPolicyRefreshScheduler::kWithInvalidationsRefreshDelayMs); |
| EXPECT_CALL(*service_.get(), RefreshPolicy(_)).Times(1); |
| EXPECT_CALL(client_, FetchPolicy()).Times(1); |
| task_runner_->RunPendingTasks(); |
| Mock::VerifyAndClearExpectations(&client_); |
| |
| // If the service goes down then the refresh scheduler falls back on the |
| // default polling rate. |
| scheduler->SetInvalidationServiceAvailability(false); |
| CheckTiming(kPolicyRefreshRate); |
| } |
| |
| TEST_F(CloudPolicyRefreshSchedulerTest, OnConnectionChangedUnregistered) { |
| client_.SetDMToken(std::string()); |
| std::unique_ptr<CloudPolicyRefreshScheduler> scheduler( |
| CreateRefreshScheduler()); |
| |
| client_.NotifyClientError(); |
| EXPECT_FALSE(task_runner_->HasPendingTask()); |
| |
| EmulateSleepThroughLastRefreshTime(scheduler.get()); |
| scheduler->OnConnectionChanged( |
| network::mojom::ConnectionType::CONNECTION_WIFI); |
| EXPECT_FALSE(task_runner_->HasPendingTask()); |
| } |
| |
| // TODO(igorcov): Before sleep in normal flow there's a task pending. When the |
| // device wakes up, OnConnectionChanged is called which should cancel the |
| // pending task and queue a new task to run earlier. It is desirable to |
| // simulate that flow here. |
| TEST_F(CloudPolicyRefreshSchedulerTest, OnConnectionChangedAfterSleep) { |
| std::unique_ptr<CloudPolicyRefreshScheduler> scheduler( |
| CreateRefreshScheduler()); |
| |
| client_.SetPolicy(dm_protocol::kChromeUserPolicyType, std::string(), |
| em::PolicyFetchResponse()); |
| task_runner_->RunPendingTasks(); |
| EXPECT_FALSE(task_runner_->HasPendingTask()); |
| |
| EmulateSleepThroughLastRefreshTime(scheduler.get()); |
| scheduler->OnConnectionChanged( |
| network::mojom::ConnectionType::CONNECTION_WIFI); |
| EXPECT_TRUE(task_runner_->HasPendingTask()); |
| task_runner_->ClearPendingTasks(); |
| } |
| |
| class CloudPolicyRefreshSchedulerSteadyStateTest |
| : public CloudPolicyRefreshSchedulerTest { |
| protected: |
| CloudPolicyRefreshSchedulerSteadyStateTest() {} |
| |
| void SetUp() override { |
| refresh_scheduler_.reset(CreateRefreshScheduler()); |
| refresh_scheduler_->SetDesiredRefreshDelay(kPolicyRefreshRate); |
| CloudPolicyRefreshSchedulerTest::SetUp(); |
| SetLastUpdateToNow(); |
| client_.NotifyPolicyFetched(); |
| CheckTiming(kPolicyRefreshRate); |
| } |
| |
| std::unique_ptr<CloudPolicyRefreshScheduler> refresh_scheduler_; |
| }; |
| |
| TEST_F(CloudPolicyRefreshSchedulerSteadyStateTest, OnPolicyFetched) { |
| client_.NotifyPolicyFetched(); |
| CheckTiming(kPolicyRefreshRate); |
| } |
| |
| TEST_F(CloudPolicyRefreshSchedulerSteadyStateTest, OnRegistrationStateChanged) { |
| client_.SetDMToken("new_token"); |
| client_.NotifyRegistrationStateChanged(); |
| EXPECT_EQ(GetLastDelay(), base::TimeDelta()); |
| |
| task_runner_->ClearPendingTasks(); |
| client_.SetDMToken(std::string()); |
| client_.NotifyRegistrationStateChanged(); |
| EXPECT_FALSE(task_runner_->HasPendingTask()); |
| } |
| |
| TEST_F(CloudPolicyRefreshSchedulerSteadyStateTest, OnStoreLoaded) { |
| store_.NotifyStoreLoaded(); |
| CheckTiming(kPolicyRefreshRate); |
| } |
| |
| TEST_F(CloudPolicyRefreshSchedulerSteadyStateTest, OnStoreError) { |
| task_runner_->ClearPendingTasks(); |
| store_.NotifyStoreError(); |
| EXPECT_FALSE(task_runner_->HasPendingTask()); |
| } |
| |
| TEST_F(CloudPolicyRefreshSchedulerSteadyStateTest, RefreshDelayChange) { |
| const int delay_short_ms = 5 * 60 * 1000; |
| refresh_scheduler_->SetDesiredRefreshDelay(delay_short_ms); |
| CheckTiming(CloudPolicyRefreshScheduler::kRefreshDelayMinMs); |
| |
| const int delay_ms = 12 * 60 * 60 * 1000; |
| refresh_scheduler_->SetDesiredRefreshDelay(delay_ms); |
| CheckTiming(delay_ms); |
| |
| const int delay_long_ms = 20 * 24 * 60 * 60 * 1000; |
| refresh_scheduler_->SetDesiredRefreshDelay(delay_long_ms); |
| CheckTiming(CloudPolicyRefreshScheduler::kRefreshDelayMaxMs); |
| } |
| |
| TEST_F(CloudPolicyRefreshSchedulerSteadyStateTest, OnConnectionChanged) { |
| client_.SetStatus(DM_STATUS_REQUEST_FAILED); |
| NotifyConnectionChanged(); |
| EXPECT_EQ(GetLastDelay(), base::TimeDelta()); |
| } |
| |
| struct ClientErrorTestParam { |
| DeviceManagementStatus client_error; |
| int64_t expected_delay_ms; |
| int backoff_factor; |
| }; |
| |
| static const ClientErrorTestParam kClientErrorTestCases[] = { |
| {DM_STATUS_REQUEST_INVALID, |
| CloudPolicyRefreshScheduler::kUnmanagedRefreshDelayMs, 1}, |
| {DM_STATUS_REQUEST_FAILED, |
| CloudPolicyRefreshScheduler::kInitialErrorRetryDelayMs, 2}, |
| {DM_STATUS_TEMPORARY_UNAVAILABLE, |
| CloudPolicyRefreshScheduler::kInitialErrorRetryDelayMs, 2}, |
| {DM_STATUS_HTTP_STATUS_ERROR, |
| CloudPolicyRefreshScheduler::kUnmanagedRefreshDelayMs, 1}, |
| {DM_STATUS_RESPONSE_DECODING_ERROR, |
| CloudPolicyRefreshScheduler::kUnmanagedRefreshDelayMs, 1}, |
| {DM_STATUS_SERVICE_MANAGEMENT_NOT_SUPPORTED, |
| CloudPolicyRefreshScheduler::kUnmanagedRefreshDelayMs, 1}, |
| {DM_STATUS_SERVICE_DEVICE_NOT_FOUND, -1, 1}, |
| {DM_STATUS_SERVICE_MANAGEMENT_TOKEN_INVALID, -1, 1}, |
| {DM_STATUS_SERVICE_ACTIVATION_PENDING, kPolicyRefreshRate, 1}, |
| {DM_STATUS_SERVICE_INVALID_SERIAL_NUMBER, -1, 1}, |
| {DM_STATUS_SERVICE_MISSING_LICENSES, -1, 1}, |
| {DM_STATUS_SERVICE_DEVICE_ID_CONFLICT, -1, 1}, |
| {DM_STATUS_SERVICE_POLICY_NOT_FOUND, kPolicyRefreshRate, 1}, |
| {DM_STATUS_SERVICE_CONSUMER_ACCOUNT_WITH_PACKAGED_LICENSE, -1, 1}, |
| }; |
| |
| class CloudPolicyRefreshSchedulerClientErrorTest |
| : public CloudPolicyRefreshSchedulerSteadyStateTest, |
| public testing::WithParamInterface<ClientErrorTestParam> {}; |
| |
| TEST_P(CloudPolicyRefreshSchedulerClientErrorTest, OnClientError) { |
| client_.SetStatus(GetParam().client_error); |
| task_runner_->ClearPendingTasks(); |
| |
| // See whether the error triggers the right refresh delay. |
| int64_t expected_delay_ms = GetParam().expected_delay_ms; |
| client_.NotifyClientError(); |
| if (expected_delay_ms >= 0) { |
| CheckTiming(expected_delay_ms); |
| |
| // Check whether exponential backoff is working as expected and capped at |
| // the regular refresh rate (if applicable). |
| do { |
| expected_delay_ms *= GetParam().backoff_factor; |
| SetLastUpdateToNow(); |
| client_.NotifyClientError(); |
| CheckTiming(std::max(std::min(expected_delay_ms, kPolicyRefreshRate), |
| GetParam().expected_delay_ms)); |
| } while (GetParam().backoff_factor > 1 && |
| expected_delay_ms <= kPolicyRefreshRate); |
| } else { |
| EXPECT_EQ(base::TimeDelta(), GetLastDelay()); |
| EXPECT_FALSE(task_runner_->HasPendingTask()); |
| } |
| } |
| |
| INSTANTIATE_TEST_CASE_P(CloudPolicyRefreshSchedulerClientErrorTest, |
| CloudPolicyRefreshSchedulerClientErrorTest, |
| testing::ValuesIn(kClientErrorTestCases)); |
| |
| } // namespace policy |