Home | History | Annotate | Download | only in cloud
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/callback.h"
      6 #include "base/compiler_specific.h"
      7 #include "base/memory/ref_counted.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "base/message_loop/message_loop.h"
     10 #include "base/test/test_simple_task_runner.h"
     11 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
     12 #include "components/policy/core/common/cloud/cloud_policy_refresh_scheduler.h"
     13 #include "components/policy/core/common/cloud/mock_cloud_policy_client.h"
     14 #include "components/policy/core/common/cloud/mock_cloud_policy_store.h"
     15 #include "testing/gmock/include/gmock/gmock.h"
     16 #include "testing/gtest/include/gtest/gtest.h"
     17 
     18 namespace em = enterprise_management;
     19 
     20 using testing::Mock;
     21 
     22 namespace policy {
     23 
     24 namespace {
     25 
     26 const int64 kPolicyRefreshRate = 4 * 60 * 60 * 1000;
     27 
     28 const int64 kInitialCacheAgeMinutes = 1;
     29 
     30 }  // namespace
     31 
     32 class CloudPolicyRefreshSchedulerTest : public testing::Test {
     33  protected:
     34   CloudPolicyRefreshSchedulerTest()
     35       : task_runner_(new base::TestSimpleTaskRunner()),
     36         network_change_notifier_(net::NetworkChangeNotifier::CreateMock()) {}
     37 
     38   virtual void SetUp() OVERRIDE {
     39     client_.SetDMToken("token");
     40 
     41     // Set up the protobuf timestamp to be one minute in the past. Since the
     42     // protobuf field only has millisecond precision, we convert the actual
     43     // value back to get a millisecond-clamped time stamp for the checks below.
     44     store_.policy_.reset(new em::PolicyData());
     45     base::Time now = base::Time::NowFromSystemTime();
     46     base::TimeDelta initial_age =
     47         base::TimeDelta::FromMinutes(kInitialCacheAgeMinutes);
     48     store_.policy_->set_timestamp(
     49         ((now - initial_age) - base::Time::UnixEpoch()).InMilliseconds());
     50     last_update_ =
     51         base::Time::UnixEpoch() +
     52         base::TimeDelta::FromMilliseconds(store_.policy_->timestamp());
     53   }
     54 
     55   CloudPolicyRefreshScheduler* CreateRefreshScheduler() {
     56     EXPECT_EQ(0u, task_runner_->GetPendingTasks().size());
     57     CloudPolicyRefreshScheduler* scheduler =
     58         new CloudPolicyRefreshScheduler(&client_, &store_, task_runner_);
     59     scheduler->SetRefreshDelay(kPolicyRefreshRate);
     60     return scheduler;
     61   }
     62 
     63   void NotifyIPAddressChanged() {
     64     net::NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
     65     loop_.RunUntilIdle();
     66   }
     67 
     68   base::TimeDelta GetLastDelay() const {
     69     const std::deque<base::TestPendingTask>& pending_tasks =
     70         task_runner_->GetPendingTasks();
     71     return
     72         pending_tasks.empty() ? base::TimeDelta() : pending_tasks.back().delay;
     73   }
     74 
     75   void CheckTiming(int64 expected_delay_ms) const {
     76     CheckTimingWithAge(base::TimeDelta::FromMilliseconds(expected_delay_ms),
     77                        base::TimeDelta());
     78   }
     79 
     80   // Checks that the latest refresh scheduled used an offset of
     81   // |offset_from_last_refresh| from the time of the previous refresh.
     82   // |cache_age| is how old the cache was when the refresh was issued.
     83   void CheckTimingWithAge(const base::TimeDelta& offset_from_last_refresh,
     84                           const base::TimeDelta& cache_age) const {
     85     EXPECT_FALSE(task_runner_->GetPendingTasks().empty());
     86     base::Time now(base::Time::NowFromSystemTime());
     87     // |last_update_| was updated and then a refresh was scheduled at time S,
     88     // so |last_update_| is a bit before that.
     89     // Now is a bit later, N.
     90     // GetLastDelay() + S is the time when the refresh will run, T.
     91     // |cache_age| is the age of the cache at time S. It was thus created at
     92     // S - cache_age.
     93     //
     94     // Schematically:
     95     //
     96     // . S . N . . . . . . . T . . . .
     97     //   |   |               |
     98     //   set "last_refresh_" and then scheduled the next refresh; the cache
     99     //   was "cache_age" old at this point.
    100     //       |               |
    101     //       some time elapsed on the test execution since then;
    102     //       this is the current time, "now"
    103     //                       |
    104     //                       the refresh will execute at this time
    105     //
    106     // So the exact delay is T - S - |cache_age|, but we don't have S here.
    107     //
    108     // |last_update_| was a bit before S, so if
    109     // elapsed = now - |last_update_| then the delay is more than
    110     // |offset_from_last_refresh| - elapsed.
    111     //
    112     // The delay is also less than offset_from_last_refresh, because some time
    113     // already elapsed. Additionally, if the cache was already considered old
    114     // when the schedule was performed then its age at that time has been
    115     // discounted from the delay. So the delay is a bit less than
    116     // |offset_from_last_refresh - cache_age|.
    117     EXPECT_GE(GetLastDelay(), offset_from_last_refresh - (now - last_update_));
    118     EXPECT_LE(GetLastDelay(), offset_from_last_refresh - cache_age);
    119   }
    120 
    121   void CheckInitialRefresh(bool with_invalidations) const {
    122 #if defined(OS_ANDROID) || defined(OS_IOS)
    123     // The mobile platforms take the cache age into account for the initial
    124     // fetch. Usually the cache age is ignored for the initial refresh, but on
    125     // mobile it's used to restrain from refreshing on every startup.
    126     base::TimeDelta rate = base::TimeDelta::FromMilliseconds(
    127         with_invalidations
    128             ? CloudPolicyRefreshScheduler::kWithInvalidationsRefreshDelayMs
    129             : kPolicyRefreshRate);
    130     CheckTimingWithAge(rate,
    131                        base::TimeDelta::FromMinutes(kInitialCacheAgeMinutes));
    132 #else
    133     // Other platforms refresh immediately.
    134     EXPECT_EQ(base::TimeDelta(), GetLastDelay());
    135 #endif
    136   }
    137 
    138   base::MessageLoop loop_;
    139   MockCloudPolicyClient client_;
    140   MockCloudPolicyStore store_;
    141   scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
    142   scoped_ptr<net::NetworkChangeNotifier> network_change_notifier_;
    143 
    144   // Base time for the refresh that the scheduler should be using.
    145   base::Time last_update_;
    146 };
    147 
    148 TEST_F(CloudPolicyRefreshSchedulerTest, InitialRefreshNoPolicy) {
    149   store_.policy_.reset();
    150   scoped_ptr<CloudPolicyRefreshScheduler> scheduler(CreateRefreshScheduler());
    151   EXPECT_FALSE(task_runner_->GetPendingTasks().empty());
    152   EXPECT_EQ(GetLastDelay(), base::TimeDelta());
    153   EXPECT_CALL(client_, FetchPolicy()).Times(1);
    154   task_runner_->RunUntilIdle();
    155 }
    156 
    157 TEST_F(CloudPolicyRefreshSchedulerTest, InitialRefreshUnmanaged) {
    158   store_.policy_->set_state(em::PolicyData::UNMANAGED);
    159   scoped_ptr<CloudPolicyRefreshScheduler> scheduler(CreateRefreshScheduler());
    160   CheckTiming(CloudPolicyRefreshScheduler::kUnmanagedRefreshDelayMs);
    161   EXPECT_CALL(client_, FetchPolicy()).Times(1);
    162   task_runner_->RunUntilIdle();
    163 }
    164 
    165 TEST_F(CloudPolicyRefreshSchedulerTest, InitialRefreshManagedNotYetFetched) {
    166   scoped_ptr<CloudPolicyRefreshScheduler> scheduler(CreateRefreshScheduler());
    167   EXPECT_FALSE(task_runner_->GetPendingTasks().empty());
    168   CheckInitialRefresh(false);
    169   EXPECT_CALL(client_, FetchPolicy()).Times(1);
    170   task_runner_->RunUntilIdle();
    171 }
    172 
    173 TEST_F(CloudPolicyRefreshSchedulerTest, InitialRefreshManagedAlreadyFetched) {
    174   last_update_ = base::Time::NowFromSystemTime();
    175   client_.SetPolicy(PolicyNamespaceKey(dm_protocol::kChromeUserPolicyType,
    176                                        std::string()),
    177       em::PolicyFetchResponse());
    178   scoped_ptr<CloudPolicyRefreshScheduler> scheduler(CreateRefreshScheduler());
    179   CheckTiming(kPolicyRefreshRate);
    180   EXPECT_CALL(client_, FetchPolicy()).Times(1);
    181   task_runner_->RunUntilIdle();
    182 }
    183 
    184 TEST_F(CloudPolicyRefreshSchedulerTest, Unregistered) {
    185   client_.SetDMToken(std::string());
    186   scoped_ptr<CloudPolicyRefreshScheduler> scheduler(CreateRefreshScheduler());
    187   client_.NotifyPolicyFetched();
    188   client_.NotifyRegistrationStateChanged();
    189   client_.NotifyClientError();
    190   scheduler->SetRefreshDelay(12 * 60 * 60 * 1000);
    191   store_.NotifyStoreLoaded();
    192   store_.NotifyStoreError();
    193   EXPECT_TRUE(task_runner_->GetPendingTasks().empty());
    194 }
    195 
    196 TEST_F(CloudPolicyRefreshSchedulerTest, RefreshSoonRateLimit) {
    197   scoped_ptr<CloudPolicyRefreshScheduler> scheduler(CreateRefreshScheduler());
    198   // Max out the request rate.
    199   for (int i = 0; i < 5; ++i) {
    200     EXPECT_CALL(client_, FetchPolicy()).Times(1);
    201     scheduler->RefreshSoon();
    202     task_runner_->RunUntilIdle();
    203     Mock::VerifyAndClearExpectations(&client_);
    204   }
    205   // The next refresh is throttled.
    206   EXPECT_CALL(client_, FetchPolicy()).Times(0);
    207   scheduler->RefreshSoon();
    208   task_runner_->RunPendingTasks();
    209   Mock::VerifyAndClearExpectations(&client_);
    210 }
    211 
    212 TEST_F(CloudPolicyRefreshSchedulerTest, InvalidationsAvailable) {
    213   scoped_ptr<CloudPolicyRefreshScheduler> scheduler(
    214       new CloudPolicyRefreshScheduler(&client_, &store_, task_runner_));
    215   scheduler->SetRefreshDelay(kPolicyRefreshRate);
    216 
    217   // The scheduler has scheduled refreshes at the initial refresh rate.
    218   EXPECT_EQ(2u, task_runner_->GetPendingTasks().size());
    219 
    220   // Signal that invalidations are available.
    221   scheduler->SetInvalidationServiceAvailability(true);
    222   EXPECT_EQ(3u, task_runner_->GetPendingTasks().size());
    223 
    224   CheckInitialRefresh(true);
    225 
    226   EXPECT_CALL(client_, FetchPolicy()).Times(1);
    227   task_runner_->RunPendingTasks();
    228   Mock::VerifyAndClearExpectations(&client_);
    229 
    230   // Complete that fetch.
    231   last_update_ = base::Time::NowFromSystemTime();
    232   client_.NotifyPolicyFetched();
    233 
    234   // The next refresh has been scheduled using a lower refresh rate.
    235   EXPECT_EQ(1u, task_runner_->GetPendingTasks().size());
    236   CheckTiming(CloudPolicyRefreshScheduler::kWithInvalidationsRefreshDelayMs);
    237 }
    238 
    239 TEST_F(CloudPolicyRefreshSchedulerTest, InvalidationsNotAvailable) {
    240   scoped_ptr<CloudPolicyRefreshScheduler> scheduler(
    241       new CloudPolicyRefreshScheduler(&client_, &store_, task_runner_));
    242   scheduler->SetRefreshDelay(kPolicyRefreshRate);
    243 
    244   // Signal that invalidations are not available. The scheduler will not
    245   // schedule refreshes since the available state is not changed.
    246   for (int i = 0; i < 10; ++i) {
    247     scheduler->SetInvalidationServiceAvailability(false);
    248     EXPECT_EQ(2u, task_runner_->GetPendingTasks().size());
    249   }
    250 
    251   // This scheduled the initial refresh.
    252   CheckInitialRefresh(false);
    253 
    254   // Perform that fetch now.
    255   EXPECT_CALL(client_, FetchPolicy()).Times(1);
    256   task_runner_->RunPendingTasks();
    257   Mock::VerifyAndClearExpectations(&client_);
    258 
    259   // Complete that fetch.
    260   last_update_ = base::Time::NowFromSystemTime();
    261   client_.NotifyPolicyFetched();
    262 
    263   // The next refresh has been scheduled at the normal rate.
    264   EXPECT_EQ(1u, task_runner_->GetPendingTasks().size());
    265   CheckTiming(kPolicyRefreshRate);
    266 }
    267 
    268 TEST_F(CloudPolicyRefreshSchedulerTest, InvalidationsOffAndOn) {
    269   scoped_ptr<CloudPolicyRefreshScheduler> scheduler(
    270       new CloudPolicyRefreshScheduler(&client_, &store_, task_runner_));
    271   scheduler->SetRefreshDelay(kPolicyRefreshRate);
    272   scheduler->SetInvalidationServiceAvailability(true);
    273   // Initial fetch.
    274   EXPECT_CALL(client_, FetchPolicy()).Times(1);
    275   task_runner_->RunUntilIdle();
    276   Mock::VerifyAndClearExpectations(&client_);
    277   last_update_ = base::Time::NowFromSystemTime();
    278   client_.NotifyPolicyFetched();
    279 
    280   // The next refresh has been scheduled using a lower refresh rate.
    281   CheckTiming(CloudPolicyRefreshScheduler::kWithInvalidationsRefreshDelayMs);
    282 
    283   // If the service goes down and comes back up before the timeout then a
    284   // refresh is rescheduled at the lower rate again; after executing all
    285   // pending tasks only 1 fetch is performed.
    286   scheduler->SetInvalidationServiceAvailability(false);
    287   scheduler->SetInvalidationServiceAvailability(true);
    288   // The next refresh has been scheduled using a lower refresh rate.
    289   EXPECT_CALL(client_, FetchPolicy()).Times(1);
    290   CheckTiming(CloudPolicyRefreshScheduler::kWithInvalidationsRefreshDelayMs);
    291   task_runner_->RunPendingTasks();
    292   Mock::VerifyAndClearExpectations(&client_);
    293 }
    294 
    295 TEST_F(CloudPolicyRefreshSchedulerTest, InvalidationsDisconnected) {
    296   scoped_ptr<CloudPolicyRefreshScheduler> scheduler(
    297       new CloudPolicyRefreshScheduler(&client_, &store_, task_runner_));
    298   scheduler->SetRefreshDelay(kPolicyRefreshRate);
    299   scheduler->SetInvalidationServiceAvailability(true);
    300   // Initial fetch.
    301   EXPECT_CALL(client_, FetchPolicy()).Times(1);
    302   task_runner_->RunUntilIdle();
    303   Mock::VerifyAndClearExpectations(&client_);
    304   last_update_ = base::Time::NowFromSystemTime();
    305   client_.NotifyPolicyFetched();
    306 
    307   // The next refresh has been scheduled using a lower refresh rate.
    308   // Flush that task.
    309   CheckTiming(CloudPolicyRefreshScheduler::kWithInvalidationsRefreshDelayMs);
    310   EXPECT_CALL(client_, FetchPolicy()).Times(1);
    311   task_runner_->RunPendingTasks();
    312   Mock::VerifyAndClearExpectations(&client_);
    313 
    314   // If the service goes down then the refresh scheduler falls back on the
    315   // default polling rate.
    316   scheduler->SetInvalidationServiceAvailability(false);
    317   CheckTiming(kPolicyRefreshRate);
    318 }
    319 
    320 class CloudPolicyRefreshSchedulerSteadyStateTest
    321     : public CloudPolicyRefreshSchedulerTest {
    322  protected:
    323   CloudPolicyRefreshSchedulerSteadyStateTest() {}
    324 
    325   virtual void SetUp() OVERRIDE {
    326     refresh_scheduler_.reset(CreateRefreshScheduler());
    327     refresh_scheduler_->SetRefreshDelay(kPolicyRefreshRate);
    328     CloudPolicyRefreshSchedulerTest::SetUp();
    329     last_update_ = base::Time::NowFromSystemTime();
    330     client_.NotifyPolicyFetched();
    331     CheckTiming(kPolicyRefreshRate);
    332   }
    333 
    334   scoped_ptr<CloudPolicyRefreshScheduler> refresh_scheduler_;
    335 };
    336 
    337 TEST_F(CloudPolicyRefreshSchedulerSteadyStateTest, OnPolicyFetched) {
    338   client_.NotifyPolicyFetched();
    339   CheckTiming(kPolicyRefreshRate);
    340 }
    341 
    342 TEST_F(CloudPolicyRefreshSchedulerSteadyStateTest, OnRegistrationStateChanged) {
    343   client_.SetDMToken("new_token");
    344   client_.NotifyRegistrationStateChanged();
    345   EXPECT_EQ(GetLastDelay(), base::TimeDelta());
    346 
    347   task_runner_->ClearPendingTasks();
    348   client_.SetDMToken(std::string());
    349   client_.NotifyRegistrationStateChanged();
    350   EXPECT_TRUE(task_runner_->GetPendingTasks().empty());
    351 }
    352 
    353 TEST_F(CloudPolicyRefreshSchedulerSteadyStateTest, OnStoreLoaded) {
    354   store_.NotifyStoreLoaded();
    355   CheckTiming(kPolicyRefreshRate);
    356 }
    357 
    358 TEST_F(CloudPolicyRefreshSchedulerSteadyStateTest, OnStoreError) {
    359   task_runner_->ClearPendingTasks();
    360   store_.NotifyStoreError();
    361   EXPECT_TRUE(task_runner_->GetPendingTasks().empty());
    362 }
    363 
    364 TEST_F(CloudPolicyRefreshSchedulerSteadyStateTest, RefreshDelayChange) {
    365   const int delay_short_ms = 5 * 60 * 1000;
    366   refresh_scheduler_->SetRefreshDelay(delay_short_ms);
    367   CheckTiming(CloudPolicyRefreshScheduler::kRefreshDelayMinMs);
    368 
    369   const int delay_ms = 12 * 60 * 60 * 1000;
    370   refresh_scheduler_->SetRefreshDelay(delay_ms);
    371   CheckTiming(delay_ms);
    372 
    373   const int delay_long_ms = 20 * 24 * 60 * 60 * 1000;
    374   refresh_scheduler_->SetRefreshDelay(delay_long_ms);
    375   CheckTiming(CloudPolicyRefreshScheduler::kRefreshDelayMaxMs);
    376 }
    377 
    378 TEST_F(CloudPolicyRefreshSchedulerSteadyStateTest, OnIPAddressChanged) {
    379   NotifyIPAddressChanged();
    380   CheckTiming(kPolicyRefreshRate);
    381 
    382   client_.SetStatus(DM_STATUS_REQUEST_FAILED);
    383   NotifyIPAddressChanged();
    384   EXPECT_EQ(GetLastDelay(), base::TimeDelta());
    385 }
    386 
    387 struct ClientErrorTestParam {
    388   DeviceManagementStatus client_error;
    389   int64 expected_delay_ms;
    390   int backoff_factor;
    391 };
    392 
    393 static const ClientErrorTestParam kClientErrorTestCases[] = {
    394   { DM_STATUS_REQUEST_INVALID,
    395     CloudPolicyRefreshScheduler::kUnmanagedRefreshDelayMs, 1 },
    396   { DM_STATUS_REQUEST_FAILED,
    397     CloudPolicyRefreshScheduler::kInitialErrorRetryDelayMs, 2 },
    398   { DM_STATUS_TEMPORARY_UNAVAILABLE,
    399     CloudPolicyRefreshScheduler::kInitialErrorRetryDelayMs, 2 },
    400   { DM_STATUS_HTTP_STATUS_ERROR,
    401     CloudPolicyRefreshScheduler::kUnmanagedRefreshDelayMs, 1 },
    402   { DM_STATUS_RESPONSE_DECODING_ERROR,
    403     CloudPolicyRefreshScheduler::kUnmanagedRefreshDelayMs, 1 },
    404   { DM_STATUS_SERVICE_MANAGEMENT_NOT_SUPPORTED,
    405     CloudPolicyRefreshScheduler::kUnmanagedRefreshDelayMs, 1 },
    406   { DM_STATUS_SERVICE_DEVICE_NOT_FOUND,
    407     -1, 1 },
    408   { DM_STATUS_SERVICE_MANAGEMENT_TOKEN_INVALID,
    409     -1, 1 },
    410   { DM_STATUS_SERVICE_ACTIVATION_PENDING,
    411     kPolicyRefreshRate, 1 },
    412   { DM_STATUS_SERVICE_INVALID_SERIAL_NUMBER,
    413     -1, 1 },
    414   { DM_STATUS_SERVICE_MISSING_LICENSES,
    415     -1, 1 },
    416   { DM_STATUS_SERVICE_DEVICE_ID_CONFLICT,
    417     -1, 1 },
    418   { DM_STATUS_SERVICE_POLICY_NOT_FOUND,
    419     kPolicyRefreshRate, 1 },
    420 };
    421 
    422 class CloudPolicyRefreshSchedulerClientErrorTest
    423     : public CloudPolicyRefreshSchedulerSteadyStateTest,
    424       public testing::WithParamInterface<ClientErrorTestParam> {
    425 };
    426 
    427 TEST_P(CloudPolicyRefreshSchedulerClientErrorTest, OnClientError) {
    428   client_.SetStatus(GetParam().client_error);
    429   task_runner_->ClearPendingTasks();
    430 
    431   // See whether the error triggers the right refresh delay.
    432   int64 expected_delay_ms = GetParam().expected_delay_ms;
    433   client_.NotifyClientError();
    434   if (expected_delay_ms >= 0) {
    435     CheckTiming(expected_delay_ms);
    436 
    437     // Check whether exponential backoff is working as expected and capped at
    438     // the regular refresh rate (if applicable).
    439     do {
    440       expected_delay_ms *= GetParam().backoff_factor;
    441       last_update_ = base::Time::NowFromSystemTime();
    442       client_.NotifyClientError();
    443       CheckTiming(std::max(std::min(expected_delay_ms, kPolicyRefreshRate),
    444                            GetParam().expected_delay_ms));
    445     } while (GetParam().backoff_factor > 1 &&
    446              expected_delay_ms <= kPolicyRefreshRate);
    447   } else {
    448     EXPECT_EQ(base::TimeDelta(), GetLastDelay());
    449     EXPECT_TRUE(task_runner_->GetPendingTasks().empty());
    450   }
    451 }
    452 
    453 INSTANTIATE_TEST_CASE_P(CloudPolicyRefreshSchedulerClientErrorTest,
    454                         CloudPolicyRefreshSchedulerClientErrorTest,
    455                         testing::ValuesIn(kClientErrorTestCases));
    456 
    457 }  // namespace policy
    458