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