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/users/mock_user_manager.h"
16#include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.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      install_attributes_("managed.com",
156                          "user@managed.com",
157                          "device_id",
158                          DEVICE_MODE_ENTERPRISE),
159      user_manager_(new chromeos::MockUserManager()),
160      user_manager_enabler_(user_manager_) {
161    // Run this test with a well-known timezone so that Time::LocalMidnight()
162    // returns the same values on all machines.
163    scoped_ptr<base::Environment> env(base::Environment::Create());
164    env->SetVar("TZ", "UTC");
165
166    TestingDeviceStatusCollector::RegisterPrefs(prefs_.registry());
167
168    EXPECT_CALL(statistics_provider_, GetMachineStatistic(_, NotNull()))
169        .WillRepeatedly(Return(false));
170
171    // Remove the real DeviceSettingsProvider and replace it with a stub.
172    cros_settings_ = chromeos::CrosSettings::Get();
173    device_settings_provider_ =
174        cros_settings_->GetProvider(chromeos::kReportDeviceVersionInfo);
175    EXPECT_TRUE(device_settings_provider_ != NULL);
176    EXPECT_TRUE(
177        cros_settings_->RemoveSettingsProvider(device_settings_provider_));
178    cros_settings_->AddSettingsProvider(&stub_settings_provider_);
179
180    RestartStatusCollector();
181  }
182
183  virtual ~DeviceStatusCollectorTest() {
184    // Finish pending tasks.
185    content::BrowserThread::GetBlockingPool()->FlushForTesting();
186    message_loop_.RunUntilIdle();
187
188    // Restore the real DeviceSettingsProvider.
189    EXPECT_TRUE(
190      cros_settings_->RemoveSettingsProvider(&stub_settings_provider_));
191    cros_settings_->AddSettingsProvider(device_settings_provider_);
192  }
193
194  virtual void SetUp() OVERRIDE {
195    // Disable network interface reporting since it requires additional setup.
196    cros_settings_->SetBoolean(chromeos::kReportDeviceNetworkInterfaces, false);
197  }
198
199  void RestartStatusCollector() {
200    policy::DeviceStatusCollector::LocationUpdateRequester callback =
201        base::Bind(&MockPositionUpdateRequester);
202    status_collector_.reset(
203        new TestingDeviceStatusCollector(&prefs_,
204                                         &statistics_provider_,
205                                         &callback));
206  }
207
208  void GetStatus() {
209    status_.Clear();
210    status_collector_->GetDeviceStatus(&status_);
211  }
212
213  void CheckThatNoLocationIsReported() {
214    GetStatus();
215    EXPECT_FALSE(status_.has_device_location());
216  }
217
218  void CheckThatAValidLocationIsReported() {
219    // Checks that a location is being reported which matches the valid fix
220    // set using SetMockPositionToReturnNext().
221    GetStatus();
222    EXPECT_TRUE(status_.has_device_location());
223    em::DeviceLocation location = status_.device_location();
224    if (location.has_error_code())
225      EXPECT_EQ(em::DeviceLocation::ERROR_CODE_NONE, location.error_code());
226    EXPECT_TRUE(location.has_latitude());
227    EXPECT_TRUE(location.has_longitude());
228    EXPECT_TRUE(location.has_accuracy());
229    EXPECT_TRUE(location.has_timestamp());
230    EXPECT_FALSE(location.has_altitude());
231    EXPECT_FALSE(location.has_altitude_accuracy());
232    EXPECT_FALSE(location.has_heading());
233    EXPECT_FALSE(location.has_speed());
234    EXPECT_FALSE(location.has_error_message());
235    EXPECT_DOUBLE_EQ(4.3, location.latitude());
236    EXPECT_DOUBLE_EQ(-7.8, location.longitude());
237    EXPECT_DOUBLE_EQ(3., location.accuracy());
238    // Check that the timestamp is not older than ten minutes.
239    EXPECT_TRUE(Time::Now() - Time::FromDoubleT(location.timestamp() / 1000.) <
240                TimeDelta::FromMinutes(10));
241  }
242
243  void CheckThatALocationErrorIsReported() {
244    GetStatus();
245    EXPECT_TRUE(status_.has_device_location());
246    em::DeviceLocation location = status_.device_location();
247    EXPECT_TRUE(location.has_error_code());
248    EXPECT_EQ(em::DeviceLocation::ERROR_CODE_POSITION_UNAVAILABLE,
249              location.error_code());
250  }
251
252 protected:
253  // Convenience method.
254  int64 ActivePeriodMilliseconds() {
255    return policy::DeviceStatusCollector::kIdlePollIntervalSeconds * 1000;
256  }
257
258  // Since this is a unit test running in browser_tests we must do additional
259  // unit test setup and make a TestingBrowserProcess. Must be first member.
260  TestingBrowserProcessInitializer initializer_;
261  base::MessageLoopForUI message_loop_;
262  content::TestBrowserThread ui_thread_;
263  content::TestBrowserThread file_thread_;
264  content::TestBrowserThread io_thread_;
265
266  ScopedStubEnterpriseInstallAttributes install_attributes_;
267  TestingPrefServiceSimple prefs_;
268  chromeos::system::MockStatisticsProvider statistics_provider_;
269  chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
270  chromeos::ScopedTestCrosSettings test_cros_settings_;
271  chromeos::CrosSettings* cros_settings_;
272  chromeos::CrosSettingsProvider* device_settings_provider_;
273  chromeos::StubCrosSettingsProvider stub_settings_provider_;
274  chromeos::MockUserManager* user_manager_;
275  chromeos::ScopedUserManagerEnabler user_manager_enabler_;
276  em::DeviceStatusReportRequest status_;
277  scoped_ptr<TestingDeviceStatusCollector> status_collector_;
278};
279
280TEST_F(DeviceStatusCollectorTest, AllIdle) {
281  IdleState test_states[] = {
282    IDLE_STATE_IDLE,
283    IDLE_STATE_IDLE,
284    IDLE_STATE_IDLE
285  };
286  cros_settings_->SetBoolean(chromeos::kReportDeviceActivityTimes, true);
287
288  // Test reporting with no data.
289  GetStatus();
290  EXPECT_EQ(0, status_.active_period_size());
291  EXPECT_EQ(0, GetActiveMilliseconds(status_));
292
293  // Test reporting with a single idle sample.
294  status_collector_->Simulate(test_states, 1);
295  GetStatus();
296  EXPECT_EQ(0, status_.active_period_size());
297  EXPECT_EQ(0, GetActiveMilliseconds(status_));
298
299  // Test reporting with multiple consecutive idle samples.
300  status_collector_->Simulate(test_states,
301                              sizeof(test_states) / sizeof(IdleState));
302  GetStatus();
303  EXPECT_EQ(0, status_.active_period_size());
304  EXPECT_EQ(0, GetActiveMilliseconds(status_));
305}
306
307TEST_F(DeviceStatusCollectorTest, AllActive) {
308  IdleState test_states[] = {
309    IDLE_STATE_ACTIVE,
310    IDLE_STATE_ACTIVE,
311    IDLE_STATE_ACTIVE
312  };
313  cros_settings_->SetBoolean(chromeos::kReportDeviceActivityTimes, true);
314
315  // Test a single active sample.
316  status_collector_->Simulate(test_states, 1);
317  GetStatus();
318  EXPECT_EQ(1, status_.active_period_size());
319  EXPECT_EQ(1 * ActivePeriodMilliseconds(), GetActiveMilliseconds(status_));
320  status_.clear_active_period(); // Clear the result protobuf.
321
322  // Test multiple consecutive active samples.
323  status_collector_->Simulate(test_states,
324                              sizeof(test_states) / sizeof(IdleState));
325  GetStatus();
326  EXPECT_EQ(1, status_.active_period_size());
327  EXPECT_EQ(4 * ActivePeriodMilliseconds(), GetActiveMilliseconds(status_));
328}
329
330TEST_F(DeviceStatusCollectorTest, MixedStates) {
331  IdleState test_states[] = {
332    IDLE_STATE_ACTIVE,
333    IDLE_STATE_IDLE,
334    IDLE_STATE_ACTIVE,
335    IDLE_STATE_ACTIVE,
336    IDLE_STATE_IDLE,
337    IDLE_STATE_IDLE,
338    IDLE_STATE_ACTIVE
339  };
340  cros_settings_->SetBoolean(chromeos::kReportDeviceActivityTimes, true);
341  status_collector_->Simulate(test_states,
342                              sizeof(test_states) / sizeof(IdleState));
343  GetStatus();
344  EXPECT_EQ(4 * ActivePeriodMilliseconds(), GetActiveMilliseconds(status_));
345}
346
347TEST_F(DeviceStatusCollectorTest, StateKeptInPref) {
348  IdleState test_states[] = {
349    IDLE_STATE_ACTIVE,
350    IDLE_STATE_IDLE,
351    IDLE_STATE_ACTIVE,
352    IDLE_STATE_ACTIVE,
353    IDLE_STATE_IDLE,
354    IDLE_STATE_IDLE
355  };
356  cros_settings_->SetBoolean(chromeos::kReportDeviceActivityTimes, true);
357  status_collector_->Simulate(test_states,
358                              sizeof(test_states) / sizeof(IdleState));
359
360  // Process the list a second time after restarting the collector. It should be
361  // able to count the active periods found by the original collector, because
362  // the results are stored in a pref.
363  RestartStatusCollector();
364  status_collector_->Simulate(test_states,
365                              sizeof(test_states) / sizeof(IdleState));
366
367  GetStatus();
368  EXPECT_EQ(6 * ActivePeriodMilliseconds(), GetActiveMilliseconds(status_));
369}
370
371TEST_F(DeviceStatusCollectorTest, Times) {
372  IdleState test_states[] = {
373    IDLE_STATE_ACTIVE,
374    IDLE_STATE_IDLE,
375    IDLE_STATE_ACTIVE,
376    IDLE_STATE_ACTIVE,
377    IDLE_STATE_IDLE,
378    IDLE_STATE_IDLE
379  };
380  cros_settings_->SetBoolean(chromeos::kReportDeviceActivityTimes, true);
381  status_collector_->Simulate(test_states,
382                              sizeof(test_states) / sizeof(IdleState));
383  GetStatus();
384  EXPECT_EQ(3 * ActivePeriodMilliseconds(), GetActiveMilliseconds(status_));
385}
386
387TEST_F(DeviceStatusCollectorTest, MaxStoredPeriods) {
388  IdleState test_states[] = {
389    IDLE_STATE_ACTIVE,
390    IDLE_STATE_IDLE
391  };
392  const int kMaxDays = 10;
393
394  cros_settings_->SetBoolean(chromeos::kReportDeviceActivityTimes, true);
395  status_collector_->set_max_stored_past_activity_days(kMaxDays - 1);
396  status_collector_->set_max_stored_future_activity_days(1);
397  Time baseline = Time::Now().LocalMidnight();
398
399  // Simulate 12 active periods.
400  for (int i = 0; i < kMaxDays + 2; i++) {
401    status_collector_->Simulate(test_states,
402                                sizeof(test_states) / sizeof(IdleState));
403    // Advance the simulated clock by a day.
404    baseline += TimeDelta::FromDays(1);
405    status_collector_->SetBaselineTime(baseline);
406  }
407
408  // Check that we don't exceed the max number of periods.
409  GetStatus();
410  EXPECT_EQ(kMaxDays - 1, status_.active_period_size());
411
412  // Simulate some future times.
413  for (int i = 0; i < kMaxDays + 2; i++) {
414    status_collector_->Simulate(test_states,
415                                sizeof(test_states) / sizeof(IdleState));
416    // Advance the simulated clock by a day.
417    baseline += TimeDelta::FromDays(1);
418    status_collector_->SetBaselineTime(baseline);
419  }
420  // Set the clock back so the previous simulated times are in the future.
421  baseline -= TimeDelta::FromDays(20);
422  status_collector_->SetBaselineTime(baseline);
423
424  // Collect one more data point to trigger pruning.
425  status_collector_->Simulate(test_states, 1);
426
427  // Check that we don't exceed the max number of periods.
428  status_.clear_active_period();
429  GetStatus();
430  EXPECT_LT(status_.active_period_size(), kMaxDays);
431}
432
433TEST_F(DeviceStatusCollectorTest, ActivityTimesEnabledByDefault) {
434  // Device activity times should be reported by default.
435  IdleState test_states[] = {
436    IDLE_STATE_ACTIVE,
437    IDLE_STATE_ACTIVE,
438    IDLE_STATE_ACTIVE
439  };
440  status_collector_->Simulate(test_states,
441                              sizeof(test_states) / sizeof(IdleState));
442  GetStatus();
443  EXPECT_EQ(1, status_.active_period_size());
444  EXPECT_EQ(3 * ActivePeriodMilliseconds(), GetActiveMilliseconds(status_));
445}
446
447TEST_F(DeviceStatusCollectorTest, ActivityTimesOff) {
448  // Device activity times should not be reported if explicitly disabled.
449  cros_settings_->SetBoolean(chromeos::kReportDeviceActivityTimes, false);
450
451  IdleState test_states[] = {
452    IDLE_STATE_ACTIVE,
453    IDLE_STATE_ACTIVE,
454    IDLE_STATE_ACTIVE
455  };
456  status_collector_->Simulate(test_states,
457                              sizeof(test_states) / sizeof(IdleState));
458  GetStatus();
459  EXPECT_EQ(0, status_.active_period_size());
460  EXPECT_EQ(0, GetActiveMilliseconds(status_));
461}
462
463TEST_F(DeviceStatusCollectorTest, ActivityCrossingMidnight) {
464  IdleState test_states[] = {
465    IDLE_STATE_ACTIVE
466  };
467  cros_settings_->SetBoolean(chromeos::kReportDeviceActivityTimes, true);
468
469  // Set the baseline time to 10 seconds after midnight.
470  status_collector_->SetBaselineTime(
471      Time::Now().LocalMidnight() + TimeDelta::FromSeconds(10));
472
473  status_collector_->Simulate(test_states, 1);
474  GetStatus();
475  ASSERT_EQ(2, status_.active_period_size());
476
477  em::ActiveTimePeriod period0 = status_.active_period(0);
478  em::ActiveTimePeriod period1 = status_.active_period(1);
479  EXPECT_EQ(ActivePeriodMilliseconds() - 10000, period0.active_duration());
480  EXPECT_EQ(10000, period1.active_duration());
481
482  em::TimePeriod time_period0 = period0.time_period();
483  em::TimePeriod time_period1 = period1.time_period();
484
485  EXPECT_EQ(time_period0.end_timestamp(), time_period1.start_timestamp());
486
487  // Ensure that the start and end times for the period are a day apart.
488  EXPECT_EQ(time_period0.end_timestamp() - time_period0.start_timestamp(),
489            kMillisecondsPerDay);
490  EXPECT_EQ(time_period1.end_timestamp() - time_period1.start_timestamp(),
491            kMillisecondsPerDay);
492}
493
494TEST_F(DeviceStatusCollectorTest, ActivityTimesKeptUntilSubmittedSuccessfully) {
495  IdleState test_states[] = {
496    IDLE_STATE_ACTIVE,
497    IDLE_STATE_ACTIVE,
498  };
499  cros_settings_->SetBoolean(chromeos::kReportDeviceActivityTimes, true);
500
501  status_collector_->Simulate(test_states, 2);
502  GetStatus();
503  EXPECT_EQ(2 * ActivePeriodMilliseconds(), GetActiveMilliseconds(status_));
504  em::DeviceStatusReportRequest first_status(status_);
505
506  // The collector returns the same status again.
507  GetStatus();
508  EXPECT_EQ(first_status.SerializeAsString(), status_.SerializeAsString());
509
510  // After indicating a successful submit, the submitted status gets cleared,
511  // but what got collected meanwhile sticks around.
512  status_collector_->Simulate(test_states, 1);
513  status_collector_->OnSubmittedSuccessfully();
514  GetStatus();
515  EXPECT_EQ(ActivePeriodMilliseconds(), GetActiveMilliseconds(status_));
516}
517
518TEST_F(DeviceStatusCollectorTest, DevSwitchBootMode) {
519  // Test that boot mode data is reported by default.
520  EXPECT_CALL(statistics_provider_,
521              GetMachineStatistic("devsw_boot", NotNull()))
522      .WillOnce(DoAll(SetArgPointee<1>("0"), Return(true)));
523  GetStatus();
524  EXPECT_EQ("Verified", status_.boot_mode());
525
526  // Test that boot mode data is not reported if the pref turned off.
527  cros_settings_->SetBoolean(chromeos::kReportDeviceBootMode, false);
528
529  EXPECT_CALL(statistics_provider_,
530              GetMachineStatistic("devsw_boot", NotNull()))
531      .WillRepeatedly(DoAll(SetArgPointee<1>("0"), Return(true)));
532  GetStatus();
533  EXPECT_FALSE(status_.has_boot_mode());
534
535  // Turn the pref on, and check that the status is reported iff the
536  // statistics provider returns valid data.
537  cros_settings_->SetBoolean(chromeos::kReportDeviceBootMode, true);
538
539  EXPECT_CALL(statistics_provider_,
540              GetMachineStatistic("devsw_boot", NotNull()))
541      .WillOnce(DoAll(SetArgPointee<1>("(error)"), Return(true)));
542  GetStatus();
543  EXPECT_FALSE(status_.has_boot_mode());
544
545  EXPECT_CALL(statistics_provider_,
546              GetMachineStatistic("devsw_boot", NotNull()))
547      .WillOnce(DoAll(SetArgPointee<1>(" "), Return(true)));
548  GetStatus();
549  EXPECT_FALSE(status_.has_boot_mode());
550
551  EXPECT_CALL(statistics_provider_,
552              GetMachineStatistic("devsw_boot", NotNull()))
553      .WillOnce(DoAll(SetArgPointee<1>("0"), Return(true)));
554  GetStatus();
555  EXPECT_EQ("Verified", status_.boot_mode());
556
557  EXPECT_CALL(statistics_provider_,
558              GetMachineStatistic("devsw_boot", NotNull()))
559      .WillOnce(DoAll(SetArgPointee<1>("1"), Return(true)));
560  GetStatus();
561  EXPECT_EQ("Dev", status_.boot_mode());
562}
563
564TEST_F(DeviceStatusCollectorTest, VersionInfo) {
565  // Expect the version info to be reported by default.
566  GetStatus();
567  EXPECT_TRUE(status_.has_browser_version());
568  EXPECT_TRUE(status_.has_os_version());
569  EXPECT_TRUE(status_.has_firmware_version());
570
571  // When the pref to collect this data is not enabled, expect that none of
572  // the fields are present in the protobuf.
573  cros_settings_->SetBoolean(chromeos::kReportDeviceVersionInfo, false);
574  GetStatus();
575  EXPECT_FALSE(status_.has_browser_version());
576  EXPECT_FALSE(status_.has_os_version());
577  EXPECT_FALSE(status_.has_firmware_version());
578
579  cros_settings_->SetBoolean(chromeos::kReportDeviceVersionInfo, true);
580  GetStatus();
581  EXPECT_TRUE(status_.has_browser_version());
582  EXPECT_TRUE(status_.has_os_version());
583  EXPECT_TRUE(status_.has_firmware_version());
584
585  // Check that the browser version is not empty. OS version & firmware
586  // don't have any reasonable values inside the unit test, so those
587  // aren't checked.
588  EXPECT_NE("", status_.browser_version());
589}
590
591TEST_F(DeviceStatusCollectorTest, Location) {
592  content::Geoposition valid_fix;
593  valid_fix.latitude = 4.3;
594  valid_fix.longitude = -7.8;
595  valid_fix.accuracy = 3.;
596  valid_fix.timestamp = Time::Now();
597
598  content::Geoposition invalid_fix;
599  invalid_fix.error_code =
600      content::Geoposition::ERROR_CODE_POSITION_UNAVAILABLE;
601  invalid_fix.timestamp = Time::Now();
602
603  // Check that when device location reporting is disabled, no location is
604  // reported.
605  SetMockPositionToReturnNext(valid_fix);
606  CheckThatNoLocationIsReported();
607
608  // Check that when device location reporting is enabled and a valid fix is
609  // available, the location is reported and is stored in local state.
610  SetMockPositionToReturnNext(valid_fix);
611  cros_settings_->SetBoolean(chromeos::kReportDeviceLocation, true);
612  EXPECT_FALSE(prefs_.GetDictionary(prefs::kDeviceLocation)->empty());
613  CheckThatAValidLocationIsReported();
614
615  // Restart the status collector. Check that the last known location has been
616  // retrieved from local state without requesting a geolocation update.
617  SetMockPositionToReturnNext(valid_fix);
618  RestartStatusCollector();
619  CheckThatAValidLocationIsReported();
620  EXPECT_TRUE(mock_position_to_return_next.get());
621
622  // Check that after disabling location reporting again, the last known
623  // location has been cleared from local state and is no longer reported.
624  SetMockPositionToReturnNext(valid_fix);
625  cros_settings_->SetBoolean(chromeos::kReportDeviceLocation, false);
626  // Allow the new pref to propagate to the status collector.
627  message_loop_.RunUntilIdle();
628  EXPECT_TRUE(prefs_.GetDictionary(prefs::kDeviceLocation)->empty());
629  CheckThatNoLocationIsReported();
630
631  // Check that after enabling location reporting again, an error is reported
632  // if no valid fix is available.
633  SetMockPositionToReturnNext(invalid_fix);
634  cros_settings_->SetBoolean(chromeos::kReportDeviceLocation, true);
635  // Allow the new pref to propagate to the status collector.
636  message_loop_.RunUntilIdle();
637  CheckThatALocationErrorIsReported();
638}
639
640TEST_F(DeviceStatusCollectorTest, ReportUsers) {
641  user_manager_->CreatePublicAccountUser("public@localhost");
642  user_manager_->AddUser("user0@managed.com");
643  user_manager_->AddUser("user1@managed.com");
644  user_manager_->AddUser("user2@managed.com");
645  user_manager_->AddUser("user3@unmanaged.com");
646  user_manager_->AddUser("user4@managed.com");
647  user_manager_->AddUser("user5@managed.com");
648
649  // Verify that users are reported by default.
650  GetStatus();
651  EXPECT_EQ(6, status_.user_size());
652
653  // Verify that users are reported after enabling the setting.
654  cros_settings_->SetBoolean(chromeos::kReportDeviceUsers, true);
655  GetStatus();
656  EXPECT_EQ(6, status_.user_size());
657  EXPECT_EQ(em::DeviceUser::USER_TYPE_MANAGED, status_.user(0).type());
658  EXPECT_EQ("user0@managed.com", status_.user(0).email());
659  EXPECT_EQ(em::DeviceUser::USER_TYPE_MANAGED, status_.user(1).type());
660  EXPECT_EQ("user1@managed.com", status_.user(1).email());
661  EXPECT_EQ(em::DeviceUser::USER_TYPE_MANAGED, status_.user(2).type());
662  EXPECT_EQ("user2@managed.com", status_.user(2).email());
663  EXPECT_EQ(em::DeviceUser::USER_TYPE_UNMANAGED, status_.user(3).type());
664  EXPECT_FALSE(status_.user(3).has_email());
665  EXPECT_EQ(em::DeviceUser::USER_TYPE_MANAGED, status_.user(4).type());
666  EXPECT_EQ("user4@managed.com", status_.user(4).email());
667  EXPECT_EQ(em::DeviceUser::USER_TYPE_MANAGED, status_.user(5).type());
668  EXPECT_EQ("user5@managed.com", status_.user(5).email());
669
670  // Verify that users are no longer reported if setting is disabled.
671  cros_settings_->SetBoolean(chromeos::kReportDeviceUsers, false);
672  GetStatus();
673  EXPECT_EQ(0, status_.user_size());
674}
675
676// Fake device state.
677struct FakeDeviceData {
678  const char* device_path;
679  const char* type;
680  const char* object_path;
681  const char* mac_address;
682  const char* meid;
683  const char* imei;
684  int expected_type; // proto enum type value, -1 for not present.
685};
686
687static const FakeDeviceData kFakeDevices[] = {
688  { "/device/ethernet", shill::kTypeEthernet, "ethernet",
689    "112233445566", "", "",
690    em::NetworkInterface::TYPE_ETHERNET },
691  { "/device/cellular1", shill::kTypeCellular, "cellular1",
692    "abcdefabcdef", "A10000009296F2", "",
693    em::NetworkInterface::TYPE_CELLULAR },
694  { "/device/cellular2", shill::kTypeCellular, "cellular2",
695    "abcdefabcdef", "", "352099001761481",
696    em::NetworkInterface::TYPE_CELLULAR },
697  { "/device/wifi", shill::kTypeWifi, "wifi",
698    "aabbccddeeff", "", "",
699    em::NetworkInterface::TYPE_WIFI },
700  { "/device/bluetooth", shill::kTypeBluetooth, "bluetooth",
701    "", "", "",
702    em::NetworkInterface::TYPE_BLUETOOTH },
703  { "/device/vpn", shill::kTypeVPN, "vpn",
704    "", "", "",
705    -1 },
706};
707
708class DeviceStatusCollectorNetworkInterfacesTest
709    : public DeviceStatusCollectorTest {
710 protected:
711  virtual void SetUp() OVERRIDE {
712    chromeos::DBusThreadManager::Initialize();
713    chromeos::NetworkHandler::Initialize();
714    chromeos::ShillDeviceClient::TestInterface* test_device_client =
715        chromeos::DBusThreadManager::Get()->GetShillDeviceClient()->
716            GetTestInterface();
717    test_device_client->ClearDevices();
718    for (size_t i = 0; i < arraysize(kFakeDevices); ++i) {
719      const FakeDeviceData& dev = kFakeDevices[i];
720      test_device_client->AddDevice(dev.device_path, dev.type,
721                                    dev.object_path);
722      if (*dev.mac_address) {
723        test_device_client->SetDeviceProperty(
724            dev.device_path, shill::kAddressProperty,
725            base::StringValue(dev.mac_address));
726      }
727      if (*dev.meid) {
728        test_device_client->SetDeviceProperty(
729            dev.device_path, shill::kMeidProperty,
730            base::StringValue(dev.meid));
731      }
732      if (*dev.imei) {
733        test_device_client->SetDeviceProperty(
734            dev.device_path, shill::kImeiProperty,
735            base::StringValue(dev.imei));
736      }
737    }
738
739    // Flush out pending state updates.
740    base::RunLoop().RunUntilIdle();
741  }
742
743  virtual void TearDown() OVERRIDE {
744    chromeos::NetworkHandler::Shutdown();
745    chromeos::DBusThreadManager::Shutdown();
746  }
747};
748
749TEST_F(DeviceStatusCollectorNetworkInterfacesTest, NetworkInterfaces) {
750  // Interfaces should be reported by default.
751  GetStatus();
752  EXPECT_TRUE(status_.network_interface_size() > 0);
753
754  // No interfaces should be reported if the policy is off.
755  cros_settings_->SetBoolean(chromeos::kReportDeviceNetworkInterfaces, false);
756  GetStatus();
757  EXPECT_EQ(0, status_.network_interface_size());
758
759  // Switch the policy on and verify the interface list is present.
760  cros_settings_->SetBoolean(chromeos::kReportDeviceNetworkInterfaces, true);
761  GetStatus();
762
763  int count = 0;
764  for (size_t i = 0; i < arraysize(kFakeDevices); ++i) {
765    const FakeDeviceData& dev = kFakeDevices[i];
766    if (dev.expected_type == -1)
767      continue;
768
769    // Find the corresponding entry in reporting data.
770    bool found_match = false;
771    google::protobuf::RepeatedPtrField<em::NetworkInterface>::const_iterator
772        iface;
773    for (iface = status_.network_interface().begin();
774         iface != status_.network_interface().end();
775         ++iface) {
776      // Check whether type, field presence and field values match.
777      if (dev.expected_type == iface->type() &&
778          iface->has_mac_address() == !!*dev.mac_address &&
779          iface->has_meid() == !!*dev.meid &&
780          iface->has_imei() == !!*dev.imei &&
781          iface->mac_address() == dev.mac_address &&
782          iface->meid() == dev.meid &&
783          iface->imei() == dev.imei) {
784        found_match = true;
785        break;
786      }
787    }
788
789    EXPECT_TRUE(found_match) << "No matching interface for fake device " << i;
790    count++;
791  }
792
793  EXPECT_EQ(count, status_.network_interface_size());
794}
795
796}  // namespace policy
797