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