auto_enrollment_client_unittest.cc revision bb1529ce867d8845a77ec7cdf3e3003ef1771a40
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        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
104  void ServerWillReplyAsync(MockDeviceManagementJob** job) {
105    EXPECT_CALL(*service_,
106                CreateJob(DeviceManagementRequestJob::TYPE_AUTO_ENROLLMENT))
107        .WillOnce(service_->CreateAsyncJob(job));
108  }
109
110  bool HasCachedDecision() {
111    return local_state_->GetUserPref(prefs::kShouldAutoEnroll);
112  }
113
114  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
129  content::TestBrowserThreadBundle browser_threads_;
130  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());
145  EXPECT_EQ(0, completion_callback_count_);
146  EXPECT_FALSE(HasCachedDecision());
147}
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());
176  EXPECT_EQ(0, completion_callback_count_);
177  EXPECT_FALSE(HasCachedDecision());
178}
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_);
187  EXPECT_FALSE(HasCachedDecision());
188}
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_);
217  EXPECT_FALSE(HasCachedDecision());
218}
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_);
225  EXPECT_FALSE(HasCachedDecision());
226}
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);
248
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_);
253}
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);
261
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_);
266}
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_);
273  EXPECT_FALSE(HasCachedDecision());
274}
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
345TEST_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
451}  // namespace
452
453}  // namespace policy
454