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