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