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