blob: 79ea72c4f42c9b3fc6af55fbcd5127d231e0662a [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/policy/device_status_collector.h"
#include "base/environment.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/prefs/pref_service.h"
#include "base/prefs/testing_pref_service.h"
#include "base/run_loop.h"
#include "base/threading/sequenced_worker_pool.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/chromeos/settings/device_settings_service.h"
#include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h"
#include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
#include "chrome/common/pref_names.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/shill_device_client.h"
#include "chromeos/network/network_handler.h"
#include "chromeos/settings/cros_settings_names.h"
#include "chromeos/settings/cros_settings_provider.h"
#include "chromeos/system/mock_statistics_provider.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/geolocation_provider.h"
#include "content/public/test/test_browser_thread.h"
#include "content/public/test/test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
using ::testing::DoAll;
using ::testing::NotNull;
using ::testing::Return;
using ::testing::SetArgPointee;
using ::testing::_;
using base::Time;
using base::TimeDelta;
namespace em = enterprise_management;
namespace {
const int64 kMillisecondsPerDay = Time::kMicrosecondsPerDay / 1000;
scoped_ptr<content::Geoposition> mock_position_to_return_next;
void SetMockPositionToReturnNext(const content::Geoposition &position) {
mock_position_to_return_next.reset(new content::Geoposition(position));
}
void MockPositionUpdateRequester(
const content::GeolocationProvider::LocationUpdateCallback& callback) {
if (!mock_position_to_return_next.get())
return;
// If the fix is invalid, the DeviceStatusCollector will immediately request
// another update when it receives the callback. This is desirable and safe in
// real life where geolocation updates arrive asynchronously. In this testing
// harness, the callback is invoked synchronously upon request, leading to a
// request-callback loop. The loop is broken by returning the mock position
// only once.
scoped_ptr<content::Geoposition> position(
mock_position_to_return_next.release());
callback.Run(*position);
}
class TestingDeviceStatusCollector : public policy::DeviceStatusCollector {
public:
TestingDeviceStatusCollector(
PrefService* local_state,
chromeos::system::StatisticsProvider* provider,
policy::DeviceStatusCollector::LocationUpdateRequester*
location_update_requester)
: policy::DeviceStatusCollector(
local_state,
provider,
location_update_requester) {
// Set the baseline time to a fixed value (1 AM) to prevent test flakiness
// due to a single activity period spanning two days.
SetBaselineTime(Time::Now().LocalMidnight() + TimeDelta::FromHours(1));
}
void Simulate(IdleState* states, int len) {
for (int i = 0; i < len; i++)
IdleStateCallback(states[i]);
}
void set_max_stored_past_activity_days(unsigned int value) {
max_stored_past_activity_days_ = value;
}
void set_max_stored_future_activity_days(unsigned int value) {
max_stored_future_activity_days_ = value;
}
// Reset the baseline time.
void SetBaselineTime(Time time) {
baseline_time_ = time;
baseline_offset_periods_ = 0;
}
protected:
virtual void CheckIdleState() OVERRIDE {
// This should never be called in testing, as it results in a dbus call.
ADD_FAILURE();
}
// Each time this is called, returns a time that is a fixed increment
// later than the previous time.
virtual Time GetCurrentTime() OVERRIDE {
int poll_interval = policy::DeviceStatusCollector::kIdlePollIntervalSeconds;
return baseline_time_ +
TimeDelta::FromSeconds(poll_interval * baseline_offset_periods_++);
}
private:
// Baseline time for the fake times returned from GetCurrentTime().
Time baseline_time_;
// The number of simulated periods since the baseline time.
int baseline_offset_periods_;
};
// Return the total number of active milliseconds contained in a device
// status report.
int64 GetActiveMilliseconds(em::DeviceStatusReportRequest& status) {
int64 active_milliseconds = 0;
for (int i = 0; i < status.active_period_size(); i++) {
active_milliseconds += status.active_period(i).active_duration();
}
return active_milliseconds;
}
} // namespace
namespace policy {
// Though it is a unit test, this test is linked with browser_tests so that it
// runs in a separate process. The intention is to avoid overriding the timezone
// environment variable for other tests.
class DeviceStatusCollectorTest : public testing::Test {
public:
DeviceStatusCollectorTest()
: message_loop_(base::MessageLoop::TYPE_UI),
ui_thread_(content::BrowserThread::UI, &message_loop_),
file_thread_(content::BrowserThread::FILE, &message_loop_),
io_thread_(content::BrowserThread::IO, &message_loop_) {
// Run this test with a well-known timezone so that Time::LocalMidnight()
// returns the same values on all machines.
scoped_ptr<base::Environment> env(base::Environment::Create());
env->SetVar("TZ", "UTC");
TestingDeviceStatusCollector::RegisterPrefs(prefs_.registry());
EXPECT_CALL(statistics_provider_, GetMachineStatistic(_, NotNull()))
.WillRepeatedly(Return(false));
// Remove the real DeviceSettingsProvider and replace it with a stub.
cros_settings_ = chromeos::CrosSettings::Get();
device_settings_provider_ =
cros_settings_->GetProvider(chromeos::kReportDeviceVersionInfo);
EXPECT_TRUE(device_settings_provider_ != NULL);
EXPECT_TRUE(
cros_settings_->RemoveSettingsProvider(device_settings_provider_));
cros_settings_->AddSettingsProvider(&stub_settings_provider_);
RestartStatusCollector();
}
virtual ~DeviceStatusCollectorTest() {
// Finish pending tasks.
content::BrowserThread::GetBlockingPool()->FlushForTesting();
message_loop_.RunUntilIdle();
// Restore the real DeviceSettingsProvider.
EXPECT_TRUE(
cros_settings_->RemoveSettingsProvider(&stub_settings_provider_));
cros_settings_->AddSettingsProvider(device_settings_provider_);
}
void RestartStatusCollector() {
policy::DeviceStatusCollector::LocationUpdateRequester callback =
base::Bind(&MockPositionUpdateRequester);
status_collector_.reset(
new TestingDeviceStatusCollector(&prefs_,
&statistics_provider_,
&callback));
}
void GetStatus() {
status_.Clear();
status_collector_->GetDeviceStatus(&status_);
}
void CheckThatNoLocationIsReported() {
GetStatus();
EXPECT_FALSE(status_.has_device_location());
}
void CheckThatAValidLocationIsReported() {
// Checks that a location is being reported which matches the valid fix
// set using SetMockPositionToReturnNext().
GetStatus();
EXPECT_TRUE(status_.has_device_location());
em::DeviceLocation location = status_.device_location();
if (location.has_error_code())
EXPECT_EQ(em::DeviceLocation::ERROR_CODE_NONE, location.error_code());
EXPECT_TRUE(location.has_latitude());
EXPECT_TRUE(location.has_longitude());
EXPECT_TRUE(location.has_accuracy());
EXPECT_TRUE(location.has_timestamp());
EXPECT_FALSE(location.has_altitude());
EXPECT_FALSE(location.has_altitude_accuracy());
EXPECT_FALSE(location.has_heading());
EXPECT_FALSE(location.has_speed());
EXPECT_FALSE(location.has_error_message());
EXPECT_DOUBLE_EQ(4.3, location.latitude());
EXPECT_DOUBLE_EQ(-7.8, location.longitude());
EXPECT_DOUBLE_EQ(3., location.accuracy());
// Check that the timestamp is not older than ten minutes.
EXPECT_TRUE(Time::Now() - Time::FromDoubleT(location.timestamp() / 1000.) <
TimeDelta::FromMinutes(10));
}
void CheckThatALocationErrorIsReported() {
GetStatus();
EXPECT_TRUE(status_.has_device_location());
em::DeviceLocation location = status_.device_location();
EXPECT_TRUE(location.has_error_code());
EXPECT_EQ(em::DeviceLocation::ERROR_CODE_POSITION_UNAVAILABLE,
location.error_code());
}
protected:
// Convenience method.
int64 ActivePeriodMilliseconds() {
return policy::DeviceStatusCollector::kIdlePollIntervalSeconds * 1000;
}
base::MessageLoop message_loop_;
content::TestBrowserThread ui_thread_;
content::TestBrowserThread file_thread_;
content::TestBrowserThread io_thread_;
TestingPrefServiceSimple prefs_;
chromeos::system::MockStatisticsProvider statistics_provider_;
chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
chromeos::ScopedTestCrosSettings test_cros_settings_;
chromeos::CrosSettings* cros_settings_;
chromeos::CrosSettingsProvider* device_settings_provider_;
chromeos::StubCrosSettingsProvider stub_settings_provider_;
em::DeviceStatusReportRequest status_;
scoped_ptr<TestingDeviceStatusCollector> status_collector_;
};
TEST_F(DeviceStatusCollectorTest, AllIdle) {
IdleState test_states[] = {
IDLE_STATE_IDLE,
IDLE_STATE_IDLE,
IDLE_STATE_IDLE
};
cros_settings_->SetBoolean(chromeos::kReportDeviceActivityTimes, true);
// Test reporting with no data.
GetStatus();
EXPECT_EQ(0, status_.active_period_size());
EXPECT_EQ(0, GetActiveMilliseconds(status_));
// Test reporting with a single idle sample.
status_collector_->Simulate(test_states, 1);
GetStatus();
EXPECT_EQ(0, status_.active_period_size());
EXPECT_EQ(0, GetActiveMilliseconds(status_));
// Test reporting with multiple consecutive idle samples.
status_collector_->Simulate(test_states,
sizeof(test_states) / sizeof(IdleState));
GetStatus();
EXPECT_EQ(0, status_.active_period_size());
EXPECT_EQ(0, GetActiveMilliseconds(status_));
}
TEST_F(DeviceStatusCollectorTest, AllActive) {
IdleState test_states[] = {
IDLE_STATE_ACTIVE,
IDLE_STATE_ACTIVE,
IDLE_STATE_ACTIVE
};
cros_settings_->SetBoolean(chromeos::kReportDeviceActivityTimes, true);
// Test a single active sample.
status_collector_->Simulate(test_states, 1);
GetStatus();
EXPECT_EQ(1, status_.active_period_size());
EXPECT_EQ(1 * ActivePeriodMilliseconds(), GetActiveMilliseconds(status_));
status_.clear_active_period(); // Clear the result protobuf.
// Test multiple consecutive active samples.
status_collector_->Simulate(test_states,
sizeof(test_states) / sizeof(IdleState));
GetStatus();
EXPECT_EQ(1, status_.active_period_size());
EXPECT_EQ(4 * ActivePeriodMilliseconds(), GetActiveMilliseconds(status_));
}
TEST_F(DeviceStatusCollectorTest, MixedStates) {
IdleState test_states[] = {
IDLE_STATE_ACTIVE,
IDLE_STATE_IDLE,
IDLE_STATE_ACTIVE,
IDLE_STATE_ACTIVE,
IDLE_STATE_IDLE,
IDLE_STATE_IDLE,
IDLE_STATE_ACTIVE
};
cros_settings_->SetBoolean(chromeos::kReportDeviceActivityTimes, true);
status_collector_->Simulate(test_states,
sizeof(test_states) / sizeof(IdleState));
GetStatus();
EXPECT_EQ(4 * ActivePeriodMilliseconds(), GetActiveMilliseconds(status_));
}
TEST_F(DeviceStatusCollectorTest, StateKeptInPref) {
IdleState test_states[] = {
IDLE_STATE_ACTIVE,
IDLE_STATE_IDLE,
IDLE_STATE_ACTIVE,
IDLE_STATE_ACTIVE,
IDLE_STATE_IDLE,
IDLE_STATE_IDLE
};
cros_settings_->SetBoolean(chromeos::kReportDeviceActivityTimes, true);
status_collector_->Simulate(test_states,
sizeof(test_states) / sizeof(IdleState));
// Process the list a second time after restarting the collector. It should be
// able to count the active periods found by the original collector, because
// the results are stored in a pref.
RestartStatusCollector();
status_collector_->Simulate(test_states,
sizeof(test_states) / sizeof(IdleState));
GetStatus();
EXPECT_EQ(6 * ActivePeriodMilliseconds(), GetActiveMilliseconds(status_));
}
TEST_F(DeviceStatusCollectorTest, Times) {
IdleState test_states[] = {
IDLE_STATE_ACTIVE,
IDLE_STATE_IDLE,
IDLE_STATE_ACTIVE,
IDLE_STATE_ACTIVE,
IDLE_STATE_IDLE,
IDLE_STATE_IDLE
};
cros_settings_->SetBoolean(chromeos::kReportDeviceActivityTimes, true);
status_collector_->Simulate(test_states,
sizeof(test_states) / sizeof(IdleState));
GetStatus();
EXPECT_EQ(3 * ActivePeriodMilliseconds(), GetActiveMilliseconds(status_));
}
TEST_F(DeviceStatusCollectorTest, MaxStoredPeriods) {
IdleState test_states[] = {
IDLE_STATE_ACTIVE,
IDLE_STATE_IDLE
};
const int kMaxDays = 10;
cros_settings_->SetBoolean(chromeos::kReportDeviceActivityTimes, true);
status_collector_->set_max_stored_past_activity_days(kMaxDays - 1);
status_collector_->set_max_stored_future_activity_days(1);
Time baseline = Time::Now().LocalMidnight();
// Simulate 12 active periods.
for (int i = 0; i < kMaxDays + 2; i++) {
status_collector_->Simulate(test_states,
sizeof(test_states) / sizeof(IdleState));
// Advance the simulated clock by a day.
baseline += TimeDelta::FromDays(1);
status_collector_->SetBaselineTime(baseline);
}
// Check that we don't exceed the max number of periods.
GetStatus();
EXPECT_EQ(kMaxDays - 1, status_.active_period_size());
// Simulate some future times.
for (int i = 0; i < kMaxDays + 2; i++) {
status_collector_->Simulate(test_states,
sizeof(test_states) / sizeof(IdleState));
// Advance the simulated clock by a day.
baseline += TimeDelta::FromDays(1);
status_collector_->SetBaselineTime(baseline);
}
// Set the clock back so the previous simulated times are in the future.
baseline -= TimeDelta::FromDays(20);
status_collector_->SetBaselineTime(baseline);
// Collect one more data point to trigger pruning.
status_collector_->Simulate(test_states, 1);
// Check that we don't exceed the max number of periods.
status_.clear_active_period();
GetStatus();
EXPECT_LT(status_.active_period_size(), kMaxDays);
}
TEST_F(DeviceStatusCollectorTest, ActivityTimesDisabledByDefault) {
// If the pref for collecting device activity times isn't explicitly turned
// on, no data on activity times should be reported.
IdleState test_states[] = {
IDLE_STATE_ACTIVE,
IDLE_STATE_ACTIVE,
IDLE_STATE_ACTIVE
};
status_collector_->Simulate(test_states,
sizeof(test_states) / sizeof(IdleState));
GetStatus();
EXPECT_EQ(0, status_.active_period_size());
EXPECT_EQ(0, GetActiveMilliseconds(status_));
}
TEST_F(DeviceStatusCollectorTest, ActivityCrossingMidnight) {
IdleState test_states[] = {
IDLE_STATE_ACTIVE
};
cros_settings_->SetBoolean(chromeos::kReportDeviceActivityTimes, true);
// Set the baseline time to 10 seconds after midnight.
status_collector_->SetBaselineTime(
Time::Now().LocalMidnight() + TimeDelta::FromSeconds(10));
status_collector_->Simulate(test_states, 1);
GetStatus();
ASSERT_EQ(2, status_.active_period_size());
em::ActiveTimePeriod period0 = status_.active_period(0);
em::ActiveTimePeriod period1 = status_.active_period(1);
EXPECT_EQ(ActivePeriodMilliseconds() - 10000, period0.active_duration());
EXPECT_EQ(10000, period1.active_duration());
em::TimePeriod time_period0 = period0.time_period();
em::TimePeriod time_period1 = period1.time_period();
EXPECT_EQ(time_period0.end_timestamp(), time_period1.start_timestamp());
// Ensure that the start and end times for the period are a day apart.
EXPECT_EQ(time_period0.end_timestamp() - time_period0.start_timestamp(),
kMillisecondsPerDay);
EXPECT_EQ(time_period1.end_timestamp() - time_period1.start_timestamp(),
kMillisecondsPerDay);
}
TEST_F(DeviceStatusCollectorTest, ActivityTimesKeptUntilSubmittedSuccessfully) {
IdleState test_states[] = {
IDLE_STATE_ACTIVE,
IDLE_STATE_ACTIVE,
};
cros_settings_->SetBoolean(chromeos::kReportDeviceActivityTimes, true);
status_collector_->Simulate(test_states, 2);
GetStatus();
EXPECT_EQ(2 * ActivePeriodMilliseconds(), GetActiveMilliseconds(status_));
em::DeviceStatusReportRequest first_status(status_);
// The collector returns the same status again.
GetStatus();
EXPECT_EQ(first_status.SerializeAsString(), status_.SerializeAsString());
// After indicating a successful submit, the submitted status gets cleared,
// but what got collected meanwhile sticks around.
status_collector_->Simulate(test_states, 1);
status_collector_->OnSubmittedSuccessfully();
GetStatus();
EXPECT_EQ(ActivePeriodMilliseconds(), GetActiveMilliseconds(status_));
}
TEST_F(DeviceStatusCollectorTest, DevSwitchBootMode) {
// Test that boot mode data is not reported if the pref is not turned on.
EXPECT_CALL(statistics_provider_,
GetMachineStatistic("devsw_boot", NotNull()))
.WillRepeatedly(DoAll(SetArgPointee<1>("0"), Return(true)));
GetStatus();
EXPECT_FALSE(status_.has_boot_mode());
// Turn the pref on, and check that the status is reported iff the
// statistics provider returns valid data.
cros_settings_->SetBoolean(chromeos::kReportDeviceBootMode, true);
EXPECT_CALL(statistics_provider_,
GetMachineStatistic("devsw_boot", NotNull()))
.WillOnce(DoAll(SetArgPointee<1>("(error)"), Return(true)));
GetStatus();
EXPECT_FALSE(status_.has_boot_mode());
EXPECT_CALL(statistics_provider_,
GetMachineStatistic("devsw_boot", NotNull()))
.WillOnce(DoAll(SetArgPointee<1>(" "), Return(true)));
GetStatus();
EXPECT_FALSE(status_.has_boot_mode());
EXPECT_CALL(statistics_provider_,
GetMachineStatistic("devsw_boot", NotNull()))
.WillOnce(DoAll(SetArgPointee<1>("0"), Return(true)));
GetStatus();
EXPECT_EQ("Verified", status_.boot_mode());
EXPECT_CALL(statistics_provider_,
GetMachineStatistic("devsw_boot", NotNull()))
.WillOnce(DoAll(SetArgPointee<1>("1"), Return(true)));
GetStatus();
EXPECT_EQ("Dev", status_.boot_mode());
}
TEST_F(DeviceStatusCollectorTest, VersionInfo) {
// When the pref to collect this data is not enabled, expect that none of
// the fields are present in the protobuf.
GetStatus();
EXPECT_FALSE(status_.has_browser_version());
EXPECT_FALSE(status_.has_os_version());
EXPECT_FALSE(status_.has_firmware_version());
cros_settings_->SetBoolean(chromeos::kReportDeviceVersionInfo, true);
GetStatus();
EXPECT_TRUE(status_.has_browser_version());
EXPECT_TRUE(status_.has_os_version());
EXPECT_TRUE(status_.has_firmware_version());
// Check that the browser version is not empty. OS version & firmware
// don't have any reasonable values inside the unit test, so those
// aren't checked.
EXPECT_NE("", status_.browser_version());
}
TEST_F(DeviceStatusCollectorTest, Location) {
content::Geoposition valid_fix;
valid_fix.latitude = 4.3;
valid_fix.longitude = -7.8;
valid_fix.accuracy = 3.;
valid_fix.timestamp = Time::Now();
content::Geoposition invalid_fix;
invalid_fix.error_code =
content::Geoposition::ERROR_CODE_POSITION_UNAVAILABLE;
invalid_fix.timestamp = Time::Now();
// Check that when device location reporting is disabled, no location is
// reported.
SetMockPositionToReturnNext(valid_fix);
CheckThatNoLocationIsReported();
// Check that when device location reporting is enabled and a valid fix is
// available, the location is reported and is stored in local state.
SetMockPositionToReturnNext(valid_fix);
cros_settings_->SetBoolean(chromeos::kReportDeviceLocation, true);
EXPECT_FALSE(prefs_.GetDictionary(prefs::kDeviceLocation)->empty());
CheckThatAValidLocationIsReported();
// Restart the status collector. Check that the last known location has been
// retrieved from local state without requesting a geolocation update.
SetMockPositionToReturnNext(valid_fix);
RestartStatusCollector();
CheckThatAValidLocationIsReported();
EXPECT_TRUE(mock_position_to_return_next.get());
// Check that after disabling location reporting again, the last known
// location has been cleared from local state and is no longer reported.
SetMockPositionToReturnNext(valid_fix);
cros_settings_->SetBoolean(chromeos::kReportDeviceLocation, false);
// Allow the new pref to propagate to the status collector.
message_loop_.RunUntilIdle();
EXPECT_TRUE(prefs_.GetDictionary(prefs::kDeviceLocation)->empty());
CheckThatNoLocationIsReported();
// Check that after enabling location reporting again, an error is reported
// if no valid fix is available.
SetMockPositionToReturnNext(invalid_fix);
cros_settings_->SetBoolean(chromeos::kReportDeviceLocation, true);
// Allow the new pref to propagate to the status collector.
message_loop_.RunUntilIdle();
CheckThatALocationErrorIsReported();
}
// Fake device state.
struct FakeDeviceData {
const char* device_path;
const char* type;
const char* object_path;
const char* mac_address;
const char* meid;
const char* imei;
int expected_type; // proto enum type value, -1 for not present.
};
static const FakeDeviceData kFakeDevices[] = {
{ "/device/ethernet", shill::kTypeEthernet, "ethernet",
"112233445566", "", "",
em::NetworkInterface::TYPE_ETHERNET },
{ "/device/cellular1", shill::kTypeCellular, "cellular1",
"abcdefabcdef", "A10000009296F2", "",
em::NetworkInterface::TYPE_CELLULAR },
{ "/device/cellular2", shill::kTypeCellular, "cellular2",
"abcdefabcdef", "", "352099001761481",
em::NetworkInterface::TYPE_CELLULAR },
{ "/device/wifi", shill::kTypeWifi, "wifi",
"aabbccddeeff", "", "",
em::NetworkInterface::TYPE_WIFI },
{ "/device/bluetooth", shill::kTypeBluetooth, "bluetooth",
"", "", "",
em::NetworkInterface::TYPE_BLUETOOTH },
{ "/device/vpn", shill::kTypeVPN, "vpn",
"", "", "",
-1 },
};
class DeviceStatusCollectorNetworkInterfacesTest
: public DeviceStatusCollectorTest {
protected:
virtual void SetUp() OVERRIDE {
chromeos::DBusThreadManager::InitializeWithStub();
chromeos::NetworkHandler::Initialize();
chromeos::ShillDeviceClient::TestInterface* test_device_client =
chromeos::DBusThreadManager::Get()->GetShillDeviceClient()->
GetTestInterface();
test_device_client->ClearDevices();
for (size_t i = 0; i < arraysize(kFakeDevices); ++i) {
const FakeDeviceData& dev = kFakeDevices[i];
test_device_client->AddDevice(dev.device_path, dev.type,
dev.object_path);
if (*dev.mac_address) {
test_device_client->SetDeviceProperty(
dev.device_path, shill::kAddressProperty,
base::StringValue(dev.mac_address));
}
if (*dev.meid) {
test_device_client->SetDeviceProperty(
dev.device_path, shill::kMeidProperty,
base::StringValue(dev.meid));
}
if (*dev.imei) {
test_device_client->SetDeviceProperty(
dev.device_path, shill::kImeiProperty,
base::StringValue(dev.imei));
}
}
// Flush out pending state updates.
base::RunLoop().RunUntilIdle();
}
virtual void TearDown() OVERRIDE {
chromeos::NetworkHandler::Shutdown();
chromeos::DBusThreadManager::Shutdown();
}
};
TEST_F(DeviceStatusCollectorNetworkInterfacesTest, NetworkInterfaces) {
// No interfaces should be reported if the policy is off.
GetStatus();
EXPECT_EQ(0, status_.network_interface_size());
// Switch the policy on and verify the interface list is present.
cros_settings_->SetBoolean(chromeos::kReportDeviceNetworkInterfaces, true);
GetStatus();
int count = 0;
for (size_t i = 0; i < arraysize(kFakeDevices); ++i) {
const FakeDeviceData& dev = kFakeDevices[i];
if (dev.expected_type == -1)
continue;
// Find the corresponding entry in reporting data.
bool found_match = false;
google::protobuf::RepeatedPtrField<em::NetworkInterface>::const_iterator
iface;
for (iface = status_.network_interface().begin();
iface != status_.network_interface().end();
++iface) {
// Check whether type, field presence and field values match.
if (dev.expected_type == iface->type() &&
iface->has_mac_address() == !!*dev.mac_address &&
iface->has_meid() == !!*dev.meid &&
iface->has_imei() == !!*dev.imei &&
iface->mac_address() == dev.mac_address &&
iface->meid() == dev.meid &&
iface->imei() == dev.imei) {
found_match = true;
break;
}
}
EXPECT_TRUE(found_match) << "No matching interface for fake device " << i;
count++;
}
EXPECT_EQ(count, status_.network_interface_size());
}
} // namespace policy