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 |