Home | History | Annotate | Download | only in policy
      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 
     39 using ::testing::DoAll;
     40 using ::testing::NotNull;
     41 using ::testing::Return;
     42 using ::testing::SetArgPointee;
     43 using ::testing::_;
     44 using base::Time;
     45 using base::TimeDelta;
     46 
     47 namespace em = enterprise_management;
     48 
     49 namespace {
     50 
     51 const int64 kMillisecondsPerDay = Time::kMicrosecondsPerDay / 1000;
     52 
     53 scoped_ptr<content::Geoposition> mock_position_to_return_next;
     54 
     55 void SetMockPositionToReturnNext(const content::Geoposition &position) {
     56   mock_position_to_return_next.reset(new content::Geoposition(position));
     57 }
     58 
     59 void 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 
     75 class 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.
    134 int64 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 
    144 namespace 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.
    149 class 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 (at) 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 
    280 TEST_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 
    307 TEST_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 
    330 TEST_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 
    347 TEST_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 
    371 TEST_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 
    387 TEST_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 
    433 TEST_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 
    447 TEST_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 
    463 TEST_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 
    494 TEST_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 
    518 TEST_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 
    564 TEST_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 
    591 TEST_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 
    640 TEST_F(DeviceStatusCollectorTest, ReportUsers) {
    641   user_manager_->CreatePublicAccountUser("public@localhost");
    642   user_manager_->AddUser("user0 (at) managed.com");
    643   user_manager_->AddUser("user1 (at) managed.com");
    644   user_manager_->AddUser("user2 (at) managed.com");
    645   user_manager_->AddUser("user3 (at) unmanaged.com");
    646   user_manager_->AddUser("user4 (at) managed.com");
    647   user_manager_->AddUser("user5 (at) 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 (at) managed.com", status_.user(0).email());
    659   EXPECT_EQ(em::DeviceUser::USER_TYPE_MANAGED, status_.user(1).type());
    660   EXPECT_EQ("user1 (at) managed.com", status_.user(1).email());
    661   EXPECT_EQ(em::DeviceUser::USER_TYPE_MANAGED, status_.user(2).type());
    662   EXPECT_EQ("user2 (at) 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 (at) managed.com", status_.user(4).email());
    667   EXPECT_EQ(em::DeviceUser::USER_TYPE_MANAGED, status_.user(5).type());
    668   EXPECT_EQ("user5 (at) 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.
    677 struct 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 
    687 static 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 
    708 class 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 
    749 TEST_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