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