device_status_collector_browsertest.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/device_status_collector.h"
6
7#include "base/environment.h"
8#include "base/logging.h"
9#include "base/memory/scoped_ptr.h"
10#include "base/message_loop/message_loop.h"
11#include "base/prefs/pref_service.h"
12#include "base/prefs/testing_pref_service.h"
13#include "base/run_loop.h"
14#include "base/threading/sequenced_worker_pool.h"
15#include "chrome/browser/chromeos/login/mock_user_manager.h"
16#include "chrome/browser/chromeos/login/user_manager.h"
17#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
18#include "chrome/browser/chromeos/policy/stub_enterprise_install_attributes.h"
19#include "chrome/browser/chromeos/settings/cros_settings.h"
20#include "chrome/browser/chromeos/settings/device_settings_service.h"
21#include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h"
22#include "chrome/common/pref_names.h"
23#include "chrome/test/base/testing_browser_process.h"
24#include "chromeos/dbus/dbus_thread_manager.h"
25#include "chromeos/dbus/shill_device_client.h"
26#include "chromeos/network/network_handler.h"
27#include "chromeos/settings/cros_settings_names.h"
28#include "chromeos/settings/cros_settings_provider.h"
29#include "chromeos/system/mock_statistics_provider.h"
30#include "content/public/browser/browser_thread.h"
31#include "content/public/browser/geolocation_provider.h"
32#include "content/public/test/test_browser_thread.h"
33#include "content/public/test/test_utils.h"
34#include "policy/proto/device_management_backend.pb.h"
35#include "testing/gmock/include/gmock/gmock.h"
36#include "testing/gtest/include/gtest/gtest.h"
37#include "third_party/cros_system_api/dbus/service_constants.h"
38
39using ::testing::DoAll;
40using ::testing::NotNull;
41using ::testing::Return;
42using ::testing::SetArgPointee;
43using ::testing::_;
44using base::Time;
45using base::TimeDelta;
46
47namespace em = enterprise_management;
48
49namespace {
50
51const int64 kMillisecondsPerDay = Time::kMicrosecondsPerDay / 1000;
52
53scoped_ptr<content::Geoposition> mock_position_to_return_next;
54
55void SetMockPositionToReturnNext(const content::Geoposition &position) {
56  mock_position_to_return_next.reset(new content::Geoposition(position));
57}
58
59void MockPositionUpdateRequester(
60    const content::GeolocationProvider::LocationUpdateCallback& callback) {
61  if (!mock_position_to_return_next.get())
62    return;
63
64  // If the fix is invalid, the DeviceStatusCollector will immediately request
65  // another update when it receives the callback. This is desirable and safe in
66  // real life where geolocation updates arrive asynchronously. In this testing
67  // harness, the callback is invoked synchronously upon request, leading to a
68  // request-callback loop. The loop is broken by returning the mock position
69  // only once.
70  scoped_ptr<content::Geoposition> position(
71      mock_position_to_return_next.release());
72  callback.Run(*position);
73}
74
75class TestingDeviceStatusCollector : public policy::DeviceStatusCollector {
76 public:
77  TestingDeviceStatusCollector(
78      PrefService* local_state,
79      chromeos::system::StatisticsProvider* provider,
80      policy::DeviceStatusCollector::LocationUpdateRequester*
81          location_update_requester)
82      : policy::DeviceStatusCollector(
83          local_state,
84          provider,
85          location_update_requester) {
86    // Set the baseline time to a fixed value (1 AM) to prevent test flakiness
87    // due to a single activity period spanning two days.
88    SetBaselineTime(Time::Now().LocalMidnight() + TimeDelta::FromHours(1));
89  }
90
91  void Simulate(IdleState* states, int len) {
92    for (int i = 0; i < len; i++)
93      IdleStateCallback(states[i]);
94  }
95
96  void set_max_stored_past_activity_days(unsigned int value) {
97    max_stored_past_activity_days_ = value;
98  }
99
100  void set_max_stored_future_activity_days(unsigned int value) {
101    max_stored_future_activity_days_ = value;
102  }
103
104  // Reset the baseline time.
105  void SetBaselineTime(Time time) {
106    baseline_time_ = time;
107    baseline_offset_periods_ = 0;
108  }
109
110 protected:
111  virtual void CheckIdleState() OVERRIDE {
112    // This should never be called in testing, as it results in a dbus call.
113    ADD_FAILURE();
114  }
115
116  // Each time this is called, returns a time that is a fixed increment
117  // later than the previous time.
118  virtual Time GetCurrentTime() OVERRIDE {
119    int poll_interval = policy::DeviceStatusCollector::kIdlePollIntervalSeconds;
120    return baseline_time_ +
121        TimeDelta::FromSeconds(poll_interval * baseline_offset_periods_++);
122  }
123
124 private:
125  // Baseline time for the fake times returned from GetCurrentTime().
126  Time baseline_time_;
127
128  // The number of simulated periods since the baseline time.
129  int baseline_offset_periods_;
130};
131
132// Return the total number of active milliseconds contained in a device
133// status report.
134int64 GetActiveMilliseconds(em::DeviceStatusReportRequest& status) {
135  int64 active_milliseconds = 0;
136  for (int i = 0; i < status.active_period_size(); i++) {
137    active_milliseconds += status.active_period(i).active_duration();
138  }
139  return active_milliseconds;
140}
141
142}  // namespace
143
144namespace policy {
145
146// Though it is a unit test, this test is linked with browser_tests so that it
147// runs in a separate process. The intention is to avoid overriding the timezone
148// environment variable for other tests.
149class DeviceStatusCollectorTest : public testing::Test {
150 public:
151  DeviceStatusCollectorTest()
152    : ui_thread_(content::BrowserThread::UI, &message_loop_),
153      file_thread_(content::BrowserThread::FILE, &message_loop_),
154      io_thread_(content::BrowserThread::IO, &message_loop_),
155      user_manager_(new chromeos::MockUserManager()),
156      user_manager_enabler_(user_manager_) {
157    // Run this test with a well-known timezone so that Time::LocalMidnight()
158    // returns the same values on all machines.
159    scoped_ptr<base::Environment> env(base::Environment::Create());
160    env->SetVar("TZ", "UTC");
161
162    TestingDeviceStatusCollector::RegisterPrefs(prefs_.registry());
163
164    EXPECT_CALL(statistics_provider_, GetMachineStatistic(_, NotNull()))
165        .WillRepeatedly(Return(false));
166
167    // Remove the real DeviceSettingsProvider and replace it with a stub.
168    cros_settings_ = chromeos::CrosSettings::Get();
169    device_settings_provider_ =
170        cros_settings_->GetProvider(chromeos::kReportDeviceVersionInfo);
171    EXPECT_TRUE(device_settings_provider_ != NULL);
172    EXPECT_TRUE(
173        cros_settings_->RemoveSettingsProvider(device_settings_provider_));
174    cros_settings_->AddSettingsProvider(&stub_settings_provider_);
175
176    // Set up fake install attributes.
177    StubEnterpriseInstallAttributes* attributes =
178        new StubEnterpriseInstallAttributes();
179    attributes->SetDomain("managed.com");
180    attributes->SetRegistrationUser("user@managed.com");
181    BrowserPolicyConnectorChromeOS::SetInstallAttributesForTesting(attributes);
182
183    RestartStatusCollector();
184  }
185
186  virtual ~DeviceStatusCollectorTest() {
187    // Finish pending tasks.
188    content::BrowserThread::GetBlockingPool()->FlushForTesting();
189    message_loop_.RunUntilIdle();
190
191    // Restore the real DeviceSettingsProvider.
192    EXPECT_TRUE(
193      cros_settings_->RemoveSettingsProvider(&stub_settings_provider_));
194    cros_settings_->AddSettingsProvider(device_settings_provider_);
195  }
196
197  void RestartStatusCollector() {
198    policy::DeviceStatusCollector::LocationUpdateRequester callback =
199        base::Bind(&MockPositionUpdateRequester);
200    status_collector_.reset(
201        new TestingDeviceStatusCollector(&prefs_,
202                                         &statistics_provider_,
203                                         &callback));
204  }
205
206  void GetStatus() {
207    status_.Clear();
208    status_collector_->GetDeviceStatus(&status_);
209  }
210
211  void CheckThatNoLocationIsReported() {
212    GetStatus();
213    EXPECT_FALSE(status_.has_device_location());
214  }
215
216  void CheckThatAValidLocationIsReported() {
217    // Checks that a location is being reported which matches the valid fix
218    // set using SetMockPositionToReturnNext().
219    GetStatus();
220    EXPECT_TRUE(status_.has_device_location());
221    em::DeviceLocation location = status_.device_location();
222    if (location.has_error_code())
223      EXPECT_EQ(em::DeviceLocation::ERROR_CODE_NONE, location.error_code());
224    EXPECT_TRUE(location.has_latitude());
225    EXPECT_TRUE(location.has_longitude());
226    EXPECT_TRUE(location.has_accuracy());
227    EXPECT_TRUE(location.has_timestamp());
228    EXPECT_FALSE(location.has_altitude());
229    EXPECT_FALSE(location.has_altitude_accuracy());
230    EXPECT_FALSE(location.has_heading());
231    EXPECT_FALSE(location.has_speed());
232    EXPECT_FALSE(location.has_error_message());
233    EXPECT_DOUBLE_EQ(4.3, location.latitude());
234    EXPECT_DOUBLE_EQ(-7.8, location.longitude());
235    EXPECT_DOUBLE_EQ(3., location.accuracy());
236    // Check that the timestamp is not older than ten minutes.
237    EXPECT_TRUE(Time::Now() - Time::FromDoubleT(location.timestamp() / 1000.) <
238                TimeDelta::FromMinutes(10));
239  }
240
241  void CheckThatALocationErrorIsReported() {
242    GetStatus();
243    EXPECT_TRUE(status_.has_device_location());
244    em::DeviceLocation location = status_.device_location();
245    EXPECT_TRUE(location.has_error_code());
246    EXPECT_EQ(em::DeviceLocation::ERROR_CODE_POSITION_UNAVAILABLE,
247              location.error_code());
248  }
249
250 protected:
251  // Convenience method.
252  int64 ActivePeriodMilliseconds() {
253    return policy::DeviceStatusCollector::kIdlePollIntervalSeconds * 1000;
254  }
255
256  // Since this is a unit test running in browser_tests we must do additional
257  // unit test setup and make a TestingBrowserProcess. Must be first member.
258  TestingBrowserProcessInitializer initializer_;
259  base::MessageLoopForUI message_loop_;
260  content::TestBrowserThread ui_thread_;
261  content::TestBrowserThread file_thread_;
262  content::TestBrowserThread io_thread_;
263
264  TestingPrefServiceSimple prefs_;
265  chromeos::system::MockStatisticsProvider statistics_provider_;
266  chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
267  chromeos::ScopedTestCrosSettings test_cros_settings_;
268  chromeos::CrosSettings* cros_settings_;
269  chromeos::CrosSettingsProvider* device_settings_provider_;
270  chromeos::StubCrosSettingsProvider stub_settings_provider_;
271  chromeos::MockUserManager* user_manager_;
272  chromeos::ScopedUserManagerEnabler user_manager_enabler_;
273  em::DeviceStatusReportRequest status_;
274  scoped_ptr<TestingDeviceStatusCollector> status_collector_;
275};
276
277TEST_F(DeviceStatusCollectorTest, AllIdle) {
278  IdleState test_states[] = {
279    IDLE_STATE_IDLE,
280    IDLE_STATE_IDLE,
281    IDLE_STATE_IDLE
282  };
283  cros_settings_->SetBoolean(chromeos::kReportDeviceActivityTimes, true);
284
285  // Test reporting with no data.
286  GetStatus();
287  EXPECT_EQ(0, status_.active_period_size());
288  EXPECT_EQ(0, GetActiveMilliseconds(status_));
289
290  // Test reporting with a single idle sample.
291  status_collector_->Simulate(test_states, 1);
292  GetStatus();
293  EXPECT_EQ(0, status_.active_period_size());
294  EXPECT_EQ(0, GetActiveMilliseconds(status_));
295
296  // Test reporting with multiple consecutive idle samples.
297  status_collector_->Simulate(test_states,
298                              sizeof(test_states) / sizeof(IdleState));
299  GetStatus();
300  EXPECT_EQ(0, status_.active_period_size());
301  EXPECT_EQ(0, GetActiveMilliseconds(status_));
302}
303
304TEST_F(DeviceStatusCollectorTest, AllActive) {
305  IdleState test_states[] = {
306    IDLE_STATE_ACTIVE,
307    IDLE_STATE_ACTIVE,
308    IDLE_STATE_ACTIVE
309  };
310  cros_settings_->SetBoolean(chromeos::kReportDeviceActivityTimes, true);
311
312  // Test a single active sample.
313  status_collector_->Simulate(test_states, 1);
314  GetStatus();
315  EXPECT_EQ(1, status_.active_period_size());
316  EXPECT_EQ(1 * ActivePeriodMilliseconds(), GetActiveMilliseconds(status_));
317  status_.clear_active_period(); // Clear the result protobuf.
318
319  // Test multiple consecutive active samples.
320  status_collector_->Simulate(test_states,
321                              sizeof(test_states) / sizeof(IdleState));
322  GetStatus();
323  EXPECT_EQ(1, status_.active_period_size());
324  EXPECT_EQ(4 * ActivePeriodMilliseconds(), GetActiveMilliseconds(status_));
325}
326
327TEST_F(DeviceStatusCollectorTest, MixedStates) {
328  IdleState test_states[] = {
329    IDLE_STATE_ACTIVE,
330    IDLE_STATE_IDLE,
331    IDLE_STATE_ACTIVE,
332    IDLE_STATE_ACTIVE,
333    IDLE_STATE_IDLE,
334    IDLE_STATE_IDLE,
335    IDLE_STATE_ACTIVE
336  };
337  cros_settings_->SetBoolean(chromeos::kReportDeviceActivityTimes, true);
338  status_collector_->Simulate(test_states,
339                              sizeof(test_states) / sizeof(IdleState));
340  GetStatus();
341  EXPECT_EQ(4 * ActivePeriodMilliseconds(), GetActiveMilliseconds(status_));
342}
343
344TEST_F(DeviceStatusCollectorTest, StateKeptInPref) {
345  IdleState test_states[] = {
346    IDLE_STATE_ACTIVE,
347    IDLE_STATE_IDLE,
348    IDLE_STATE_ACTIVE,
349    IDLE_STATE_ACTIVE,
350    IDLE_STATE_IDLE,
351    IDLE_STATE_IDLE
352  };
353  cros_settings_->SetBoolean(chromeos::kReportDeviceActivityTimes, true);
354  status_collector_->Simulate(test_states,
355                              sizeof(test_states) / sizeof(IdleState));
356
357  // Process the list a second time after restarting the collector. It should be
358  // able to count the active periods found by the original collector, because
359  // the results are stored in a pref.
360  RestartStatusCollector();
361  status_collector_->Simulate(test_states,
362                              sizeof(test_states) / sizeof(IdleState));
363
364  GetStatus();
365  EXPECT_EQ(6 * ActivePeriodMilliseconds(), GetActiveMilliseconds(status_));
366}
367
368TEST_F(DeviceStatusCollectorTest, Times) {
369  IdleState test_states[] = {
370    IDLE_STATE_ACTIVE,
371    IDLE_STATE_IDLE,
372    IDLE_STATE_ACTIVE,
373    IDLE_STATE_ACTIVE,
374    IDLE_STATE_IDLE,
375    IDLE_STATE_IDLE
376  };
377  cros_settings_->SetBoolean(chromeos::kReportDeviceActivityTimes, true);
378  status_collector_->Simulate(test_states,
379                              sizeof(test_states) / sizeof(IdleState));
380  GetStatus();
381  EXPECT_EQ(3 * ActivePeriodMilliseconds(), GetActiveMilliseconds(status_));
382}
383
384TEST_F(DeviceStatusCollectorTest, MaxStoredPeriods) {
385  IdleState test_states[] = {
386    IDLE_STATE_ACTIVE,
387    IDLE_STATE_IDLE
388  };
389  const int kMaxDays = 10;
390
391  cros_settings_->SetBoolean(chromeos::kReportDeviceActivityTimes, true);
392  status_collector_->set_max_stored_past_activity_days(kMaxDays - 1);
393  status_collector_->set_max_stored_future_activity_days(1);
394  Time baseline = Time::Now().LocalMidnight();
395
396  // Simulate 12 active periods.
397  for (int i = 0; i < kMaxDays + 2; i++) {
398    status_collector_->Simulate(test_states,
399                                sizeof(test_states) / sizeof(IdleState));
400    // Advance the simulated clock by a day.
401    baseline += TimeDelta::FromDays(1);
402    status_collector_->SetBaselineTime(baseline);
403  }
404
405  // Check that we don't exceed the max number of periods.
406  GetStatus();
407  EXPECT_EQ(kMaxDays - 1, status_.active_period_size());
408
409  // Simulate some future times.
410  for (int i = 0; i < kMaxDays + 2; i++) {
411    status_collector_->Simulate(test_states,
412                                sizeof(test_states) / sizeof(IdleState));
413    // Advance the simulated clock by a day.
414    baseline += TimeDelta::FromDays(1);
415    status_collector_->SetBaselineTime(baseline);
416  }
417  // Set the clock back so the previous simulated times are in the future.
418  baseline -= TimeDelta::FromDays(20);
419  status_collector_->SetBaselineTime(baseline);
420
421  // Collect one more data point to trigger pruning.
422  status_collector_->Simulate(test_states, 1);
423
424  // Check that we don't exceed the max number of periods.
425  status_.clear_active_period();
426  GetStatus();
427  EXPECT_LT(status_.active_period_size(), kMaxDays);
428}
429
430TEST_F(DeviceStatusCollectorTest, ActivityTimesDisabledByDefault) {
431  // If the pref for collecting device activity times isn't explicitly turned
432  // on, no data on activity times should be reported.
433
434  IdleState test_states[] = {
435    IDLE_STATE_ACTIVE,
436    IDLE_STATE_ACTIVE,
437    IDLE_STATE_ACTIVE
438  };
439  status_collector_->Simulate(test_states,
440                              sizeof(test_states) / sizeof(IdleState));
441  GetStatus();
442  EXPECT_EQ(0, status_.active_period_size());
443  EXPECT_EQ(0, GetActiveMilliseconds(status_));
444}
445
446TEST_F(DeviceStatusCollectorTest, ActivityCrossingMidnight) {
447  IdleState test_states[] = {
448    IDLE_STATE_ACTIVE
449  };
450  cros_settings_->SetBoolean(chromeos::kReportDeviceActivityTimes, true);
451
452  // Set the baseline time to 10 seconds after midnight.
453  status_collector_->SetBaselineTime(
454      Time::Now().LocalMidnight() + TimeDelta::FromSeconds(10));
455
456  status_collector_->Simulate(test_states, 1);
457  GetStatus();
458  ASSERT_EQ(2, status_.active_period_size());
459
460  em::ActiveTimePeriod period0 = status_.active_period(0);
461  em::ActiveTimePeriod period1 = status_.active_period(1);
462  EXPECT_EQ(ActivePeriodMilliseconds() - 10000, period0.active_duration());
463  EXPECT_EQ(10000, period1.active_duration());
464
465  em::TimePeriod time_period0 = period0.time_period();
466  em::TimePeriod time_period1 = period1.time_period();
467
468  EXPECT_EQ(time_period0.end_timestamp(), time_period1.start_timestamp());
469
470  // Ensure that the start and end times for the period are a day apart.
471  EXPECT_EQ(time_period0.end_timestamp() - time_period0.start_timestamp(),
472            kMillisecondsPerDay);
473  EXPECT_EQ(time_period1.end_timestamp() - time_period1.start_timestamp(),
474            kMillisecondsPerDay);
475}
476
477TEST_F(DeviceStatusCollectorTest, ActivityTimesKeptUntilSubmittedSuccessfully) {
478  IdleState test_states[] = {
479    IDLE_STATE_ACTIVE,
480    IDLE_STATE_ACTIVE,
481  };
482  cros_settings_->SetBoolean(chromeos::kReportDeviceActivityTimes, true);
483
484  status_collector_->Simulate(test_states, 2);
485  GetStatus();
486  EXPECT_EQ(2 * ActivePeriodMilliseconds(), GetActiveMilliseconds(status_));
487  em::DeviceStatusReportRequest first_status(status_);
488
489  // The collector returns the same status again.
490  GetStatus();
491  EXPECT_EQ(first_status.SerializeAsString(), status_.SerializeAsString());
492
493  // After indicating a successful submit, the submitted status gets cleared,
494  // but what got collected meanwhile sticks around.
495  status_collector_->Simulate(test_states, 1);
496  status_collector_->OnSubmittedSuccessfully();
497  GetStatus();
498  EXPECT_EQ(ActivePeriodMilliseconds(), GetActiveMilliseconds(status_));
499}
500
501TEST_F(DeviceStatusCollectorTest, DevSwitchBootMode) {
502  // Test that boot mode data is not reported if the pref is not turned on.
503  EXPECT_CALL(statistics_provider_,
504              GetMachineStatistic("devsw_boot", NotNull()))
505      .WillRepeatedly(DoAll(SetArgPointee<1>("0"), Return(true)));
506  GetStatus();
507  EXPECT_FALSE(status_.has_boot_mode());
508
509  // Turn the pref on, and check that the status is reported iff the
510  // statistics provider returns valid data.
511  cros_settings_->SetBoolean(chromeos::kReportDeviceBootMode, true);
512
513  EXPECT_CALL(statistics_provider_,
514              GetMachineStatistic("devsw_boot", NotNull()))
515      .WillOnce(DoAll(SetArgPointee<1>("(error)"), Return(true)));
516  GetStatus();
517  EXPECT_FALSE(status_.has_boot_mode());
518
519  EXPECT_CALL(statistics_provider_,
520              GetMachineStatistic("devsw_boot", NotNull()))
521      .WillOnce(DoAll(SetArgPointee<1>(" "), Return(true)));
522  GetStatus();
523  EXPECT_FALSE(status_.has_boot_mode());
524
525  EXPECT_CALL(statistics_provider_,
526              GetMachineStatistic("devsw_boot", NotNull()))
527      .WillOnce(DoAll(SetArgPointee<1>("0"), Return(true)));
528  GetStatus();
529  EXPECT_EQ("Verified", status_.boot_mode());
530
531  EXPECT_CALL(statistics_provider_,
532              GetMachineStatistic("devsw_boot", NotNull()))
533      .WillOnce(DoAll(SetArgPointee<1>("1"), Return(true)));
534  GetStatus();
535  EXPECT_EQ("Dev", status_.boot_mode());
536}
537
538TEST_F(DeviceStatusCollectorTest, VersionInfo) {
539  // When the pref to collect this data is not enabled, expect that none of
540  // the fields are present in the protobuf.
541  GetStatus();
542  EXPECT_FALSE(status_.has_browser_version());
543  EXPECT_FALSE(status_.has_os_version());
544  EXPECT_FALSE(status_.has_firmware_version());
545
546  cros_settings_->SetBoolean(chromeos::kReportDeviceVersionInfo, true);
547  GetStatus();
548  EXPECT_TRUE(status_.has_browser_version());
549  EXPECT_TRUE(status_.has_os_version());
550  EXPECT_TRUE(status_.has_firmware_version());
551
552  // Check that the browser version is not empty. OS version & firmware
553  // don't have any reasonable values inside the unit test, so those
554  // aren't checked.
555  EXPECT_NE("", status_.browser_version());
556}
557
558TEST_F(DeviceStatusCollectorTest, Location) {
559  content::Geoposition valid_fix;
560  valid_fix.latitude = 4.3;
561  valid_fix.longitude = -7.8;
562  valid_fix.accuracy = 3.;
563  valid_fix.timestamp = Time::Now();
564
565  content::Geoposition invalid_fix;
566  invalid_fix.error_code =
567      content::Geoposition::ERROR_CODE_POSITION_UNAVAILABLE;
568  invalid_fix.timestamp = Time::Now();
569
570  // Check that when device location reporting is disabled, no location is
571  // reported.
572  SetMockPositionToReturnNext(valid_fix);
573  CheckThatNoLocationIsReported();
574
575  // Check that when device location reporting is enabled and a valid fix is
576  // available, the location is reported and is stored in local state.
577  SetMockPositionToReturnNext(valid_fix);
578  cros_settings_->SetBoolean(chromeos::kReportDeviceLocation, true);
579  EXPECT_FALSE(prefs_.GetDictionary(prefs::kDeviceLocation)->empty());
580  CheckThatAValidLocationIsReported();
581
582  // Restart the status collector. Check that the last known location has been
583  // retrieved from local state without requesting a geolocation update.
584  SetMockPositionToReturnNext(valid_fix);
585  RestartStatusCollector();
586  CheckThatAValidLocationIsReported();
587  EXPECT_TRUE(mock_position_to_return_next.get());
588
589  // Check that after disabling location reporting again, the last known
590  // location has been cleared from local state and is no longer reported.
591  SetMockPositionToReturnNext(valid_fix);
592  cros_settings_->SetBoolean(chromeos::kReportDeviceLocation, false);
593  // Allow the new pref to propagate to the status collector.
594  message_loop_.RunUntilIdle();
595  EXPECT_TRUE(prefs_.GetDictionary(prefs::kDeviceLocation)->empty());
596  CheckThatNoLocationIsReported();
597
598  // Check that after enabling location reporting again, an error is reported
599  // if no valid fix is available.
600  SetMockPositionToReturnNext(invalid_fix);
601  cros_settings_->SetBoolean(chromeos::kReportDeviceLocation, true);
602  // Allow the new pref to propagate to the status collector.
603  message_loop_.RunUntilIdle();
604  CheckThatALocationErrorIsReported();
605}
606
607TEST_F(DeviceStatusCollectorTest, ReportUsers) {
608  user_manager_->CreatePublicAccountUser("public@localhost");
609  user_manager_->AddUser("user0@managed.com");
610  user_manager_->AddUser("user1@managed.com");
611  user_manager_->AddUser("user2@managed.com");
612  user_manager_->AddUser("user3@unmanaged.com");
613  user_manager_->AddUser("user4@managed.com");
614  user_manager_->AddUser("user5@managed.com");
615
616  // Verify that users are not reported by default.
617  GetStatus();
618  EXPECT_EQ(0, status_.user_size());
619
620  // Verify that users are reported after enabling the setting.
621  cros_settings_->SetBoolean(chromeos::kReportDeviceUsers, true);
622  GetStatus();
623  EXPECT_EQ(5, status_.user_size());
624  EXPECT_EQ(em::DeviceUser::USER_TYPE_MANAGED, status_.user(0).type());
625  EXPECT_EQ("user0@managed.com", status_.user(0).email());
626  EXPECT_EQ(em::DeviceUser::USER_TYPE_MANAGED, status_.user(1).type());
627  EXPECT_EQ("user1@managed.com", status_.user(1).email());
628  EXPECT_EQ(em::DeviceUser::USER_TYPE_MANAGED, status_.user(2).type());
629  EXPECT_EQ("user2@managed.com", status_.user(2).email());
630  EXPECT_EQ(em::DeviceUser::USER_TYPE_UNMANAGED, status_.user(3).type());
631  EXPECT_FALSE(status_.user(3).has_email());
632  EXPECT_EQ(em::DeviceUser::USER_TYPE_MANAGED, status_.user(4).type());
633  EXPECT_EQ("user4@managed.com", status_.user(4).email());
634
635  // Verify that users are no longer reported if setting is disabled.
636  cros_settings_->SetBoolean(chromeos::kReportDeviceUsers, false);
637  GetStatus();
638  EXPECT_EQ(0, status_.user_size());
639}
640
641TEST_F(DeviceStatusCollectorTest, ReportManagedUser) {
642  // Verify that at least one managed user is reported regardless of list size.
643  user_manager_->AddUser("user0@unmanaged.com");
644  user_manager_->AddUser("user1@unmanaged.com");
645  user_manager_->AddUser("user2@unmanaged.com");
646  user_manager_->AddUser("user3@unmanaged.com");
647  user_manager_->AddUser("user4@unmanaged.com");
648  user_manager_->AddUser("user5@unmanaged.com");
649  user_manager_->AddUser("user6@managed.com");
650  user_manager_->AddUser("user7@managed.com");
651
652  cros_settings_->SetBoolean(chromeos::kReportDeviceUsers, true);
653  GetStatus();
654  EXPECT_EQ(7, status_.user_size());
655  for (int i = 0; i < 6; ++i)
656    EXPECT_EQ(em::DeviceUser::USER_TYPE_UNMANAGED, status_.user(i).type());
657  EXPECT_EQ(em::DeviceUser::USER_TYPE_MANAGED, status_.user(6).type());
658  EXPECT_EQ("user6@managed.com", status_.user(6).email());
659}
660
661// Fake device state.
662struct FakeDeviceData {
663  const char* device_path;
664  const char* type;
665  const char* object_path;
666  const char* mac_address;
667  const char* meid;
668  const char* imei;
669  int expected_type; // proto enum type value, -1 for not present.
670};
671
672static const FakeDeviceData kFakeDevices[] = {
673  { "/device/ethernet", shill::kTypeEthernet, "ethernet",
674    "112233445566", "", "",
675    em::NetworkInterface::TYPE_ETHERNET },
676  { "/device/cellular1", shill::kTypeCellular, "cellular1",
677    "abcdefabcdef", "A10000009296F2", "",
678    em::NetworkInterface::TYPE_CELLULAR },
679  { "/device/cellular2", shill::kTypeCellular, "cellular2",
680    "abcdefabcdef", "", "352099001761481",
681    em::NetworkInterface::TYPE_CELLULAR },
682  { "/device/wifi", shill::kTypeWifi, "wifi",
683    "aabbccddeeff", "", "",
684    em::NetworkInterface::TYPE_WIFI },
685  { "/device/bluetooth", shill::kTypeBluetooth, "bluetooth",
686    "", "", "",
687    em::NetworkInterface::TYPE_BLUETOOTH },
688  { "/device/vpn", shill::kTypeVPN, "vpn",
689    "", "", "",
690    -1 },
691};
692
693class DeviceStatusCollectorNetworkInterfacesTest
694    : public DeviceStatusCollectorTest {
695 protected:
696  virtual void SetUp() OVERRIDE {
697    chromeos::DBusThreadManager::InitializeWithStub();
698    chromeos::NetworkHandler::Initialize();
699    chromeos::ShillDeviceClient::TestInterface* test_device_client =
700        chromeos::DBusThreadManager::Get()->GetShillDeviceClient()->
701            GetTestInterface();
702    test_device_client->ClearDevices();
703    for (size_t i = 0; i < arraysize(kFakeDevices); ++i) {
704      const FakeDeviceData& dev = kFakeDevices[i];
705      test_device_client->AddDevice(dev.device_path, dev.type,
706                                    dev.object_path);
707      if (*dev.mac_address) {
708        test_device_client->SetDeviceProperty(
709            dev.device_path, shill::kAddressProperty,
710            base::StringValue(dev.mac_address));
711      }
712      if (*dev.meid) {
713        test_device_client->SetDeviceProperty(
714            dev.device_path, shill::kMeidProperty,
715            base::StringValue(dev.meid));
716      }
717      if (*dev.imei) {
718        test_device_client->SetDeviceProperty(
719            dev.device_path, shill::kImeiProperty,
720            base::StringValue(dev.imei));
721      }
722    }
723
724    // Flush out pending state updates.
725    base::RunLoop().RunUntilIdle();
726  }
727
728  virtual void TearDown() OVERRIDE {
729    chromeos::NetworkHandler::Shutdown();
730    chromeos::DBusThreadManager::Shutdown();
731  }
732};
733
734TEST_F(DeviceStatusCollectorNetworkInterfacesTest, NetworkInterfaces) {
735  // No interfaces should be reported if the policy is off.
736  GetStatus();
737  EXPECT_EQ(0, status_.network_interface_size());
738
739  // Switch the policy on and verify the interface list is present.
740  cros_settings_->SetBoolean(chromeos::kReportDeviceNetworkInterfaces, true);
741  GetStatus();
742
743  int count = 0;
744  for (size_t i = 0; i < arraysize(kFakeDevices); ++i) {
745    const FakeDeviceData& dev = kFakeDevices[i];
746    if (dev.expected_type == -1)
747      continue;
748
749    // Find the corresponding entry in reporting data.
750    bool found_match = false;
751    google::protobuf::RepeatedPtrField<em::NetworkInterface>::const_iterator
752        iface;
753    for (iface = status_.network_interface().begin();
754         iface != status_.network_interface().end();
755         ++iface) {
756      // Check whether type, field presence and field values match.
757      if (dev.expected_type == iface->type() &&
758          iface->has_mac_address() == !!*dev.mac_address &&
759          iface->has_meid() == !!*dev.meid &&
760          iface->has_imei() == !!*dev.imei &&
761          iface->mac_address() == dev.mac_address &&
762          iface->meid() == dev.meid &&
763          iface->imei() == dev.imei) {
764        found_match = true;
765        break;
766      }
767    }
768
769    EXPECT_TRUE(found_match) << "No matching interface for fake device " << i;
770    count++;
771  }
772
773  EXPECT_EQ(count, status_.network_interface_size());
774}
775
776}  // namespace policy
777