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