Home | History | Annotate | Download | only in network
      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 "chromeos/network/shill_property_handler.h"
      6 
      7 #include <map>
      8 #include <set>
      9 #include <string>
     10 
     11 #include "base/bind.h"
     12 #include "base/memory/scoped_ptr.h"
     13 #include "base/message_loop/message_loop.h"
     14 #include "base/values.h"
     15 #include "chromeos/dbus/dbus_thread_manager.h"
     16 #include "chromeos/dbus/shill_device_client.h"
     17 #include "chromeos/dbus/shill_ipconfig_client.h"
     18 #include "chromeos/dbus/shill_manager_client.h"
     19 #include "chromeos/dbus/shill_profile_client.h"
     20 #include "chromeos/dbus/shill_service_client.h"
     21 #include "dbus/object_path.h"
     22 #include "testing/gtest/include/gtest/gtest.h"
     23 #include "third_party/cros_system_api/dbus/service_constants.h"
     24 
     25 namespace chromeos {
     26 
     27 namespace {
     28 
     29 void DoNothingWithCallStatus(DBusMethodCallStatus call_status) {
     30 }
     31 
     32 void ErrorCallbackFunction(const std::string& error_name,
     33                            const std::string& error_message) {
     34   LOG(ERROR) << "Shill Error: " << error_name << " : " << error_message;
     35 }
     36 
     37 class TestListener : public internal::ShillPropertyHandler::Listener {
     38  public:
     39   TestListener() : technology_list_updates_(0),
     40                    errors_(0) {
     41   }
     42 
     43   virtual void UpdateManagedList(ManagedState::ManagedType type,
     44                                  const base::ListValue& entries) OVERRIDE {
     45     UpdateEntries(GetTypeString(type), entries);
     46   }
     47 
     48   virtual void UpdateManagedStateProperties(
     49       ManagedState::ManagedType type,
     50       const std::string& path,
     51       const base::DictionaryValue& properties) OVERRIDE {
     52     AddInitialPropertyUpdate(GetTypeString(type), path);
     53   }
     54 
     55   virtual void ProfileListChanged() OVERRIDE {
     56   }
     57 
     58   virtual void UpdateNetworkServiceProperty(
     59       const std::string& service_path,
     60       const std::string& key,
     61       const base::Value& value) OVERRIDE {
     62     AddPropertyUpdate(shill::kServicesProperty, service_path);
     63   }
     64 
     65   virtual void UpdateDeviceProperty(
     66       const std::string& device_path,
     67       const std::string& key,
     68       const base::Value& value) OVERRIDE {
     69     AddPropertyUpdate(shill::kDevicesProperty, device_path);
     70   }
     71 
     72   virtual void TechnologyListChanged() OVERRIDE {
     73     ++technology_list_updates_;
     74   }
     75 
     76   virtual void CheckPortalListChanged(
     77       const std::string& check_portal_list) OVERRIDE {
     78   }
     79 
     80   virtual void ManagedStateListChanged(
     81       ManagedState::ManagedType type) OVERRIDE {
     82     AddStateListUpdate(GetTypeString(type));
     83   }
     84 
     85   std::vector<std::string>& entries(const std::string& type) {
     86     return entries_[type];
     87   }
     88   std::map<std::string, int>& property_updates(const std::string& type) {
     89     return property_updates_[type];
     90   }
     91   std::map<std::string, int>& initial_property_updates(
     92       const std::string& type) {
     93     return initial_property_updates_[type];
     94   }
     95   int list_updates(const std::string& type) { return list_updates_[type]; }
     96   int technology_list_updates() { return technology_list_updates_; }
     97   int errors() { return errors_; }
     98 
     99  private:
    100   std::string GetTypeString(ManagedState::ManagedType type) {
    101     if (type == ManagedState::MANAGED_TYPE_NETWORK) {
    102       return shill::kServicesProperty;
    103     } else if (type == ManagedState::MANAGED_TYPE_FAVORITE) {
    104       return shill::kServiceCompleteListProperty;
    105     } else if (type == ManagedState::MANAGED_TYPE_DEVICE) {
    106       return shill::kDevicesProperty;
    107     }
    108     LOG(ERROR) << "UpdateManagedList called with unrecognized type: " << type;
    109     ++errors_;
    110     return std::string();
    111   }
    112 
    113   void UpdateEntries(const std::string& type, const base::ListValue& entries) {
    114     if (type.empty())
    115       return;
    116     entries_[type].clear();
    117     for (base::ListValue::const_iterator iter = entries.begin();
    118          iter != entries.end(); ++iter) {
    119       std::string path;
    120       if ((*iter)->GetAsString(&path))
    121         entries_[type].push_back(path);
    122     }
    123   }
    124 
    125   void AddPropertyUpdate(const std::string& type, const std::string& path) {
    126     if (type.empty())
    127       return;
    128     property_updates(type)[path] += 1;
    129   }
    130 
    131   void AddInitialPropertyUpdate(const std::string& type,
    132                                 const std::string& path) {
    133     if (type.empty())
    134       return;
    135     initial_property_updates(type)[path] += 1;
    136   }
    137 
    138   void AddStateListUpdate(const std::string& type) {
    139     if (type.empty())
    140       return;
    141     list_updates_[type] += 1;
    142   }
    143 
    144   // Map of list-type -> paths
    145   std::map<std::string, std::vector<std::string> > entries_;
    146   // Map of list-type -> map of paths -> update counts
    147   std::map<std::string, std::map<std::string, int> > property_updates_;
    148   std::map<std::string, std::map<std::string, int> > initial_property_updates_;
    149   // Map of list-type -> list update counts
    150   std::map<std::string, int > list_updates_;
    151   int technology_list_updates_;
    152   int errors_;
    153 };
    154 
    155 }  // namespace
    156 
    157 class ShillPropertyHandlerTest : public testing::Test {
    158  public:
    159   ShillPropertyHandlerTest()
    160       : manager_test_(NULL),
    161         device_test_(NULL),
    162         service_test_(NULL),
    163         profile_test_(NULL) {
    164   }
    165   virtual ~ShillPropertyHandlerTest() {
    166   }
    167 
    168   virtual void SetUp() OVERRIDE {
    169     // Initialize DBusThreadManager with a stub implementation.
    170     DBusThreadManager::InitializeWithStub();
    171     // Get the test interface for manager / device / service and clear the
    172     // default stub properties.
    173     manager_test_ =
    174         DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface();
    175     ASSERT_TRUE(manager_test_);
    176     device_test_ =
    177         DBusThreadManager::Get()->GetShillDeviceClient()->GetTestInterface();
    178     ASSERT_TRUE(device_test_);
    179     service_test_ =
    180         DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
    181     ASSERT_TRUE(service_test_);
    182     profile_test_ =
    183         DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface();
    184     ASSERT_TRUE(profile_test_);
    185     SetupShillPropertyHandler();
    186     message_loop_.RunUntilIdle();
    187   }
    188 
    189   virtual void TearDown() OVERRIDE {
    190     shill_property_handler_.reset();
    191     listener_.reset();
    192     DBusThreadManager::Shutdown();
    193   }
    194 
    195   void AddDevice(const std::string& type, const std::string& id) {
    196     ASSERT_TRUE(IsValidType(type));
    197     device_test_->AddDevice(id, type, std::string("/device/" + id));
    198   }
    199 
    200   void RemoveDevice(const std::string& id) {
    201     device_test_->RemoveDevice(id);
    202   }
    203 
    204   void AddService(const std::string& type,
    205                   const std::string& id,
    206                   const std::string& state,
    207                   bool add_to_watch_list) {
    208     ASSERT_TRUE(IsValidType(type));
    209     service_test_->AddService(id, id, type, state,
    210                               true /* visible */, add_to_watch_list);
    211   }
    212 
    213   void AddServiceWithIPConfig(const std::string& type,
    214                               const std::string& id,
    215                               const std::string& state,
    216                               const std::string& ipconfig_path,
    217                               bool add_to_watch_list) {
    218     ASSERT_TRUE(IsValidType(type));
    219     service_test_->AddServiceWithIPConfig(id, id, type, state,
    220                                           ipconfig_path,
    221                                           true /* visible */,
    222                                           add_to_watch_list);
    223   }
    224 
    225   void AddServiceToProfile(const std::string& type,
    226                            const std::string& id,
    227                            bool visible) {
    228     service_test_->AddService(id, id, type, shill::kStateIdle,
    229                               visible, false /* watch */);
    230     std::vector<std::string> profiles;
    231     profile_test_->GetProfilePaths(&profiles);
    232     ASSERT_TRUE(profiles.size() > 0);
    233     base::DictionaryValue properties;  // Empty entry
    234     profile_test_->AddService(profiles[0], id);
    235   }
    236 
    237   void RemoveService(const std::string& id) {
    238     service_test_->RemoveService(id);
    239   }
    240 
    241   // Call this after any initial Shill client setup
    242   void SetupShillPropertyHandler() {
    243     SetupDefaultShillState();
    244     listener_.reset(new TestListener);
    245     shill_property_handler_.reset(
    246         new internal::ShillPropertyHandler(listener_.get()));
    247     shill_property_handler_->Init();
    248   }
    249 
    250   bool IsValidType(const std::string& type) {
    251     return (type == shill::kTypeEthernet ||
    252             type == shill::kTypeEthernetEap ||
    253             type == shill::kTypeWifi ||
    254             type == shill::kTypeWimax ||
    255             type == shill::kTypeBluetooth ||
    256             type == shill::kTypeCellular ||
    257             type == shill::kTypeVPN);
    258   }
    259 
    260  protected:
    261   void SetupDefaultShillState() {
    262     message_loop_.RunUntilIdle();  // Process any pending updates
    263     device_test_->ClearDevices();
    264     AddDevice(shill::kTypeWifi, "stub_wifi_device1");
    265     AddDevice(shill::kTypeCellular, "stub_cellular_device1");
    266     service_test_->ClearServices();
    267     const bool add_to_watchlist = true;
    268     AddService(shill::kTypeEthernet, "stub_ethernet",
    269                shill::kStateOnline, add_to_watchlist);
    270     AddService(shill::kTypeWifi, "stub_wifi1",
    271                shill::kStateOnline, add_to_watchlist);
    272     AddService(shill::kTypeWifi, "stub_wifi2",
    273                shill::kStateIdle, add_to_watchlist);
    274     AddService(shill::kTypeCellular, "stub_cellular1",
    275                shill::kStateIdle, add_to_watchlist);
    276   }
    277 
    278   base::MessageLoopForUI message_loop_;
    279   scoped_ptr<TestListener> listener_;
    280   scoped_ptr<internal::ShillPropertyHandler> shill_property_handler_;
    281   ShillManagerClient::TestInterface* manager_test_;
    282   ShillDeviceClient::TestInterface* device_test_;
    283   ShillServiceClient::TestInterface* service_test_;
    284   ShillProfileClient::TestInterface* profile_test_;
    285 
    286  private:
    287   DISALLOW_COPY_AND_ASSIGN(ShillPropertyHandlerTest);
    288 };
    289 
    290 TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerStub) {
    291   EXPECT_TRUE(shill_property_handler_->IsTechnologyAvailable(shill::kTypeWifi));
    292   EXPECT_TRUE(shill_property_handler_->IsTechnologyEnabled(shill::kTypeWifi));
    293   const size_t kNumShillManagerClientStubImplDevices = 2;
    294   EXPECT_EQ(kNumShillManagerClientStubImplDevices,
    295             listener_->entries(shill::kDevicesProperty).size());
    296   const size_t kNumShillManagerClientStubImplServices = 4;
    297   EXPECT_EQ(kNumShillManagerClientStubImplServices,
    298             listener_->entries(shill::kServicesProperty).size());
    299 
    300   EXPECT_EQ(0, listener_->errors());
    301 }
    302 
    303 TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerTechnologyChanged) {
    304   const int initial_technology_updates = 2;  // Available and Enabled lists
    305   EXPECT_EQ(initial_technology_updates, listener_->technology_list_updates());
    306 
    307   // Remove a technology. Updates both the Available and Enabled lists.
    308   manager_test_->RemoveTechnology(shill::kTypeWimax);
    309   message_loop_.RunUntilIdle();
    310   EXPECT_EQ(initial_technology_updates + 2,
    311             listener_->technology_list_updates());
    312 
    313   // Add a disabled technology.
    314   manager_test_->AddTechnology(shill::kTypeWimax, false);
    315   message_loop_.RunUntilIdle();
    316   EXPECT_EQ(initial_technology_updates + 3,
    317             listener_->technology_list_updates());
    318   EXPECT_TRUE(shill_property_handler_->IsTechnologyAvailable(
    319       shill::kTypeWimax));
    320   EXPECT_FALSE(shill_property_handler_->IsTechnologyEnabled(shill::kTypeWimax));
    321 
    322   // Enable the technology.
    323   DBusThreadManager::Get()->GetShillManagerClient()->EnableTechnology(
    324       shill::kTypeWimax,
    325       base::Bind(&base::DoNothing), base::Bind(&ErrorCallbackFunction));
    326   message_loop_.RunUntilIdle();
    327   EXPECT_EQ(initial_technology_updates + 4,
    328             listener_->technology_list_updates());
    329   EXPECT_TRUE(shill_property_handler_->IsTechnologyEnabled(shill::kTypeWimax));
    330 
    331   EXPECT_EQ(0, listener_->errors());
    332 }
    333 
    334 TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerDevicePropertyChanged) {
    335   EXPECT_EQ(1, listener_->list_updates(shill::kDevicesProperty));
    336   const size_t kNumShillManagerClientStubImplDevices = 2;
    337   EXPECT_EQ(kNumShillManagerClientStubImplDevices,
    338             listener_->entries(shill::kDevicesProperty).size());
    339   // Add a device.
    340   const std::string kTestDevicePath("test_wifi_device1");
    341   AddDevice(shill::kTypeWifi, kTestDevicePath);
    342   message_loop_.RunUntilIdle();
    343   EXPECT_EQ(2, listener_->list_updates(shill::kDevicesProperty));
    344   EXPECT_EQ(kNumShillManagerClientStubImplDevices + 1,
    345             listener_->entries(shill::kDevicesProperty).size());
    346   // Device changes are not observed.
    347   // Remove a device
    348   RemoveDevice(kTestDevicePath);
    349   message_loop_.RunUntilIdle();
    350   EXPECT_EQ(3, listener_->list_updates(shill::kDevicesProperty));
    351   EXPECT_EQ(kNumShillManagerClientStubImplDevices,
    352             listener_->entries(shill::kDevicesProperty).size());
    353 
    354   EXPECT_EQ(0, listener_->errors());
    355 }
    356 
    357 TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerServicePropertyChanged) {
    358   EXPECT_EQ(1, listener_->list_updates(shill::kServicesProperty));
    359   const size_t kNumShillManagerClientStubImplServices = 4;
    360   EXPECT_EQ(kNumShillManagerClientStubImplServices,
    361             listener_->entries(shill::kServicesProperty).size());
    362 
    363   // Add an unwatched service.
    364   const std::string kTestServicePath("test_wifi_service1");
    365   AddService(shill::kTypeWifi, kTestServicePath, shill::kStateIdle, false);
    366   message_loop_.RunUntilIdle();
    367   // Watched and unwatched services trigger a service list update.
    368   EXPECT_EQ(2, listener_->list_updates(shill::kServicesProperty));
    369   EXPECT_EQ(kNumShillManagerClientStubImplServices + 1,
    370             listener_->entries(shill::kServicesProperty).size());
    371   // Service receives an initial property update.
    372   EXPECT_EQ(1, listener_->initial_property_updates(
    373       shill::kServicesProperty)[kTestServicePath]);
    374   // Change a property.
    375   base::FundamentalValue scan_interval(3);
    376   DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
    377       dbus::ObjectPath(kTestServicePath),
    378       shill::kScanIntervalProperty,
    379       scan_interval,
    380       base::Bind(&base::DoNothing), base::Bind(&ErrorCallbackFunction));
    381   message_loop_.RunUntilIdle();
    382   // Property change triggers an update.
    383   EXPECT_EQ(1, listener_->property_updates(
    384       shill::kServicesProperty)[kTestServicePath]);
    385 
    386   // Add the existing service to the watch list.
    387   AddService(shill::kTypeWifi, kTestServicePath, shill::kStateIdle, true);
    388   message_loop_.RunUntilIdle();
    389   // Service list update should be received when watch list changes.
    390   EXPECT_EQ(2, listener_->list_updates(shill::kServicesProperty));
    391   // Number of services shouldn't change.
    392   EXPECT_EQ(kNumShillManagerClientStubImplServices + 1,
    393             listener_->entries(shill::kServicesProperty).size());
    394 
    395   // Change a property.
    396   DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
    397       dbus::ObjectPath(kTestServicePath),
    398       shill::kScanIntervalProperty,
    399       scan_interval,
    400       base::Bind(&base::DoNothing), base::Bind(&ErrorCallbackFunction));
    401   message_loop_.RunUntilIdle();
    402   // Property change should trigger another update.
    403   EXPECT_EQ(2, listener_->property_updates(
    404       shill::kServicesProperty)[kTestServicePath]);
    405 
    406   // Remove a service
    407   RemoveService(kTestServicePath);
    408   message_loop_.RunUntilIdle();
    409   EXPECT_EQ(3, listener_->list_updates(shill::kServicesProperty));
    410   EXPECT_EQ(kNumShillManagerClientStubImplServices,
    411             listener_->entries(shill::kServicesProperty).size());
    412 
    413   EXPECT_EQ(0, listener_->errors());
    414 }
    415 
    416 TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerIPConfigPropertyChanged) {
    417   // Set the properties for an IP Config object.
    418   const std::string kTestIPConfigPath("test_ip_config_path");
    419 
    420   base::StringValue ip_address("192.168.1.1");
    421   DBusThreadManager::Get()->GetShillIPConfigClient()->SetProperty(
    422       dbus::ObjectPath(kTestIPConfigPath),
    423       shill::kAddressProperty, ip_address,
    424       base::Bind(&DoNothingWithCallStatus));
    425   base::ListValue dns_servers;
    426   dns_servers.Append(base::Value::CreateStringValue("192.168.1.100"));
    427   dns_servers.Append(base::Value::CreateStringValue("192.168.1.101"));
    428   DBusThreadManager::Get()->GetShillIPConfigClient()->SetProperty(
    429       dbus::ObjectPath(kTestIPConfigPath),
    430       shill::kNameServersProperty, dns_servers,
    431       base::Bind(&DoNothingWithCallStatus));
    432   base::FundamentalValue prefixlen(8);
    433   DBusThreadManager::Get()->GetShillIPConfigClient()->SetProperty(
    434       dbus::ObjectPath(kTestIPConfigPath),
    435       shill::kPrefixlenProperty, prefixlen,
    436       base::Bind(&DoNothingWithCallStatus));
    437   base::StringValue gateway("192.0.0.1");
    438   DBusThreadManager::Get()->GetShillIPConfigClient()->SetProperty(
    439       dbus::ObjectPath(kTestIPConfigPath),
    440       shill::kGatewayProperty, gateway,
    441       base::Bind(&DoNothingWithCallStatus));
    442   message_loop_.RunUntilIdle();
    443 
    444   // Add a service with an empty ipconfig and then update
    445   // its ipconfig property.
    446   const std::string kTestServicePath1("test_wifi_service1");
    447   AddService(shill::kTypeWifi, kTestServicePath1, shill::kStateIdle, true);
    448   message_loop_.RunUntilIdle();
    449   // This is the initial property update.
    450   EXPECT_EQ(1, listener_->initial_property_updates(
    451       shill::kServicesProperty)[kTestServicePath1]);
    452   DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
    453       dbus::ObjectPath(kTestServicePath1),
    454       shill::kIPConfigProperty,
    455       base::StringValue(kTestIPConfigPath),
    456       base::Bind(&base::DoNothing), base::Bind(&ErrorCallbackFunction));
    457   message_loop_.RunUntilIdle();
    458   // IPConfig property change on the service should trigger property updates for
    459   // IP Address, DNS, prefixlen, and gateway.
    460   EXPECT_EQ(4, listener_->property_updates(
    461       shill::kServicesProperty)[kTestServicePath1]);
    462 
    463   // Now, Add a new watched service with the IPConfig already set.
    464   const std::string kTestServicePath2("test_wifi_service2");
    465   AddServiceWithIPConfig(shill::kTypeWifi, kTestServicePath2,
    466                          shill::kStateIdle, kTestIPConfigPath, true);
    467   message_loop_.RunUntilIdle();
    468   // A watched service with the IPConfig property already set must trigger
    469   // property updates for IP Address, DNS, prefixlen, and gateway when added.
    470   EXPECT_EQ(4, listener_->property_updates(
    471       shill::kServicesProperty)[kTestServicePath2]);
    472 }
    473 
    474 TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerServiceCompleteList) {
    475   // Initial list updates.
    476   EXPECT_EQ(1, listener_->list_updates(shill::kServicesProperty));
    477   EXPECT_EQ(1, listener_->list_updates(shill::kServiceCompleteListProperty));
    478 
    479   // Add a new entry to the profile only; should trigger a single list update
    480   // for both Services and ServiceCompleteList, and a single property update
    481   // for ServiceCompleteList.
    482   const std::string kTestServicePath1("stub_wifi_profile_only1");
    483   AddServiceToProfile(shill::kTypeWifi, kTestServicePath1, false);
    484   shill_property_handler_->UpdateManagerProperties();
    485   message_loop_.RunUntilIdle();
    486   EXPECT_EQ(2, listener_->list_updates(shill::kServicesProperty));
    487   EXPECT_EQ(2, listener_->list_updates(shill::kServiceCompleteListProperty));
    488   EXPECT_EQ(0, listener_->initial_property_updates(
    489       shill::kServicesProperty)[kTestServicePath1]);
    490   EXPECT_EQ(1, listener_->initial_property_updates(
    491       shill::kServiceCompleteListProperty)[kTestServicePath1]);
    492   EXPECT_EQ(0, listener_->property_updates(
    493       shill::kServicesProperty)[kTestServicePath1]);
    494   EXPECT_EQ(0, listener_->property_updates(
    495       shill::kServiceCompleteListProperty)[kTestServicePath1]);
    496 
    497   // Add a new entry to the services and the profile; should also trigger a
    498   // single list update for both Services and ServiceCompleteList, and should
    499   // trigger tow property updates for Services (one when the Profile propety
    500   // changes, and one for the Request) and one ServiceCompleteList change for
    501   // the Request.
    502   const std::string kTestServicePath2("stub_wifi_profile_only2");
    503   AddServiceToProfile(shill::kTypeWifi, kTestServicePath2, true);
    504   shill_property_handler_->UpdateManagerProperties();
    505   message_loop_.RunUntilIdle();
    506   EXPECT_EQ(3, listener_->list_updates(shill::kServicesProperty));
    507   EXPECT_EQ(3, listener_->list_updates(shill::kServiceCompleteListProperty));
    508   EXPECT_EQ(1, listener_->initial_property_updates(
    509       shill::kServicesProperty)[kTestServicePath2]);
    510   EXPECT_EQ(1, listener_->initial_property_updates(
    511       shill::kServiceCompleteListProperty)[kTestServicePath2]);
    512   // Expect one property update for the Profile property of the Network.
    513   EXPECT_EQ(1, listener_->property_updates(
    514       shill::kServicesProperty)[kTestServicePath2]);
    515   EXPECT_EQ(0, listener_->property_updates(
    516       shill::kServiceCompleteListProperty)[kTestServicePath2]);
    517 
    518   // Change a property of a Network in a Profile.
    519   base::FundamentalValue scan_interval(3);
    520   DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
    521       dbus::ObjectPath(kTestServicePath2),
    522       shill::kScanIntervalProperty,
    523       scan_interval,
    524       base::Bind(&base::DoNothing), base::Bind(&ErrorCallbackFunction));
    525   message_loop_.RunUntilIdle();
    526   // Property change should trigger an update for the Network only; no
    527   // property updates pushed by Shill affect Favorites.
    528   EXPECT_EQ(2, listener_->property_updates(
    529       shill::kServicesProperty)[kTestServicePath2]);
    530   EXPECT_EQ(0, listener_->property_updates(
    531       shill::kServiceCompleteListProperty)[kTestServicePath2]);
    532 }
    533 
    534 }  // namespace chromeos
    535