| OLD | NEW |
| (Empty) |
| 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 <vector> | |
| 6 | |
| 7 #include "base/files/scoped_temp_dir.h" | |
| 8 #include "base/logging.h" | |
| 9 #include "base/memory/scoped_ptr.h" | |
| 10 #include "base/message_loop.h" | |
| 11 #include "base/values.h" | |
| 12 #include "chrome/browser/browser_process.h" | |
| 13 #include "chrome/browser/policy/cloud_policy_data_store.h" | |
| 14 #include "chrome/browser/policy/logging_work_scheduler.h" | |
| 15 #include "chrome/browser/policy/proto/cloud_policy.pb.h" | |
| 16 #include "chrome/browser/policy/proto/device_management_backend.pb.h" | |
| 17 #include "chrome/browser/policy/testing_cloud_policy_subsystem.h" | |
| 18 #include "chrome/browser/policy/testing_policy_url_fetcher_factory.h" | |
| 19 #include "chrome/browser/policy/user_policy_cache.h" | |
| 20 #include "chrome/common/pref_names.h" | |
| 21 #include "chrome/test/base/testing_browser_process.h" | |
| 22 #include "chrome/test/base/testing_pref_service.h" | |
| 23 #include "content/public/test/test_browser_thread.h" | |
| 24 #include "policy/policy_constants.h" | |
| 25 #include "testing/gtest/include/gtest/gtest.h" | |
| 26 | |
| 27 namespace policy { | |
| 28 | |
| 29 using ::testing::AtMost; | |
| 30 using ::testing::InSequence; | |
| 31 using ::testing::_; | |
| 32 using content::BrowserThread; | |
| 33 | |
| 34 namespace em = enterprise_management; | |
| 35 | |
| 36 namespace { | |
| 37 | |
| 38 const char kGaiaAuthHeader[] = "GoogleLogin auth=secret123"; | |
| 39 const char kDMAuthHeader[] = "GoogleDMToken token=token123456"; | |
| 40 const char kDMToken[] = "token123456"; | |
| 41 | |
| 42 const char kDeviceManagementUrl[] = | |
| 43 "http://localhost:12345/device_management_test"; | |
| 44 | |
| 45 // Fake data to be included in requests. | |
| 46 const char kUsername[] = "john@smith.com"; | |
| 47 const char kAuthToken[] = "secret123"; | |
| 48 const char kPolicyType[] = "google/chrome/test"; | |
| 49 const char kMachineId[] = "test-machine-id"; | |
| 50 | |
| 51 } // namespace | |
| 52 | |
| 53 // An action that returns an URLRequestJob with an HTTP error code. | |
| 54 ACTION_P(CreateFailedResponse, http_error_code) { | |
| 55 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 56 em::DeviceManagementResponse response_data; | |
| 57 | |
| 58 arg3->response_data = response_data.SerializeAsString(); | |
| 59 arg3->response_code = http_error_code; | |
| 60 } | |
| 61 | |
| 62 // An action that returns an URLRequestJob with a successful device | |
| 63 // registration response. | |
| 64 ACTION_P(CreateSuccessfulRegisterResponse, token) { | |
| 65 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 66 em::DeviceManagementResponse response_data; | |
| 67 response_data.mutable_register_response()->set_device_management_token(token); | |
| 68 response_data.mutable_register_response()->set_enrollment_type( | |
| 69 em::DeviceRegisterResponse::ENTERPRISE); | |
| 70 | |
| 71 arg3->response_data = response_data.SerializeAsString(); | |
| 72 arg3->response_code = 200; | |
| 73 } | |
| 74 | |
| 75 // An action that returns an URLRequestJob with a successful policy response. | |
| 76 ACTION_P3(CreateSuccessfulPolicyResponse, | |
| 77 homepage_location, | |
| 78 set_serial_valid, | |
| 79 serial_valid) { | |
| 80 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 81 em::CloudPolicySettings settings; | |
| 82 settings.mutable_homepagelocation()->set_value(homepage_location); | |
| 83 em::PolicyData policy_data; | |
| 84 policy_data.set_policy_type(kPolicyType); | |
| 85 policy_data.set_policy_value(settings.SerializeAsString()); | |
| 86 if (set_serial_valid) | |
| 87 policy_data.set_valid_serial_number_missing(serial_valid); | |
| 88 | |
| 89 em::DeviceManagementResponse response_data; | |
| 90 em::DevicePolicyResponse* policy_response = | |
| 91 response_data.mutable_policy_response(); | |
| 92 em::PolicyFetchResponse* fetch_response = policy_response->add_response(); | |
| 93 fetch_response->set_error_code(200); | |
| 94 fetch_response->set_policy_data(policy_data.SerializeAsString()); | |
| 95 | |
| 96 arg3->response_data = response_data.SerializeAsString(); | |
| 97 arg3->response_code = 200; | |
| 98 } | |
| 99 | |
| 100 // Tests CloudPolicySubsystem by intercepting its network requests. | |
| 101 // The requests are intercepted by PolicyRequestInterceptor and they are | |
| 102 // logged by LoggingWorkScheduler for further examination. | |
| 103 class CloudPolicySubsystemTestBase : public testing::Test { | |
| 104 public: | |
| 105 CloudPolicySubsystemTestBase() | |
| 106 : ui_thread_(BrowserThread::UI, &loop_), | |
| 107 file_thread_(BrowserThread::FILE, &loop_), | |
| 108 io_thread_(BrowserThread::IO, &loop_) {} | |
| 109 | |
| 110 virtual ~CloudPolicySubsystemTestBase() {} | |
| 111 | |
| 112 protected: | |
| 113 void StopMessageLoop() { | |
| 114 loop_.QuitNow(); | |
| 115 } | |
| 116 | |
| 117 virtual void SetUp() { | |
| 118 prefs_.reset(new TestingPrefServiceSimple); | |
| 119 CloudPolicySubsystem::RegisterPrefs(prefs_.get()); | |
| 120 ((TestingBrowserProcess*) g_browser_process)->SetLocalState(prefs_.get()); | |
| 121 | |
| 122 logger_.reset(new EventLogger); | |
| 123 factory_.reset(new TestingPolicyURLFetcherFactory(logger_.get())); | |
| 124 ASSERT_TRUE(temp_user_data_dir_.CreateUniqueTempDir()); | |
| 125 data_store_.reset(CloudPolicyDataStore::CreateForUserPolicies()); | |
| 126 cache_ = new UserPolicyCache( | |
| 127 temp_user_data_dir_.path().AppendASCII("CloudPolicyControllerTest"), | |
| 128 false /* wait_for_policy_fetch */); | |
| 129 cloud_policy_subsystem_.reset(new TestingCloudPolicySubsystem( | |
| 130 data_store_.get(), cache_, | |
| 131 kDeviceManagementUrl, logger_.get())); | |
| 132 cloud_policy_subsystem_->CompleteInitialization( | |
| 133 prefs::kDevicePolicyRefreshRate, 0); | |
| 134 | |
| 135 // Abort the test on unexpected requests. | |
| 136 ON_CALL(factory(), Intercept(_, _, _, _)) | |
| 137 .WillByDefault(InvokeWithoutArgs( | |
| 138 this, | |
| 139 &CloudPolicySubsystemTestBase::StopMessageLoop)); | |
| 140 } | |
| 141 | |
| 142 virtual void TearDown() { | |
| 143 TestingBrowserProcess::GetGlobal()->SetLocalState(NULL); | |
| 144 cloud_policy_subsystem_->Shutdown(); | |
| 145 cloud_policy_subsystem_.reset(); | |
| 146 data_store_.reset(); | |
| 147 factory_.reset(); | |
| 148 logger_.reset(); | |
| 149 prefs_.reset(); | |
| 150 } | |
| 151 | |
| 152 void ExecuteTest() { | |
| 153 // Stop the test once all the expectations are met. This relies on a | |
| 154 // sequence being active (see tests below). | |
| 155 EXPECT_CALL(factory(), Intercept(_, _, _, _)) | |
| 156 .Times(AtMost(1)) | |
| 157 .WillRepeatedly( | |
| 158 InvokeWithoutArgs(this, | |
| 159 &CloudPolicySubsystemTestBase::StopMessageLoop)); | |
| 160 | |
| 161 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 162 data_store_->set_user_name(kUsername); | |
| 163 data_store_->SetGaiaToken(kAuthToken); | |
| 164 data_store_->SetDeviceToken("", true); | |
| 165 loop_.RunUntilIdle(); | |
| 166 } | |
| 167 | |
| 168 void VerifyTest(const std::string& homepage_location) { | |
| 169 // Test conditions. | |
| 170 EXPECT_EQ(CloudPolicySubsystem::SUCCESS, cloud_policy_subsystem_->state()); | |
| 171 StringValue homepage_value(homepage_location); | |
| 172 VerifyPolicy(key::kHomepageLocation, &homepage_value); | |
| 173 VerifyServerLoad(); | |
| 174 } | |
| 175 | |
| 176 void VerifyState(CloudPolicySubsystem::PolicySubsystemState state) { | |
| 177 EXPECT_EQ(state, cloud_policy_subsystem_->state()); | |
| 178 } | |
| 179 | |
| 180 void ExpectSuccessfulRegistration() { | |
| 181 EXPECT_CALL(factory(), Intercept(kGaiaAuthHeader, "register", _, _)) | |
| 182 .WillOnce(CreateSuccessfulRegisterResponse(kDMToken)); | |
| 183 } | |
| 184 | |
| 185 void ExpectFailedRegistration(int n, int code) { | |
| 186 EXPECT_CALL(factory(), Intercept(kGaiaAuthHeader, "register", _, _)) | |
| 187 .Times(n) | |
| 188 .WillRepeatedly(CreateFailedResponse(code)); | |
| 189 } | |
| 190 | |
| 191 void ExpectFailedPolicy(int n, int code) { | |
| 192 EXPECT_CALL(factory(), Intercept(kDMAuthHeader, "policy", _, _)) | |
| 193 .Times(n) | |
| 194 .WillRepeatedly(CreateFailedResponse(code)); | |
| 195 } | |
| 196 | |
| 197 void ExpectSuccessfulPolicy(int n, | |
| 198 const std::string& homepage) { | |
| 199 EXPECT_CALL(factory(), Intercept(kDMAuthHeader, "policy", _, _)) | |
| 200 .Times(n) | |
| 201 .WillRepeatedly(CreateSuccessfulPolicyResponse(homepage, false, false)); | |
| 202 } | |
| 203 | |
| 204 TestingPolicyURLFetcherFactory& factory() { return *factory_; } | |
| 205 CloudPolicyDataStore* data_store() { return data_store_.get(); } | |
| 206 | |
| 207 private: | |
| 208 // Verifies for a given policy that it is provided by the subsystem. | |
| 209 void VerifyPolicy(const char* policy_name, Value* expected) { | |
| 210 const PolicyMap* policy_map = cache_->policy(); | |
| 211 ASSERT_TRUE(Value::Equals(expected, policy_map->GetValue(policy_name))); | |
| 212 } | |
| 213 | |
| 214 // Verifies that the last recorded run of the subsystem did not issue | |
| 215 // too frequent requests: | |
| 216 // - no more than 10 requests in the first 10 minutes | |
| 217 // - no more then 12 requests per hour in the next 10 hours | |
| 218 // TODO(gfeher): Thighten these conditions further. This will require | |
| 219 // fine-tuning of the subsystem. See: http://crosbug.com/16637 | |
| 220 void VerifyServerLoad() { | |
| 221 std::vector<int64> events; | |
| 222 logger_->Swap(&events); | |
| 223 | |
| 224 ASSERT_FALSE(events.empty()); | |
| 225 | |
| 226 int64 cur = 0; | |
| 227 int count = 0; | |
| 228 | |
| 229 // Length and max number of requests for the first interval. | |
| 230 int64 length = 10 * 60 * 1000; // 10 minutes | |
| 231 int64 limit = 10; // maximum nr of requests in the first 10 minutes | |
| 232 | |
| 233 while (cur <= events.back()) { | |
| 234 EXPECT_LE(EventLogger::CountEvents(events, cur, length), limit); | |
| 235 count++; | |
| 236 | |
| 237 cur += length; | |
| 238 | |
| 239 // Length and max number of requests for the subsequent intervals. | |
| 240 length = 60 * 60 * 1000; // 60 minutes | |
| 241 limit = 12; // maxminum nr of requests in the next 60 minutes | |
| 242 } | |
| 243 | |
| 244 EXPECT_GE(count, 11) | |
| 245 << "No enough requests were fired during the test run."; | |
| 246 } | |
| 247 | |
| 248 base::ScopedTempDir temp_user_data_dir_; | |
| 249 | |
| 250 MessageLoop loop_; | |
| 251 content::TestBrowserThread ui_thread_; | |
| 252 content::TestBrowserThread file_thread_; | |
| 253 content::TestBrowserThread io_thread_; | |
| 254 | |
| 255 scoped_ptr<EventLogger> logger_; | |
| 256 scoped_ptr<CloudPolicyDataStore> data_store_; | |
| 257 scoped_ptr<CloudPolicySubsystem> cloud_policy_subsystem_; | |
| 258 scoped_ptr<PrefServiceSimple> prefs_; | |
| 259 CloudPolicyCacheBase* cache_; | |
| 260 | |
| 261 scoped_ptr<TestingPolicyURLFetcherFactory> factory_; | |
| 262 | |
| 263 DISALLOW_COPY_AND_ASSIGN(CloudPolicySubsystemTestBase); | |
| 264 }; | |
| 265 | |
| 266 // A parameterized test case that simulates 100 failed registration attempts, | |
| 267 // then a successful one, then 100 failed policy fetch attempts and then 100 | |
| 268 // successful policy fetches. The two parameters are the error codes for the | |
| 269 // failed registration and policy responses. | |
| 270 | |
| 271 class CombinedTestDesc { | |
| 272 public: | |
| 273 CombinedTestDesc(int registration_error_code, int policy_error_code) | |
| 274 : registration_error_code_(registration_error_code), | |
| 275 policy_error_code_(policy_error_code) { | |
| 276 } | |
| 277 | |
| 278 ~CombinedTestDesc() {} | |
| 279 | |
| 280 int registration_error_code() const { return registration_error_code_; } | |
| 281 int policy_error_code() const { return policy_error_code_; } | |
| 282 | |
| 283 private: | |
| 284 int registration_error_code_; | |
| 285 int policy_error_code_; | |
| 286 }; | |
| 287 | |
| 288 class CloudPolicySubsystemCombinedTest | |
| 289 : public CloudPolicySubsystemTestBase, | |
| 290 public testing::WithParamInterface<CombinedTestDesc> { | |
| 291 }; | |
| 292 | |
| 293 TEST_P(CloudPolicySubsystemCombinedTest, Combined) { | |
| 294 InSequence s; | |
| 295 ExpectFailedRegistration(100, GetParam().registration_error_code()); | |
| 296 ExpectSuccessfulRegistration(); | |
| 297 ExpectFailedPolicy(100, GetParam().policy_error_code()); | |
| 298 ExpectSuccessfulPolicy(100, "http://www.google.com"); | |
| 299 ExpectSuccessfulPolicy(1, "http://www.chromium.org"); | |
| 300 ExecuteTest(); | |
| 301 VerifyTest("http://www.chromium.org"); | |
| 302 } | |
| 303 | |
| 304 // A random sample of error code pairs. Note that the following policy error | |
| 305 // codes (401, 403, 410) make the policy subsystem to try and reregister, and | |
| 306 // that is not expected in these tests. | |
| 307 INSTANTIATE_TEST_CASE_P( | |
| 308 CloudPolicySubsystemCombinedTestInstance, | |
| 309 CloudPolicySubsystemCombinedTest, | |
| 310 testing::Values( | |
| 311 CombinedTestDesc(403, 400), | |
| 312 CombinedTestDesc(403, 404), | |
| 313 CombinedTestDesc(403, 412), | |
| 314 CombinedTestDesc(403, 500), | |
| 315 CombinedTestDesc(403, 503), | |
| 316 CombinedTestDesc(403, 902), | |
| 317 CombinedTestDesc(902, 400), | |
| 318 CombinedTestDesc(503, 404), | |
| 319 CombinedTestDesc(500, 412), | |
| 320 CombinedTestDesc(412, 500), | |
| 321 CombinedTestDesc(404, 503), | |
| 322 CombinedTestDesc(400, 902))); | |
| 323 | |
| 324 // A parameterized test case that simulates 100 failed registration attempts, | |
| 325 // then a successful one, and then a succesful policy fetch. The parameter is | |
| 326 // the error code returned for registration attempts. | |
| 327 | |
| 328 class CloudPolicySubsystemRegistrationTest | |
| 329 : public CloudPolicySubsystemTestBase, | |
| 330 public testing::WithParamInterface<int> { | |
| 331 }; | |
| 332 | |
| 333 TEST_P(CloudPolicySubsystemRegistrationTest, Registration) { | |
| 334 InSequence s; | |
| 335 ExpectFailedRegistration(100, GetParam()); | |
| 336 ExpectSuccessfulRegistration(); | |
| 337 ExpectSuccessfulPolicy(1, "http://www.youtube.com"); | |
| 338 ExecuteTest(); | |
| 339 VerifyTest("http://www.youtube.com"); | |
| 340 } | |
| 341 | |
| 342 INSTANTIATE_TEST_CASE_P( | |
| 343 CloudPolicySubsystemRegistrationTestInstance, | |
| 344 CloudPolicySubsystemRegistrationTest, | |
| 345 // For the case of 401 see CloudPolicySubsystemRegistrationFailureTest | |
| 346 testing::Values(400, 403, 404, 410, 412, 500, 503, 902)); | |
| 347 | |
| 348 // A test case that verifies that the subsystem understands the "not managed" | |
| 349 // response from the server. | |
| 350 | |
| 351 class CloudPolicySubsystemRegistrationFailureTest | |
| 352 : public CloudPolicySubsystemTestBase { | |
| 353 }; | |
| 354 | |
| 355 TEST_F(CloudPolicySubsystemRegistrationFailureTest, RegistrationFailure) { | |
| 356 InSequence s; | |
| 357 ExpectFailedRegistration(1, 401); | |
| 358 ExecuteTest(); | |
| 359 VerifyState(CloudPolicySubsystem::BAD_GAIA_TOKEN); | |
| 360 } | |
| 361 | |
| 362 // A parameterized test case that simulates a successful registration, then 100 | |
| 363 // failed policy fetch attempts and then a successful one. The parameter is | |
| 364 // the error code returned for failed policy attempts. | |
| 365 | |
| 366 class CloudPolicySubsystemPolicyTest | |
| 367 : public CloudPolicySubsystemTestBase, | |
| 368 public testing::WithParamInterface<int> { | |
| 369 }; | |
| 370 | |
| 371 TEST_P(CloudPolicySubsystemPolicyTest, Policy) { | |
| 372 InSequence s; | |
| 373 ExpectSuccessfulRegistration(); | |
| 374 ExpectFailedPolicy(100, GetParam()); | |
| 375 ExpectSuccessfulPolicy(1, "http://www.youtube.com"); | |
| 376 ExecuteTest(); | |
| 377 VerifyTest("http://www.youtube.com"); | |
| 378 } | |
| 379 | |
| 380 INSTANTIATE_TEST_CASE_P( | |
| 381 CloudPolicySubsystemPolicyTestInstance, | |
| 382 CloudPolicySubsystemPolicyTest, | |
| 383 testing::Values(400, 404, 412, 500, 503, 902)); | |
| 384 | |
| 385 // A parameterized test case that simulates a successful registration, then 40 | |
| 386 // failed policy fetch attempts and a successful registration after each of | |
| 387 // them. The parameter is the error code returned for registration attempts. | |
| 388 | |
| 389 class CloudPolicySubsystemPolicyReregisterTest | |
| 390 : public CloudPolicySubsystemTestBase, | |
| 391 public testing::WithParamInterface<int> { | |
| 392 }; | |
| 393 | |
| 394 TEST_P(CloudPolicySubsystemPolicyReregisterTest, Policy) { | |
| 395 // This logs a lot of WARNINGs. Temporarily increase the logging threshold. | |
| 396 int prev_level = logging::GetMinLogLevel(); | |
| 397 logging::SetMinLogLevel(logging::LOG_ERROR); | |
| 398 | |
| 399 InSequence s; | |
| 400 for (int i = 0; i < 40; i++) { | |
| 401 ExpectSuccessfulRegistration(); | |
| 402 ExpectFailedPolicy(1, GetParam()); | |
| 403 } | |
| 404 ExpectSuccessfulRegistration(); | |
| 405 ExpectSuccessfulPolicy(1, "http://www.youtube.com"); | |
| 406 ExecuteTest(); | |
| 407 VerifyTest("http://www.youtube.com"); | |
| 408 | |
| 409 logging::SetMinLogLevel(prev_level); | |
| 410 } | |
| 411 | |
| 412 INSTANTIATE_TEST_CASE_P( | |
| 413 CloudPolicySubsystemPolicyReregisterTestInstance, | |
| 414 CloudPolicySubsystemPolicyReregisterTest, | |
| 415 testing::Values(401, 403, 410)); | |
| 416 | |
| 417 MATCHER_P(PolicyWithSerial, expected_serial, "") { | |
| 418 return arg.policy_request().request(0).machine_id() == expected_serial; | |
| 419 } | |
| 420 | |
| 421 class CloudPolicySubsystemSerialNumberRecoveryTest | |
| 422 : public CloudPolicySubsystemTestBase { | |
| 423 protected: | |
| 424 virtual ~CloudPolicySubsystemSerialNumberRecoveryTest() {} | |
| 425 | |
| 426 virtual void SetUp() { | |
| 427 CloudPolicySubsystemTestBase::SetUp(); | |
| 428 data_store()->set_machine_id(kMachineId); | |
| 429 } | |
| 430 | |
| 431 void ExpectPolicyRequest(const std::string& serial, | |
| 432 bool set_serial_valid, | |
| 433 bool serial_valid) { | |
| 434 EXPECT_CALL(factory(), Intercept(kDMAuthHeader, "policy", | |
| 435 PolicyWithSerial(serial), _)) | |
| 436 .WillOnce(CreateSuccessfulPolicyResponse("", set_serial_valid, | |
| 437 serial_valid)); | |
| 438 } | |
| 439 }; | |
| 440 | |
| 441 // Tests that no serial is sent if the flag is not set. | |
| 442 TEST_F(CloudPolicySubsystemSerialNumberRecoveryTest, FlagNotSet) { | |
| 443 InSequence s; | |
| 444 ExpectSuccessfulRegistration(); | |
| 445 ExpectPolicyRequest("", false, false); | |
| 446 ExpectPolicyRequest("", false, false); | |
| 447 ExecuteTest(); | |
| 448 } | |
| 449 | |
| 450 // Tests that no serial is sent if the flag is set to false. | |
| 451 TEST_F(CloudPolicySubsystemSerialNumberRecoveryTest, FlagFalse) { | |
| 452 InSequence s; | |
| 453 ExpectSuccessfulRegistration(); | |
| 454 ExpectPolicyRequest("", true, false); | |
| 455 ExpectPolicyRequest("", false, false); | |
| 456 ExecuteTest(); | |
| 457 } | |
| 458 | |
| 459 // Tests that the serial is sent once if the server requests it. | |
| 460 TEST_F(CloudPolicySubsystemSerialNumberRecoveryTest, SerialRequested) { | |
| 461 InSequence s; | |
| 462 ExpectSuccessfulRegistration(); | |
| 463 ExpectPolicyRequest("", true, true); | |
| 464 ExpectPolicyRequest(kMachineId, false, false); | |
| 465 ExpectPolicyRequest("", false, false); | |
| 466 ExecuteTest(); | |
| 467 } | |
| 468 | |
| 469 } // policy | |
| OLD | NEW |