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