blob: 18554fac2a763418fc1981a2465d0a213be90635 [file] [log] [blame]
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001// 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 "chrome/browser/chromeos/policy/auto_enrollment_client.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
Ben Murdochbb1529c2013-08-08 10:24:53 +01009#include "base/message_loop/message_loop.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000010#include "base/prefs/pref_service.h"
11#include "base/prefs/testing_pref_service.h"
12#include "base/values.h"
13#include "chrome/browser/browser_process.h"
14#include "chrome/browser/policy/cloud/mock_device_management_service.h"
15#include "chrome/common/pref_names.h"
16#include "chrome/test/base/scoped_testing_local_state.h"
17#include "chrome/test/base/testing_browser_process.h"
Ben Murdochbb1529c2013-08-08 10:24:53 +010018#include "content/public/test/test_browser_thread_bundle.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000019#include "crypto/sha2.h"
20#include "testing/gmock/include/gmock/gmock.h"
21#include "testing/gtest/include/gtest/gtest.h"
22
23namespace em = enterprise_management;
24
25namespace policy {
26
27namespace {
28
29const char* kSerial = "serial";
30const char* kSerialHash =
31 "\x01\x44\xb1\xde\xfc\xf7\x56\x10\x87\x01\x5f\x8d\x83\x0d\x65\xb1"
32 "\x6f\x02\x4a\xd7\xeb\x92\x45\xfc\xd4\xe4\x37\xa1\x55\x2b\x13\x8a";
33
34using ::testing::InSequence;
35using ::testing::SaveArg;
36using ::testing::_;
37
38class AutoEnrollmentClientTest : public testing::Test {
39 protected:
40 AutoEnrollmentClientTest()
41 : scoped_testing_local_state_(
42 TestingBrowserProcess::GetGlobal()),
43 local_state_(scoped_testing_local_state_.Get()),
44 service_(NULL),
45 completion_callback_count_(0) {}
46
47 virtual void SetUp() OVERRIDE {
48 CreateClient(kSerial, 4, 8);
49 ASSERT_FALSE(local_state_->GetUserPref(prefs::kShouldAutoEnroll));
50 ASSERT_FALSE(local_state_->GetUserPref(prefs::kAutoEnrollmentPowerLimit));
51 }
52
53 void CreateClient(const std::string& serial,
54 int power_initial,
55 int power_limit) {
56 service_ = new MockDeviceManagementService();
57 EXPECT_CALL(*service_, StartJob(_, _, _, _, _, _, _))
58 .WillRepeatedly(SaveArg<6>(&last_request_));
59 base::Closure callback =
60 base::Bind(&AutoEnrollmentClientTest::CompletionCallback,
61 base::Unretained(this));
62 client_.reset(new AutoEnrollmentClient(callback,
63 service_,
64 local_state_,
65 serial,
66 power_initial,
67 power_limit));
68 }
69
70 void CompletionCallback() {
71 completion_callback_count_++;
72 }
73
74 void ServerWillFail(DeviceManagementStatus error) {
75 em::DeviceManagementResponse dummy_response;
76 EXPECT_CALL(*service_,
77 CreateJob(DeviceManagementRequestJob::TYPE_AUTO_ENROLLMENT))
78 .WillOnce(service_->FailJob(error));
79 }
80
81 void ServerWillReply(int64 modulus, bool with_hashes, bool with_serial_hash) {
82 em::DeviceManagementResponse response;
83 em::DeviceAutoEnrollmentResponse* enrollment_response =
84 response.mutable_auto_enrollment_response();
85 if (modulus >= 0)
86 enrollment_response->set_expected_modulus(modulus);
87 if (with_hashes) {
88 for (size_t i = 0; i < 10; ++i) {
89 std::string serial = "serial X";
90 serial[7] = '0' + i;
91 std::string hash = crypto::SHA256HashString(serial);
92 enrollment_response->mutable_hash()->Add()->assign(hash);
93 }
94 }
95 if (with_serial_hash) {
96 enrollment_response->mutable_hash()->Add()->assign(kSerialHash,
97 crypto::kSHA256Length);
98 }
99 EXPECT_CALL(*service_,
100 CreateJob(DeviceManagementRequestJob::TYPE_AUTO_ENROLLMENT))
101 .WillOnce(service_->SucceedJob(response));
102 }
103
Ben Murdochbb1529c2013-08-08 10:24:53 +0100104 void ServerWillReplyAsync(MockDeviceManagementJob** job) {
105 EXPECT_CALL(*service_,
106 CreateJob(DeviceManagementRequestJob::TYPE_AUTO_ENROLLMENT))
107 .WillOnce(service_->CreateAsyncJob(job));
108 }
109
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100110 bool HasCachedDecision() {
111 return local_state_->GetUserPref(prefs::kShouldAutoEnroll);
112 }
113
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000114 void VerifyCachedResult(bool should_enroll, int power_limit) {
115 base::FundamentalValue value_should_enroll(should_enroll);
116 base::FundamentalValue value_power_limit(power_limit);
117 EXPECT_TRUE(Value::Equals(
118 &value_should_enroll,
119 local_state_->GetUserPref(prefs::kShouldAutoEnroll)));
120 EXPECT_TRUE(Value::Equals(
121 &value_power_limit,
122 local_state_->GetUserPref(prefs::kAutoEnrollmentPowerLimit)));
123 }
124
125 const em::DeviceAutoEnrollmentRequest& auto_enrollment_request() {
126 return last_request_.auto_enrollment_request();
127 }
128
Ben Murdochbb1529c2013-08-08 10:24:53 +0100129 content::TestBrowserThreadBundle browser_threads_;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000130 ScopedTestingLocalState scoped_testing_local_state_;
131 TestingPrefServiceSimple* local_state_;
132 MockDeviceManagementService* service_;
133 scoped_ptr<AutoEnrollmentClient> client_;
134 em::DeviceManagementRequest last_request_;
135 int completion_callback_count_;
136
137 private:
138 DISALLOW_COPY_AND_ASSIGN(AutoEnrollmentClientTest);
139};
140
141TEST_F(AutoEnrollmentClientTest, NetworkFailure) {
142 ServerWillFail(DM_STATUS_TEMPORARY_UNAVAILABLE);
143 client_->Start();
144 EXPECT_FALSE(client_->should_auto_enroll());
Ben Murdochbb1529c2013-08-08 10:24:53 +0100145 EXPECT_EQ(0, completion_callback_count_);
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100146 EXPECT_FALSE(HasCachedDecision());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000147}
148
149TEST_F(AutoEnrollmentClientTest, EmptyReply) {
150 ServerWillReply(-1, false, false);
151 client_->Start();
152 EXPECT_FALSE(client_->should_auto_enroll());
153 EXPECT_EQ(1, completion_callback_count_);
154 VerifyCachedResult(false, 8);
155}
156
157TEST_F(AutoEnrollmentClientTest, ClientUploadsRightBits) {
158 ServerWillReply(-1, false, false);
159 client_->Start();
160 EXPECT_FALSE(client_->should_auto_enroll());
161 EXPECT_EQ(1, completion_callback_count_);
162
163 EXPECT_TRUE(auto_enrollment_request().has_remainder());
164 EXPECT_TRUE(auto_enrollment_request().has_modulus());
165 EXPECT_EQ(16, auto_enrollment_request().modulus());
166 EXPECT_EQ(kSerialHash[31] & 0xf, auto_enrollment_request().remainder());
167 VerifyCachedResult(false, 8);
168}
169
170TEST_F(AutoEnrollmentClientTest, AskForMoreThenFail) {
171 InSequence sequence;
172 ServerWillReply(32, false, false);
173 ServerWillFail(DM_STATUS_TEMPORARY_UNAVAILABLE);
174 client_->Start();
175 EXPECT_FALSE(client_->should_auto_enroll());
Ben Murdochbb1529c2013-08-08 10:24:53 +0100176 EXPECT_EQ(0, completion_callback_count_);
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100177 EXPECT_FALSE(HasCachedDecision());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000178}
179
180TEST_F(AutoEnrollmentClientTest, AskForMoreThenEvenMore) {
181 InSequence sequence;
182 ServerWillReply(32, false, false);
183 ServerWillReply(64, false, false);
184 client_->Start();
185 EXPECT_FALSE(client_->should_auto_enroll());
186 EXPECT_EQ(1, completion_callback_count_);
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100187 EXPECT_FALSE(HasCachedDecision());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000188}
189
190TEST_F(AutoEnrollmentClientTest, AskForLess) {
191 InSequence sequence;
192 ServerWillReply(8, false, false);
193 ServerWillReply(-1, true, true);
194 client_->Start();
195 EXPECT_TRUE(client_->should_auto_enroll());
196 EXPECT_EQ(1, completion_callback_count_);
197 VerifyCachedResult(true, 8);
198}
199
200TEST_F(AutoEnrollmentClientTest, AskForSame) {
201 InSequence sequence;
202 ServerWillReply(16, false, false);
203 ServerWillReply(-1, true, true);
204 client_->Start();
205 EXPECT_TRUE(client_->should_auto_enroll());
206 EXPECT_EQ(1, completion_callback_count_);
207 VerifyCachedResult(true, 8);
208}
209
210TEST_F(AutoEnrollmentClientTest, AskForSameTwice) {
211 InSequence sequence;
212 ServerWillReply(16, false, false);
213 ServerWillReply(16, false, false);
214 client_->Start();
215 EXPECT_FALSE(client_->should_auto_enroll());
216 EXPECT_EQ(1, completion_callback_count_);
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100217 EXPECT_FALSE(HasCachedDecision());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000218}
219
220TEST_F(AutoEnrollmentClientTest, AskForTooMuch) {
221 ServerWillReply(512, false, false);
222 client_->Start();
223 EXPECT_FALSE(client_->should_auto_enroll());
224 EXPECT_EQ(1, completion_callback_count_);
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100225 EXPECT_FALSE(HasCachedDecision());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000226}
227
228TEST_F(AutoEnrollmentClientTest, AskNonPowerOf2) {
229 InSequence sequence;
230 ServerWillReply(100, false, false);
231 ServerWillReply(-1, false, false);
232 client_->Start();
233 EXPECT_FALSE(client_->should_auto_enroll());
234 EXPECT_EQ(1, completion_callback_count_);
235 EXPECT_TRUE(auto_enrollment_request().has_remainder());
236 EXPECT_TRUE(auto_enrollment_request().has_modulus());
237 EXPECT_EQ(128, auto_enrollment_request().modulus());
238 EXPECT_EQ(kSerialHash[31] & 0x7f, auto_enrollment_request().remainder());
239 VerifyCachedResult(false, 8);
240}
241
242TEST_F(AutoEnrollmentClientTest, ConsumerDevice) {
243 ServerWillReply(-1, true, false);
244 client_->Start();
245 EXPECT_FALSE(client_->should_auto_enroll());
246 EXPECT_EQ(1, completion_callback_count_);
247 VerifyCachedResult(false, 8);
Ben Murdochbb1529c2013-08-08 10:24:53 +0100248
249 // Network changes don't trigger retries after obtaining a response from
250 // the server.
251 client_->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_ETHERNET);
252 EXPECT_EQ(1, completion_callback_count_);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000253}
254
255TEST_F(AutoEnrollmentClientTest, EnterpriseDevice) {
256 ServerWillReply(-1, true, true);
257 client_->Start();
258 EXPECT_TRUE(client_->should_auto_enroll());
259 EXPECT_EQ(1, completion_callback_count_);
260 VerifyCachedResult(true, 8);
Ben Murdochbb1529c2013-08-08 10:24:53 +0100261
262 // Network changes don't trigger retries after obtaining a response from
263 // the server.
264 client_->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_ETHERNET);
265 EXPECT_EQ(1, completion_callback_count_);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000266}
267
268TEST_F(AutoEnrollmentClientTest, NoSerial) {
269 CreateClient("", 4, 8);
270 client_->Start();
271 EXPECT_FALSE(client_->should_auto_enroll());
272 EXPECT_EQ(1, completion_callback_count_);
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100273 EXPECT_FALSE(HasCachedDecision());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000274}
275
276TEST_F(AutoEnrollmentClientTest, NoBitsUploaded) {
277 CreateClient(kSerial, 0, 0);
278 ServerWillReply(-1, false, false);
279 client_->Start();
280 EXPECT_FALSE(client_->should_auto_enroll());
281 EXPECT_EQ(1, completion_callback_count_);
282 EXPECT_TRUE(auto_enrollment_request().has_remainder());
283 EXPECT_TRUE(auto_enrollment_request().has_modulus());
284 EXPECT_EQ(1, auto_enrollment_request().modulus());
285 EXPECT_EQ(0, auto_enrollment_request().remainder());
286 VerifyCachedResult(false, 0);
287}
288
289TEST_F(AutoEnrollmentClientTest, ManyBitsUploaded) {
290 int64 bottom62 = GG_INT64_C(0x14e437a1552b138a);
291 for (int i = 0; i <= 62; ++i) {
292 completion_callback_count_ = 0;
293 CreateClient(kSerial, i, i);
294 ServerWillReply(-1, false, false);
295 client_->Start();
296 EXPECT_FALSE(client_->should_auto_enroll());
297 EXPECT_EQ(1, completion_callback_count_);
298 EXPECT_TRUE(auto_enrollment_request().has_remainder());
299 EXPECT_TRUE(auto_enrollment_request().has_modulus());
300 EXPECT_EQ(GG_INT64_C(1) << i, auto_enrollment_request().modulus());
301 EXPECT_EQ(bottom62 % (GG_INT64_C(1) << i),
302 auto_enrollment_request().remainder());
303 VerifyCachedResult(false, i);
304 }
305}
306
307TEST_F(AutoEnrollmentClientTest, MoreThan32BitsUploaded) {
308 CreateClient(kSerial, 10, 37);
309 InSequence sequence;
310 ServerWillReply(GG_INT64_C(1) << 37, false, false);
311 ServerWillReply(-1, true, true);
312 client_->Start();
313 EXPECT_TRUE(client_->should_auto_enroll());
314 EXPECT_EQ(1, completion_callback_count_);
315 VerifyCachedResult(true, 37);
316}
317
318TEST_F(AutoEnrollmentClientTest, ReuseCachedDecision) {
319 EXPECT_CALL(*service_, CreateJob(_)).Times(0);
320 local_state_->SetUserPref(prefs::kShouldAutoEnroll,
321 Value::CreateBooleanValue(true));
322 local_state_->SetUserPref(prefs::kAutoEnrollmentPowerLimit,
323 Value::CreateIntegerValue(8));
324 client_->Start();
325 EXPECT_TRUE(client_->should_auto_enroll());
326 EXPECT_EQ(1, completion_callback_count_);
327 AutoEnrollmentClient::CancelAutoEnrollment();
328 client_->Start();
329 EXPECT_FALSE(client_->should_auto_enroll());
330 EXPECT_EQ(2, completion_callback_count_);
331}
332
333TEST_F(AutoEnrollmentClientTest, RetryIfPowerLargerThanCached) {
334 local_state_->SetUserPref(prefs::kShouldAutoEnroll,
335 Value::CreateBooleanValue(false));
336 local_state_->SetUserPref(prefs::kAutoEnrollmentPowerLimit,
337 Value::CreateIntegerValue(8));
338 CreateClient(kSerial, 5, 10);
339 ServerWillReply(-1, true, true);
340 client_->Start();
341 EXPECT_TRUE(client_->should_auto_enroll());
342 EXPECT_EQ(1, completion_callback_count_);
343}
344
Ben Murdochbb1529c2013-08-08 10:24:53 +0100345TEST_F(AutoEnrollmentClientTest, NetworkChangeRetryAfterErrors) {
346 ServerWillFail(DM_STATUS_TEMPORARY_UNAVAILABLE);
347 client_->Start();
348 EXPECT_FALSE(client_->should_auto_enroll());
349 // Don't invoke the callback if there was a network failure.
350 EXPECT_EQ(0, completion_callback_count_);
351 EXPECT_FALSE(HasCachedDecision());
352
353 // The client doesn't retry if no new connection became available.
354 client_->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_NONE);
355 EXPECT_FALSE(client_->should_auto_enroll());
356 EXPECT_EQ(0, completion_callback_count_);
357 EXPECT_FALSE(HasCachedDecision());
358
359 // Retry once the network is back.
360 ServerWillReply(-1, true, true);
361 client_->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_ETHERNET);
362 EXPECT_TRUE(client_->should_auto_enroll());
363 EXPECT_EQ(1, completion_callback_count_);
364 EXPECT_TRUE(HasCachedDecision());
365
366 // Subsequent network changes don't trigger retries.
367 client_->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_NONE);
368 client_->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_ETHERNET);
369 EXPECT_TRUE(client_->should_auto_enroll());
370 EXPECT_EQ(1, completion_callback_count_);
371 EXPECT_TRUE(HasCachedDecision());
372}
373
374TEST_F(AutoEnrollmentClientTest, CancelAndDeleteSoonWithPendingRequest) {
375 MockDeviceManagementJob* job = NULL;
376 ServerWillReplyAsync(&job);
377 EXPECT_FALSE(job);
378 client_->Start();
379 ASSERT_TRUE(job);
380 EXPECT_EQ(0, completion_callback_count_);
381
382 // Cancel while a request is in flight.
383 EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting());
384 client_.release()->CancelAndDeleteSoon();
385 EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting());
386
387 // The client cleans itself up once a reply is received.
388 job->SendResponse(DM_STATUS_TEMPORARY_UNAVAILABLE,
389 em::DeviceManagementResponse());
390 // The DeleteSoon task has been posted:
391 EXPECT_FALSE(base::MessageLoop::current()->IsIdleForTesting());
392 EXPECT_EQ(0, completion_callback_count_);
393}
394
395TEST_F(AutoEnrollmentClientTest, NetworkChangedAfterCancelAndDeleteSoon) {
396 MockDeviceManagementJob* job = NULL;
397 ServerWillReplyAsync(&job);
398 EXPECT_FALSE(job);
399 client_->Start();
400 ASSERT_TRUE(job);
401 EXPECT_EQ(0, completion_callback_count_);
402
403 // Cancel while a request is in flight.
404 EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting());
405 AutoEnrollmentClient* client = client_.release();
406 client->CancelAndDeleteSoon();
407 EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting());
408
409 // Network change events are ignored while a request is pending.
410 client->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_ETHERNET);
411 EXPECT_EQ(0, completion_callback_count_);
412
413 // The client cleans itself up once a reply is received.
414 job->SendResponse(DM_STATUS_TEMPORARY_UNAVAILABLE,
415 em::DeviceManagementResponse());
416 // The DeleteSoon task has been posted:
417 EXPECT_FALSE(base::MessageLoop::current()->IsIdleForTesting());
418 EXPECT_EQ(0, completion_callback_count_);
419
420 // Network changes that have been posted before are also ignored:
421 client->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_ETHERNET);
422 EXPECT_EQ(0, completion_callback_count_);
423}
424
425TEST_F(AutoEnrollmentClientTest, CancelAndDeleteSoonAfterCompletion) {
426 ServerWillReply(-1, true, true);
427 client_->Start();
428 EXPECT_EQ(1, completion_callback_count_);
429 EXPECT_TRUE(client_->should_auto_enroll());
430
431 // The client will delete itself immediately if there are no pending
432 // requests.
433 EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting());
434 client_.release()->CancelAndDeleteSoon();
435 EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting());
436}
437
438TEST_F(AutoEnrollmentClientTest, CancelAndDeleteSoonAfterNetworkFailure) {
439 ServerWillFail(DM_STATUS_TEMPORARY_UNAVAILABLE);
440 client_->Start();
441 EXPECT_EQ(0, completion_callback_count_);
442 EXPECT_FALSE(client_->should_auto_enroll());
443
444 // The client will delete itself immediately if there are no pending
445 // requests.
446 EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting());
447 client_.release()->CancelAndDeleteSoon();
448 EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting());
449}
450
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000451} // namespace
452
453} // namespace policy