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