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