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