shill_property_handler_unittest.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
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.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_service_client.h" 20#include "dbus/object_path.h" 21#include "testing/gtest/include/gtest/gtest.h" 22#include "third_party/cros_system_api/dbus/service_constants.h" 23 24namespace chromeos { 25 26namespace { 27 28void DoNothingWithCallStatus(DBusMethodCallStatus call_status) { 29} 30 31void ErrorCallbackFunction(const std::string& error_name, 32 const std::string& error_message) { 33 LOG(ERROR) << "Shill Error: " << error_name << " : " << error_message; 34} 35 36class TestListener : public internal::ShillPropertyHandler::Listener { 37 public: 38 TestListener() : manager_updates_(0), errors_(0) { 39 } 40 41 virtual void UpdateManagedList(ManagedState::ManagedType type, 42 const base::ListValue& entries) OVERRIDE { 43 UpdateEntries(GetTypeString(type), entries); 44 } 45 46 virtual void UpdateManagedStateProperties( 47 ManagedState::ManagedType type, 48 const std::string& path, 49 const base::DictionaryValue& properties) OVERRIDE { 50 AddPropertyUpdate(GetTypeString(type), path); 51 } 52 53 virtual void ProfileListChanged() OVERRIDE { 54 } 55 56 virtual void UpdateNetworkServiceProperty( 57 const std::string& service_path, 58 const std::string& key, 59 const base::Value& value) OVERRIDE { 60 AddPropertyUpdate(flimflam::kServicesProperty, service_path); 61 } 62 63 virtual void UpdateDeviceProperty( 64 const std::string& device_path, 65 const std::string& key, 66 const base::Value& value) OVERRIDE { 67 AddPropertyUpdate(flimflam::kDevicesProperty, device_path); 68 } 69 70 virtual void NotifyManagerPropertyChanged() OVERRIDE { 71 ++manager_updates_; 72 } 73 74 virtual void ManagedStateListChanged( 75 ManagedState::ManagedType type) OVERRIDE { 76 AddStateListUpdate(GetTypeString(type)); 77 } 78 79 std::vector<std::string>& entries(const std::string& type) { 80 return entries_[type]; 81 } 82 std::map<std::string, int>& property_updates(const std::string& type) { 83 return property_updates_[type]; 84 } 85 int list_updates(const std::string& type) { return list_updates_[type]; } 86 int manager_updates() { return manager_updates_; } 87 int errors() { return errors_; } 88 89 private: 90 std::string GetTypeString(ManagedState::ManagedType type) { 91 if (type == ManagedState::MANAGED_TYPE_NETWORK) { 92 return flimflam::kServicesProperty; 93 } else if (type == ManagedState::MANAGED_TYPE_DEVICE) { 94 return flimflam::kDevicesProperty; 95 } 96 LOG(ERROR) << "UpdateManagedList called with unrecognized type: " << type; 97 ++errors_; 98 return std::string(); 99 } 100 101 void UpdateEntries(const std::string& type, const base::ListValue& entries) { 102 if (type.empty()) 103 return; 104 entries_[type].clear(); 105 for (base::ListValue::const_iterator iter = entries.begin(); 106 iter != entries.end(); ++iter) { 107 std::string path; 108 if ((*iter)->GetAsString(&path)) 109 entries_[type].push_back(path); 110 } 111 } 112 113 void AddPropertyUpdate(const std::string& type, const std::string& path) { 114 if (type.empty()) 115 return; 116 property_updates(type)[path] += 1; 117 } 118 119 void AddStateListUpdate(const std::string& type) { 120 if (type.empty()) 121 return; 122 list_updates_[type] += 1; 123 } 124 125 // Map of list-type -> paths 126 std::map<std::string, std::vector<std::string> > entries_; 127 // Map of list-type -> map of paths -> update counts 128 std::map<std::string, std::map<std::string, int> > property_updates_; 129 // Map of list-type -> list update counts 130 std::map<std::string, int > list_updates_; 131 int manager_updates_; 132 int errors_; 133}; 134 135} // namespace 136 137class ShillPropertyHandlerTest : public testing::Test { 138 public: 139 ShillPropertyHandlerTest() 140 : manager_test_(NULL), 141 device_test_(NULL), 142 service_test_(NULL) { 143 } 144 virtual ~ShillPropertyHandlerTest() { 145 } 146 147 virtual void SetUp() OVERRIDE { 148 // Initialize DBusThreadManager with a stub implementation. 149 DBusThreadManager::InitializeWithStub(); 150 // Get the test interface for manager / device / service and clear the 151 // default stub properties. 152 manager_test_ = 153 DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface(); 154 ASSERT_TRUE(manager_test_); 155 device_test_ = 156 DBusThreadManager::Get()->GetShillDeviceClient()->GetTestInterface(); 157 ASSERT_TRUE(device_test_); 158 service_test_ = 159 DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface(); 160 ASSERT_TRUE(service_test_); 161 SetupShillPropertyHandler(); 162 message_loop_.RunUntilIdle(); 163 } 164 165 virtual void TearDown() OVERRIDE { 166 shill_property_handler_.reset(); 167 listener_.reset(); 168 DBusThreadManager::Shutdown(); 169 } 170 171 void AddDevice(const std::string& type, const std::string& id) { 172 ASSERT_TRUE(IsValidType(type)); 173 device_test_->AddDevice(id, type, std::string("/device/" + id)); 174 } 175 176 void RemoveDevice(const std::string& id) { 177 device_test_->RemoveDevice(id); 178 } 179 180 void AddService(const std::string& type, 181 const std::string& id, 182 const std::string& state, 183 bool add_to_watch_list) { 184 ASSERT_TRUE(IsValidType(type)); 185 service_test_->AddService(id, id, type, state, 186 add_to_watch_list); 187 } 188 189 void AddServiceWithIPConfig(const std::string& type, 190 const std::string& id, 191 const std::string& state, 192 const std::string& ipconfig_path, 193 bool add_to_watch_list) { 194 ASSERT_TRUE(IsValidType(type)); 195 service_test_->AddServiceWithIPConfig(id, id, type, state, 196 ipconfig_path, add_to_watch_list); 197 } 198 199 void RemoveService(const std::string& id) { 200 service_test_->RemoveService(id); 201 } 202 203 // Call this after any initial Shill client setup 204 void SetupShillPropertyHandler() { 205 SetupDefaultShillState(); 206 listener_.reset(new TestListener); 207 shill_property_handler_.reset( 208 new internal::ShillPropertyHandler(listener_.get())); 209 shill_property_handler_->Init(); 210 } 211 212 bool IsValidType(const std::string& type) { 213 return (type == flimflam::kTypeEthernet || 214 type == flimflam::kTypeWifi || 215 type == flimflam::kTypeWimax || 216 type == flimflam::kTypeBluetooth || 217 type == flimflam::kTypeCellular || 218 type == flimflam::kTypeVPN); 219 } 220 221 protected: 222 void SetupDefaultShillState() { 223 message_loop_.RunUntilIdle(); // Process any pending updates 224 device_test_->ClearDevices(); 225 AddDevice(flimflam::kTypeWifi, "stub_wifi_device1"); 226 AddDevice(flimflam::kTypeCellular, "stub_cellular_device1"); 227 service_test_->ClearServices(); 228 const bool add_to_watchlist = true; 229 AddService(flimflam::kTypeEthernet, "stub_ethernet", 230 flimflam::kStateOnline, add_to_watchlist); 231 AddService(flimflam::kTypeWifi, "stub_wifi1", 232 flimflam::kStateOnline, add_to_watchlist); 233 AddService(flimflam::kTypeWifi, "stub_wifi2", 234 flimflam::kStateIdle, add_to_watchlist); 235 AddService(flimflam::kTypeCellular, "stub_cellular1", 236 flimflam::kStateIdle, add_to_watchlist); 237 } 238 239 MessageLoopForUI message_loop_; 240 scoped_ptr<TestListener> listener_; 241 scoped_ptr<internal::ShillPropertyHandler> shill_property_handler_; 242 ShillManagerClient::TestInterface* manager_test_; 243 ShillDeviceClient::TestInterface* device_test_; 244 ShillServiceClient::TestInterface* service_test_; 245 246 private: 247 DISALLOW_COPY_AND_ASSIGN(ShillPropertyHandlerTest); 248}; 249 250TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerStub) { 251 EXPECT_EQ(1, listener_->manager_updates()); 252 EXPECT_TRUE(shill_property_handler_->IsTechnologyAvailable( 253 flimflam::kTypeWifi)); 254 EXPECT_TRUE(shill_property_handler_->IsTechnologyEnabled( 255 flimflam::kTypeWifi)); 256 const size_t kNumShillManagerClientStubImplDevices = 2; 257 EXPECT_EQ(kNumShillManagerClientStubImplDevices, 258 listener_->entries(flimflam::kDevicesProperty).size()); 259 const size_t kNumShillManagerClientStubImplServices = 4; 260 EXPECT_EQ(kNumShillManagerClientStubImplServices, 261 listener_->entries(flimflam::kServicesProperty).size()); 262 263 EXPECT_EQ(0, listener_->errors()); 264} 265 266TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerTechnologyChanged) { 267 EXPECT_EQ(1, listener_->manager_updates()); 268 // Add a disabled technology. 269 manager_test_->AddTechnology(flimflam::kTypeWimax, false); 270 message_loop_.RunUntilIdle(); 271 EXPECT_EQ(2, listener_->manager_updates()); 272 EXPECT_TRUE(shill_property_handler_->IsTechnologyAvailable( 273 flimflam::kTypeWimax)); 274 EXPECT_FALSE(shill_property_handler_->IsTechnologyEnabled( 275 flimflam::kTypeWimax)); 276 277 // Enable the technology. 278 DBusThreadManager::Get()->GetShillManagerClient()->EnableTechnology( 279 flimflam::kTypeWimax, 280 base::Bind(&base::DoNothing), base::Bind(&ErrorCallbackFunction)); 281 message_loop_.RunUntilIdle(); 282 EXPECT_EQ(3, listener_->manager_updates()); 283 EXPECT_TRUE(shill_property_handler_->IsTechnologyEnabled( 284 flimflam::kTypeWimax)); 285 286 EXPECT_EQ(0, listener_->errors()); 287} 288 289TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerDevicePropertyChanged) { 290 EXPECT_EQ(1, listener_->manager_updates()); 291 EXPECT_EQ(1, listener_->list_updates(flimflam::kDevicesProperty)); 292 const size_t kNumShillManagerClientStubImplDevices = 2; 293 EXPECT_EQ(kNumShillManagerClientStubImplDevices, 294 listener_->entries(flimflam::kDevicesProperty).size()); 295 // Add a device. 296 const std::string kTestDevicePath("test_wifi_device1"); 297 AddDevice(flimflam::kTypeWifi, kTestDevicePath); 298 message_loop_.RunUntilIdle(); 299 EXPECT_EQ(1, listener_->manager_updates()); // No new manager updates. 300 EXPECT_EQ(2, listener_->list_updates(flimflam::kDevicesProperty)); 301 EXPECT_EQ(kNumShillManagerClientStubImplDevices + 1, 302 listener_->entries(flimflam::kDevicesProperty).size()); 303 // Device changes are not observed. 304 // Remove a device 305 RemoveDevice(kTestDevicePath); 306 message_loop_.RunUntilIdle(); 307 EXPECT_EQ(3, listener_->list_updates(flimflam::kDevicesProperty)); 308 EXPECT_EQ(kNumShillManagerClientStubImplDevices, 309 listener_->entries(flimflam::kDevicesProperty).size()); 310 311 EXPECT_EQ(0, listener_->errors()); 312} 313 314TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerServicePropertyChanged) { 315 EXPECT_EQ(1, listener_->manager_updates()); 316 EXPECT_EQ(1, listener_->list_updates(flimflam::kServicesProperty)); 317 const size_t kNumShillManagerClientStubImplServices = 4; 318 EXPECT_EQ(kNumShillManagerClientStubImplServices, 319 listener_->entries(flimflam::kServicesProperty).size()); 320 321 // Add an unwatched service. 322 const std::string kTestServicePath("test_wifi_service1"); 323 AddService(flimflam::kTypeWifi, kTestServicePath, 324 flimflam::kStateIdle, false); 325 message_loop_.RunUntilIdle(); 326 EXPECT_EQ(1, listener_->manager_updates()); // No new manager updates. 327 // Watched and unwatched services trigger a service list update. 328 EXPECT_EQ(2, listener_->list_updates(flimflam::kServicesProperty)); 329 EXPECT_EQ(kNumShillManagerClientStubImplServices + 1, 330 listener_->entries(flimflam::kServicesProperty).size()); 331 // Service receives an initial property update. 332 EXPECT_EQ(1, listener_-> 333 property_updates(flimflam::kServicesProperty)[kTestServicePath]); 334 // Change a property. 335 base::FundamentalValue scan_interval(3); 336 DBusThreadManager::Get()->GetShillServiceClient()->SetProperty( 337 dbus::ObjectPath(kTestServicePath), 338 flimflam::kScanIntervalProperty, 339 scan_interval, 340 base::Bind(&base::DoNothing), base::Bind(&ErrorCallbackFunction)); 341 message_loop_.RunUntilIdle(); 342 // Property change triggers an update. 343 EXPECT_EQ(2, listener_-> 344 property_updates(flimflam::kServicesProperty)[kTestServicePath]); 345 346 // Add the existing service to the watch list. 347 AddService(flimflam::kTypeWifi, kTestServicePath, 348 flimflam::kStateIdle, true); 349 message_loop_.RunUntilIdle(); 350 // Service list update should be received when watch list changes. 351 EXPECT_EQ(2, listener_->list_updates(flimflam::kServicesProperty)); 352 // Number of services shouldn't change. 353 EXPECT_EQ(kNumShillManagerClientStubImplServices + 1, 354 listener_->entries(flimflam::kServicesProperty).size()); 355 356 // Change a property. 357 DBusThreadManager::Get()->GetShillServiceClient()->SetProperty( 358 dbus::ObjectPath(kTestServicePath), 359 flimflam::kScanIntervalProperty, 360 scan_interval, 361 base::Bind(&base::DoNothing), base::Bind(&ErrorCallbackFunction)); 362 message_loop_.RunUntilIdle(); 363 // Property change should trigger another update. 364 EXPECT_EQ(3, listener_-> 365 property_updates(flimflam::kServicesProperty)[kTestServicePath]); 366 367 // Remove a service 368 RemoveService(kTestServicePath); 369 message_loop_.RunUntilIdle(); 370 EXPECT_EQ(3, listener_->list_updates(flimflam::kServicesProperty)); 371 EXPECT_EQ(kNumShillManagerClientStubImplServices, 372 listener_->entries(flimflam::kServicesProperty).size()); 373 374 EXPECT_EQ(0, listener_->errors()); 375} 376 377TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerIPConfigPropertyChanged) { 378 // Set the properties for an IP Config object. 379 const std::string kTestIPConfigPath("test_ip_config_path"); 380 base::StringValue ip_address("192.168.1.1"); 381 DBusThreadManager::Get()->GetShillIPConfigClient()->SetProperty( 382 dbus::ObjectPath(kTestIPConfigPath), 383 flimflam::kAddressProperty, 384 ip_address, 385 base::Bind(&DoNothingWithCallStatus)); 386 base::ListValue dns_servers; 387 dns_servers.Append(base::Value::CreateStringValue("192.168.1.100")); 388 dns_servers.Append(base::Value::CreateStringValue("192.168.1.101")); 389 DBusThreadManager::Get()->GetShillIPConfigClient()->SetProperty( 390 dbus::ObjectPath(kTestIPConfigPath), 391 flimflam::kNameServersProperty, 392 dns_servers, 393 base::Bind(&DoNothingWithCallStatus)); 394 message_loop_.RunUntilIdle(); 395 396 // Add a service with an empty ipconfig and then update 397 // its ipconfig property. 398 const std::string kTestServicePath1("test_wifi_service1"); 399 AddService(flimflam::kTypeWifi, kTestServicePath1, 400 flimflam::kStateIdle, true); 401 message_loop_.RunUntilIdle(); 402 // This is the initial property update. 403 EXPECT_EQ(1, listener_-> 404 property_updates(flimflam::kServicesProperty)[kTestServicePath1]); 405 DBusThreadManager::Get()->GetShillServiceClient()->SetProperty( 406 dbus::ObjectPath(kTestServicePath1), 407 shill::kIPConfigProperty, 408 base::StringValue(kTestIPConfigPath), 409 base::Bind(&base::DoNothing), base::Bind(&ErrorCallbackFunction)); 410 message_loop_.RunUntilIdle(); 411 // IPConfig property change on the service should trigger property updates for 412 // IP Address and DNS. 413 EXPECT_EQ(3, listener_-> 414 property_updates(flimflam::kServicesProperty)[kTestServicePath1]); 415 416 // Now, Add a new watched service with the IPConfig already set. 417 const std::string kTestServicePath2("test_wifi_service2"); 418 AddServiceWithIPConfig(flimflam::kTypeWifi, kTestServicePath2, 419 flimflam::kStateIdle, kTestIPConfigPath, true); 420 message_loop_.RunUntilIdle(); 421 // A watched service with the IPConfig property already set must 422 // trigger property updates for IP Address and DNS when added. 423 EXPECT_EQ(3, listener_-> 424 property_updates(flimflam::kServicesProperty)[kTestServicePath2]); 425} 426 427} // namespace chromeos 428