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