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::InitializeWithStub();
    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, id, type, state, true /* visible */);
    220   }
    221 
    222   void AddServiceWithIPConfig(const std::string& type,
    223                               const std::string& id,
    224                               const std::string& state,
    225                               const std::string& ipconfig_path) {
    226     ASSERT_TRUE(IsValidType(type));
    227     service_test_->AddServiceWithIPConfig(id, /* service_path */
    228                                           "" /* guid */,
    229                                           id /* name */,
    230                                           type,
    231                                           state,
    232                                           ipconfig_path,
    233                                           true /* visible */);
    234   }
    235 
    236   void AddServiceToProfile(const std::string& type,
    237                            const std::string& id,
    238                            bool visible) {
    239     service_test_->AddService(id, id, type, shill::kStateIdle, visible);
    240     std::vector<std::string> profiles;
    241     profile_test_->GetProfilePaths(&profiles);
    242     ASSERT_TRUE(profiles.size() > 0);
    243     base::DictionaryValue properties;  // Empty entry
    244     profile_test_->AddService(profiles[0], id);
    245   }
    246 
    247   void RemoveService(const std::string& id) {
    248     service_test_->RemoveService(id);
    249   }
    250 
    251   // Call this after any initial Shill client setup
    252   void SetupShillPropertyHandler() {
    253     SetupDefaultShillState();
    254     listener_.reset(new TestListener);
    255     shill_property_handler_.reset(
    256         new internal::ShillPropertyHandler(listener_.get()));
    257     shill_property_handler_->Init();
    258   }
    259 
    260   bool IsValidType(const std::string& type) {
    261     return (type == shill::kTypeEthernet ||
    262             type == shill::kTypeEthernetEap ||
    263             type == shill::kTypeWifi ||
    264             type == shill::kTypeWimax ||
    265             type == shill::kTypeBluetooth ||
    266             type == shill::kTypeCellular ||
    267             type == shill::kTypeVPN);
    268   }
    269 
    270  protected:
    271   void SetupDefaultShillState() {
    272     message_loop_.RunUntilIdle();  // Process any pending updates
    273     device_test_->ClearDevices();
    274     AddDevice(shill::kTypeWifi, "stub_wifi_device1");
    275     AddDevice(shill::kTypeCellular, "stub_cellular_device1");
    276     service_test_->ClearServices();
    277     AddService(shill::kTypeEthernet, "stub_ethernet", shill::kStateOnline);
    278     AddService(shill::kTypeWifi, "stub_wifi1", shill::kStateOnline);
    279     AddService(shill::kTypeWifi, "stub_wifi2", shill::kStateIdle);
    280     AddService(shill::kTypeCellular, "stub_cellular1", shill::kStateIdle);
    281   }
    282 
    283   base::MessageLoopForUI message_loop_;
    284   scoped_ptr<TestListener> listener_;
    285   scoped_ptr<internal::ShillPropertyHandler> shill_property_handler_;
    286   ShillManagerClient::TestInterface* manager_test_;
    287   ShillDeviceClient::TestInterface* device_test_;
    288   ShillServiceClient::TestInterface* service_test_;
    289   ShillProfileClient::TestInterface* profile_test_;
    290 
    291  private:
    292   DISALLOW_COPY_AND_ASSIGN(ShillPropertyHandlerTest);
    293 };
    294 
    295 TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerStub) {
    296   EXPECT_TRUE(shill_property_handler_->IsTechnologyAvailable(shill::kTypeWifi));
    297   EXPECT_TRUE(shill_property_handler_->IsTechnologyEnabled(shill::kTypeWifi));
    298   const size_t kNumShillManagerClientStubImplDevices = 2;
    299   EXPECT_EQ(kNumShillManagerClientStubImplDevices,
    300             listener_->entries(shill::kDevicesProperty).size());
    301   const size_t kNumShillManagerClientStubImplServices = 4;
    302   EXPECT_EQ(kNumShillManagerClientStubImplServices,
    303             listener_->entries(shill::kServiceCompleteListProperty).size());
    304 
    305   EXPECT_EQ(0, listener_->errors());
    306 }
    307 
    308 TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerTechnologyChanged) {
    309   const int initial_technology_updates = 2;  // Available and Enabled lists
    310   EXPECT_EQ(initial_technology_updates, listener_->technology_list_updates());
    311 
    312   // Remove an enabled technology. Updates both the Available and Enabled lists.
    313   listener_->reset_list_updates();
    314   manager_test_->RemoveTechnology(shill::kTypeWifi);
    315   message_loop_.RunUntilIdle();
    316   EXPECT_EQ(2, listener_->technology_list_updates());
    317 
    318   // Add a disabled technology.
    319   listener_->reset_list_updates();
    320   manager_test_->AddTechnology(shill::kTypeWifi, false);
    321   message_loop_.RunUntilIdle();
    322   EXPECT_EQ(1, listener_->technology_list_updates());
    323   EXPECT_TRUE(shill_property_handler_->IsTechnologyAvailable(
    324       shill::kTypeWifi));
    325   EXPECT_FALSE(shill_property_handler_->IsTechnologyEnabled(shill::kTypeWifi));
    326 
    327   // Enable the technology.
    328   listener_->reset_list_updates();
    329   DBusThreadManager::Get()->GetShillManagerClient()->EnableTechnology(
    330       shill::kTypeWifi,
    331       base::Bind(&base::DoNothing), base::Bind(&ErrorCallbackFunction));
    332   message_loop_.RunUntilIdle();
    333   EXPECT_EQ(1, listener_->technology_list_updates());
    334   EXPECT_TRUE(shill_property_handler_->IsTechnologyEnabled(shill::kTypeWifi));
    335 
    336   EXPECT_EQ(0, listener_->errors());
    337 }
    338 
    339 TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerDevicePropertyChanged) {
    340   const size_t kNumShillManagerClientStubImplDevices = 2;
    341   EXPECT_EQ(kNumShillManagerClientStubImplDevices,
    342             listener_->entries(shill::kDevicesProperty).size());
    343   // Add a device.
    344   listener_->reset_list_updates();
    345   const std::string kTestDevicePath("test_wifi_device1");
    346   AddDevice(shill::kTypeWifi, kTestDevicePath);
    347   message_loop_.RunUntilIdle();
    348   EXPECT_EQ(1, listener_->list_updates(shill::kDevicesProperty));
    349   EXPECT_EQ(kNumShillManagerClientStubImplDevices + 1,
    350             listener_->entries(shill::kDevicesProperty).size());
    351 
    352   // Remove a device
    353   listener_->reset_list_updates();
    354   RemoveDevice(kTestDevicePath);
    355   message_loop_.RunUntilIdle();
    356   EXPECT_EQ(1, listener_->list_updates(shill::kDevicesProperty));
    357   EXPECT_EQ(kNumShillManagerClientStubImplDevices,
    358             listener_->entries(shill::kDevicesProperty).size());
    359 
    360   EXPECT_EQ(0, listener_->errors());
    361 }
    362 
    363 TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerServicePropertyChanged) {
    364   const size_t kNumShillManagerClientStubImplServices = 4;
    365   EXPECT_EQ(kNumShillManagerClientStubImplServices,
    366             listener_->entries(shill::kServiceCompleteListProperty).size());
    367 
    368   // Add a service.
    369   listener_->reset_list_updates();
    370   const std::string kTestServicePath("test_wifi_service1");
    371   AddService(shill::kTypeWifi, kTestServicePath, shill::kStateIdle);
    372   message_loop_.RunUntilIdle();
    373   // Add should trigger a service list update and update entries.
    374   EXPECT_EQ(1, listener_->list_updates(shill::kServiceCompleteListProperty));
    375   EXPECT_EQ(kNumShillManagerClientStubImplServices + 1,
    376             listener_->entries(shill::kServiceCompleteListProperty).size());
    377   // Service receives an initial property update.
    378   EXPECT_EQ(1, listener_->initial_property_updates(
    379       shill::kServiceCompleteListProperty)[kTestServicePath]);
    380   // Change a property.
    381   base::FundamentalValue scan_interval(3);
    382   DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
    383       dbus::ObjectPath(kTestServicePath),
    384       shill::kScanIntervalProperty,
    385       scan_interval,
    386       base::Bind(&base::DoNothing), base::Bind(&ErrorCallbackFunction));
    387   message_loop_.RunUntilIdle();
    388   // Property change triggers an update (but not a service list update).
    389   EXPECT_EQ(1, listener_->property_updates(
    390       shill::kServiceCompleteListProperty)[kTestServicePath]);
    391 
    392   // Change the visibility of a service. This will trigger a service list
    393   // updates.
    394   listener_->reset_list_updates();
    395   DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
    396       dbus::ObjectPath(kTestServicePath),
    397       shill::kVisibleProperty,
    398       base::FundamentalValue(false),
    399       base::Bind(&base::DoNothing), base::Bind(&ErrorCallbackFunction));
    400   message_loop_.RunUntilIdle();
    401   EXPECT_EQ(1, listener_->list_updates(shill::kServiceCompleteListProperty));
    402 
    403   // Remove a service. This will update the entries and signal a service list
    404   // update.
    405   listener_->reset_list_updates();
    406   RemoveService(kTestServicePath);
    407   message_loop_.RunUntilIdle();
    408   EXPECT_EQ(1, listener_->list_updates(shill::kServiceCompleteListProperty));
    409   EXPECT_EQ(kNumShillManagerClientStubImplServices,
    410             listener_->entries(shill::kServiceCompleteListProperty).size());
    411 
    412   EXPECT_EQ(0, listener_->errors());
    413 }
    414 
    415 TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerIPConfigPropertyChanged) {
    416   // Set the properties for an IP Config object.
    417   const std::string kTestIPConfigPath("test_ip_config_path");
    418 
    419   base::StringValue ip_address("192.168.1.1");
    420   DBusThreadManager::Get()->GetShillIPConfigClient()->SetProperty(
    421       dbus::ObjectPath(kTestIPConfigPath),
    422       shill::kAddressProperty, ip_address,
    423       base::Bind(&DoNothingWithCallStatus));
    424   base::ListValue dns_servers;
    425   dns_servers.Append(base::Value::CreateStringValue("192.168.1.100"));
    426   dns_servers.Append(base::Value::CreateStringValue("192.168.1.101"));
    427   DBusThreadManager::Get()->GetShillIPConfigClient()->SetProperty(
    428       dbus::ObjectPath(kTestIPConfigPath),
    429       shill::kNameServersProperty, dns_servers,
    430       base::Bind(&DoNothingWithCallStatus));
    431   base::FundamentalValue prefixlen(8);
    432   DBusThreadManager::Get()->GetShillIPConfigClient()->SetProperty(
    433       dbus::ObjectPath(kTestIPConfigPath),
    434       shill::kPrefixlenProperty, prefixlen,
    435       base::Bind(&DoNothingWithCallStatus));
    436   base::StringValue gateway("192.0.0.1");
    437   DBusThreadManager::Get()->GetShillIPConfigClient()->SetProperty(
    438       dbus::ObjectPath(kTestIPConfigPath),
    439       shill::kGatewayProperty, gateway,
    440       base::Bind(&DoNothingWithCallStatus));
    441   message_loop_.RunUntilIdle();
    442 
    443   // Add a service with an empty ipconfig and then update
    444   // its ipconfig property.
    445   const std::string kTestServicePath1("test_wifi_service1");
    446   AddService(shill::kTypeWifi, kTestServicePath1, shill::kStateIdle);
    447   message_loop_.RunUntilIdle();
    448   // This is the initial property update.
    449   EXPECT_EQ(1, listener_->initial_property_updates(
    450       shill::kServiceCompleteListProperty)[kTestServicePath1]);
    451   DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
    452       dbus::ObjectPath(kTestServicePath1),
    453       shill::kIPConfigProperty,
    454       base::StringValue(kTestIPConfigPath),
    455       base::Bind(&base::DoNothing), base::Bind(&ErrorCallbackFunction));
    456   message_loop_.RunUntilIdle();
    457   // IPConfig property change on the service should trigger an IPConfigs update.
    458   EXPECT_EQ(1, listener_->property_updates(
    459       shill::kIPConfigsProperty)[kTestIPConfigPath]);
    460 
    461   // Now, Add a new service with the IPConfig already set.
    462   const std::string kTestServicePath2("test_wifi_service2");
    463   AddServiceWithIPConfig(shill::kTypeWifi, kTestServicePath2,
    464                          shill::kStateIdle, kTestIPConfigPath);
    465   message_loop_.RunUntilIdle();
    466   // A service with the IPConfig property already set should trigger an
    467   // additional IPConfigs update.
    468   EXPECT_EQ(2, listener_->property_updates(
    469       shill::kIPConfigsProperty)[kTestIPConfigPath]);
    470 }
    471 
    472 TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerServiceList) {
    473   // Add an entry to the profile only.
    474   const std::string kTestServicePath1("stub_wifi_profile_only1");
    475   AddServiceToProfile(shill::kTypeWifi, kTestServicePath1, false /* visible */);
    476   message_loop_.RunUntilIdle();
    477 
    478   // Update the Manager properties. This should trigger a single list update,
    479   // an initial property update, and a regular property update.
    480   listener_->reset_list_updates();
    481   shill_property_handler_->UpdateManagerProperties();
    482   message_loop_.RunUntilIdle();
    483   EXPECT_EQ(1, listener_->list_updates(shill::kServiceCompleteListProperty));
    484   EXPECT_EQ(1, listener_->initial_property_updates(
    485       shill::kServiceCompleteListProperty)[kTestServicePath1]);
    486   EXPECT_EQ(1, listener_->property_updates(
    487       shill::kServiceCompleteListProperty)[kTestServicePath1]);
    488 
    489   // Add a new entry to the services and the profile; should also trigger a
    490   // service list update, and a property update.
    491   listener_->reset_list_updates();
    492   const std::string kTestServicePath2("stub_wifi_profile_only2");
    493   AddServiceToProfile(shill::kTypeWifi, kTestServicePath2, true);
    494   shill_property_handler_->UpdateManagerProperties();
    495   message_loop_.RunUntilIdle();
    496   EXPECT_EQ(1, listener_->list_updates(shill::kServiceCompleteListProperty));
    497   EXPECT_EQ(1, listener_->initial_property_updates(
    498       shill::kServiceCompleteListProperty)[kTestServicePath2]);
    499   EXPECT_EQ(1, listener_->property_updates(
    500       shill::kServiceCompleteListProperty)[kTestServicePath2]);
    501 }
    502 
    503 }  // namespace chromeos
    504