• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
CloudPolicyRefreshSchedulerTest()34   CloudPolicyRefreshSchedulerTest()
35       : task_runner_(new base::TestSimpleTaskRunner()),
36         network_change_notifier_(net::NetworkChangeNotifier::CreateMock()) {}
37 
SetUp()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 
CreateRefreshScheduler()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 
NotifyIPAddressChanged()63   void NotifyIPAddressChanged() {
64     net::NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
65     loop_.RunUntilIdle();
66   }
67 
GetLastDelay() const68   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 
CheckTiming(int64 expected_delay_ms) const75   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.
CheckTimingWithAge(const base::TimeDelta & offset_from_last_refresh,const base::TimeDelta & cache_age) const83   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 
CheckInitialRefresh(bool with_invalidations) const121   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 
TEST_F(CloudPolicyRefreshSchedulerTest,InitialRefreshNoPolicy)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 
TEST_F(CloudPolicyRefreshSchedulerTest,InitialRefreshUnmanaged)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 
TEST_F(CloudPolicyRefreshSchedulerTest,InitialRefreshManagedNotYetFetched)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 
TEST_F(CloudPolicyRefreshSchedulerTest,InitialRefreshManagedAlreadyFetched)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 
TEST_F(CloudPolicyRefreshSchedulerTest,Unregistered)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 
TEST_F(CloudPolicyRefreshSchedulerTest,RefreshSoonRateLimit)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 
TEST_F(CloudPolicyRefreshSchedulerTest,InvalidationsAvailable)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 
TEST_F(CloudPolicyRefreshSchedulerTest,InvalidationsNotAvailable)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 
TEST_F(CloudPolicyRefreshSchedulerTest,InvalidationsOffAndOn)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 
TEST_F(CloudPolicyRefreshSchedulerTest,InvalidationsDisconnected)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:
CloudPolicyRefreshSchedulerSteadyStateTest()323   CloudPolicyRefreshSchedulerSteadyStateTest() {}
324 
SetUp()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 
TEST_F(CloudPolicyRefreshSchedulerSteadyStateTest,OnPolicyFetched)337 TEST_F(CloudPolicyRefreshSchedulerSteadyStateTest, OnPolicyFetched) {
338   client_.NotifyPolicyFetched();
339   CheckTiming(kPolicyRefreshRate);
340 }
341 
TEST_F(CloudPolicyRefreshSchedulerSteadyStateTest,OnRegistrationStateChanged)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 
TEST_F(CloudPolicyRefreshSchedulerSteadyStateTest,OnStoreLoaded)353 TEST_F(CloudPolicyRefreshSchedulerSteadyStateTest, OnStoreLoaded) {
354   store_.NotifyStoreLoaded();
355   CheckTiming(kPolicyRefreshRate);
356 }
357 
TEST_F(CloudPolicyRefreshSchedulerSteadyStateTest,OnStoreError)358 TEST_F(CloudPolicyRefreshSchedulerSteadyStateTest, OnStoreError) {
359   task_runner_->ClearPendingTasks();
360   store_.NotifyStoreError();
361   EXPECT_TRUE(task_runner_->GetPendingTasks().empty());
362 }
363 
TEST_F(CloudPolicyRefreshSchedulerSteadyStateTest,RefreshDelayChange)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 
TEST_F(CloudPolicyRefreshSchedulerSteadyStateTest,OnIPAddressChanged)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 
TEST_P(CloudPolicyRefreshSchedulerClientErrorTest,OnClientError)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