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