shill_property_handler_unittest.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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_manager_client.h" 18#include "chromeos/dbus/shill_service_client.h" 19#include "dbus/object_path.h" 20#include "testing/gtest/include/gtest/gtest.h" 21#include "third_party/cros_system_api/dbus/service_constants.h" 22 23namespace chromeos { 24 25namespace { 26 27void ErrorCallbackFunction(const std::string& error_name, 28 const std::string& error_message) { 29 LOG(ERROR) << "Shill Error: " << error_name << " : " << error_message; 30} 31 32class TestListener : public internal::ShillPropertyHandler::Listener { 33 public: 34 TestListener() : manager_updates_(0), errors_(0) { 35 } 36 37 virtual void UpdateManagedList(ManagedState::ManagedType type, 38 const base::ListValue& entries) OVERRIDE { 39 UpdateEntries(GetTypeString(type), entries); 40 } 41 42 virtual void UpdateManagedStateProperties( 43 ManagedState::ManagedType type, 44 const std::string& path, 45 const base::DictionaryValue& properties) OVERRIDE { 46 AddPropertyUpdate(GetTypeString(type), path); 47 } 48 49 virtual void UpdateNetworkServiceProperty( 50 const std::string& service_path, 51 const std::string& key, 52 const base::Value& value) OVERRIDE { 53 AddPropertyUpdate(flimflam::kServicesProperty, service_path); 54 } 55 56 virtual void UpdateDeviceProperty( 57 const std::string& device_path, 58 const std::string& key, 59 const base::Value& value) OVERRIDE { 60 AddPropertyUpdate(flimflam::kDevicesProperty, device_path); 61 } 62 63 virtual void ManagerPropertyChanged() OVERRIDE { 64 ++manager_updates_; 65 } 66 67 virtual void UpdateNetworkServiceIPAddress( 68 const std::string& service_path, 69 const std::string& ip_address) OVERRIDE { 70 AddPropertyUpdate(flimflam::kServicesProperty, service_path); 71 } 72 73 virtual void ManagedStateListChanged( 74 ManagedState::ManagedType type) OVERRIDE { 75 AddStateListUpdate(GetTypeString(type)); 76 } 77 78 std::vector<std::string>& entries(const std::string& type) { 79 return entries_[type]; 80 } 81 std::map<std::string, int>& property_updates(const std::string& type) { 82 return property_updates_[type]; 83 } 84 int list_updates(const std::string& type) { return list_updates_[type]; } 85 int manager_updates() { return manager_updates_; } 86 int errors() { return errors_; } 87 88 private: 89 std::string GetTypeString(ManagedState::ManagedType type) { 90 if (type == ManagedState::MANAGED_TYPE_NETWORK) { 91 return flimflam::kServicesProperty; 92 } else if (type == ManagedState::MANAGED_TYPE_DEVICE) { 93 return flimflam::kDevicesProperty; 94 } 95 LOG(ERROR) << "UpdateManagedList called with unrecognized type: " << type; 96 ++errors_; 97 return std::string(); 98 } 99 100 void UpdateEntries(const std::string& type, const base::ListValue& entries) { 101 if (type.empty()) 102 return; 103 entries_[type].clear(); 104 for (base::ListValue::const_iterator iter = entries.begin(); 105 iter != entries.end(); ++iter) { 106 std::string path; 107 if ((*iter)->GetAsString(&path)) 108 entries_[type].push_back(path); 109 } 110 } 111 112 void AddPropertyUpdate(const std::string& type, const std::string& path) { 113 if (type.empty()) 114 return; 115 property_updates(type)[path] += 1; 116 } 117 118 void AddStateListUpdate(const std::string& type) { 119 if (type.empty()) 120 return; 121 list_updates_[type] += 1; 122 } 123 124 // Map of list-type -> paths 125 std::map<std::string, std::vector<std::string> > entries_; 126 // Map of list-type -> map of paths -> update counts 127 std::map<std::string, std::map<std::string, int> > property_updates_; 128 // Map of list-type -> list update counts 129 std::map<std::string, int > list_updates_; 130 int manager_updates_; 131 int errors_; 132}; 133 134} // namespace 135 136class ShillPropertyHandlerTest : public testing::Test { 137 public: 138 ShillPropertyHandlerTest() 139 : manager_test_(NULL), 140 device_test_(NULL), 141 service_test_(NULL) { 142 } 143 virtual ~ShillPropertyHandlerTest() { 144 } 145 146 virtual void SetUp() OVERRIDE { 147 // Initialize DBusThreadManager with a stub implementation. 148 DBusThreadManager::InitializeWithStub(); 149 // Get the test interface for manager / device / service and clear the 150 // default stub properties. 151 manager_test_ = 152 DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface(); 153 ASSERT_TRUE(manager_test_); 154 device_test_ = 155 DBusThreadManager::Get()->GetShillDeviceClient()->GetTestInterface(); 156 ASSERT_TRUE(device_test_); 157 service_test_ = 158 DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface(); 159 ASSERT_TRUE(service_test_); 160 } 161 162 virtual void TearDown() OVERRIDE { 163 shill_property_handler_.reset(); 164 listener_.reset(); 165 DBusThreadManager::Shutdown(); 166 } 167 168 void AddDevice(const std::string& type, const std::string& id) { 169 ASSERT_TRUE(IsValidType(type)); 170 device_test_->AddDevice(id, type, std::string("/device/" + id)); 171 } 172 173 void RemoveDevice(const std::string& id) { 174 device_test_->RemoveDevice(id); 175 } 176 177 void AddService(const std::string& type, 178 const std::string& id, 179 const std::string& state, 180 bool add_to_watch_list) { 181 ASSERT_TRUE(IsValidType(type)); 182 service_test_->AddService(id, id, type, state, add_to_watch_list); 183 } 184 185 void RemoveService(const std::string& id) { 186 service_test_->RemoveService(id); 187 } 188 189 // Call this after any initial Shill client setup 190 void SetupShillPropertyHandler() { 191 SetupDefaultShillState(); 192 listener_.reset(new TestListener); 193 shill_property_handler_.reset( 194 new internal::ShillPropertyHandler(listener_.get())); 195 shill_property_handler_->Init(); 196 } 197 198 bool IsValidType(const std::string& type) { 199 return (type == flimflam::kTypeEthernet || 200 type == flimflam::kTypeWifi || 201 type == flimflam::kTypeWimax || 202 type == flimflam::kTypeBluetooth || 203 type == flimflam::kTypeCellular || 204 type == flimflam::kTypeVPN); 205 } 206 207 protected: 208 void SetupDefaultShillState() { 209 message_loop_.RunUntilIdle(); // Process any pending updates 210 device_test_->ClearDevices(); 211 AddDevice(flimflam::kTypeWifi, "stub_wifi_device1"); 212 AddDevice(flimflam::kTypeCellular, "stub_cellular_device1"); 213 service_test_->ClearServices(); 214 const bool add_to_watchlist = true; 215 AddService(flimflam::kTypeEthernet, "stub_ethernet", 216 flimflam::kStateOnline, add_to_watchlist); 217 AddService(flimflam::kTypeWifi, "stub_wifi1", 218 flimflam::kStateOnline, add_to_watchlist); 219 AddService(flimflam::kTypeWifi, "stub_wifi2", 220 flimflam::kStateIdle, add_to_watchlist); 221 AddService(flimflam::kTypeCellular, "stub_cellular1", 222 flimflam::kStateIdle, add_to_watchlist); 223 } 224 225 MessageLoopForUI message_loop_; 226 scoped_ptr<TestListener> listener_; 227 scoped_ptr<internal::ShillPropertyHandler> shill_property_handler_; 228 ShillManagerClient::TestInterface* manager_test_; 229 ShillDeviceClient::TestInterface* device_test_; 230 ShillServiceClient::TestInterface* service_test_; 231 232 private: 233 DISALLOW_COPY_AND_ASSIGN(ShillPropertyHandlerTest); 234}; 235 236TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerStub) { 237 SetupShillPropertyHandler(); 238 message_loop_.RunUntilIdle(); 239 EXPECT_EQ(1, listener_->manager_updates()); 240 EXPECT_TRUE(shill_property_handler_->TechnologyAvailable( 241 flimflam::kTypeWifi)); 242 EXPECT_TRUE(shill_property_handler_->TechnologyEnabled( 243 flimflam::kTypeWifi)); 244 const size_t kNumShillManagerClientStubImplDevices = 2; 245 EXPECT_EQ(kNumShillManagerClientStubImplDevices, 246 listener_->entries(flimflam::kDevicesProperty).size()); 247 const size_t kNumShillManagerClientStubImplServices = 4; 248 EXPECT_EQ(kNumShillManagerClientStubImplServices, 249 listener_->entries(flimflam::kServicesProperty).size()); 250 251 EXPECT_EQ(0, listener_->errors()); 252} 253 254TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerTechnologyChanged) { 255 SetupShillPropertyHandler(); 256 message_loop_.RunUntilIdle(); 257 EXPECT_EQ(1, listener_->manager_updates()); 258 // Add a disabled technology. 259 manager_test_->AddTechnology(flimflam::kTypeWimax, false); 260 message_loop_.RunUntilIdle(); 261 EXPECT_EQ(2, listener_->manager_updates()); 262 EXPECT_TRUE(shill_property_handler_->TechnologyAvailable( 263 flimflam::kTypeWimax)); 264 EXPECT_FALSE(shill_property_handler_->TechnologyEnabled( 265 flimflam::kTypeWimax)); 266 267 // Enable the technology. 268 DBusThreadManager::Get()->GetShillManagerClient()->EnableTechnology( 269 flimflam::kTypeWimax, 270 base::Bind(&base::DoNothing), base::Bind(&ErrorCallbackFunction)); 271 message_loop_.RunUntilIdle(); 272 EXPECT_EQ(3, listener_->manager_updates()); 273 EXPECT_TRUE(shill_property_handler_->TechnologyEnabled( 274 flimflam::kTypeWimax)); 275 276 EXPECT_EQ(0, listener_->errors()); 277} 278 279TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerDevicePropertyChanged) { 280 SetupShillPropertyHandler(); 281 message_loop_.RunUntilIdle(); 282 EXPECT_EQ(1, listener_->manager_updates()); 283 EXPECT_EQ(1, listener_->list_updates(flimflam::kDevicesProperty)); 284 const size_t kNumShillManagerClientStubImplDevices = 2; 285 EXPECT_EQ(kNumShillManagerClientStubImplDevices, 286 listener_->entries(flimflam::kDevicesProperty).size()); 287 // Add a device. 288 const std::string kTestDevicePath("test_wifi_device1"); 289 AddDevice(flimflam::kTypeWifi, kTestDevicePath); 290 message_loop_.RunUntilIdle(); 291 EXPECT_EQ(1, listener_->manager_updates()); // No new manager updates. 292 EXPECT_EQ(2, listener_->list_updates(flimflam::kDevicesProperty)); 293 EXPECT_EQ(kNumShillManagerClientStubImplDevices + 1, 294 listener_->entries(flimflam::kDevicesProperty).size()); 295 // Device changes are not observed. 296 // Remove a device 297 RemoveDevice(kTestDevicePath); 298 message_loop_.RunUntilIdle(); 299 EXPECT_EQ(3, listener_->list_updates(flimflam::kDevicesProperty)); 300 EXPECT_EQ(kNumShillManagerClientStubImplDevices, 301 listener_->entries(flimflam::kDevicesProperty).size()); 302 303 EXPECT_EQ(0, listener_->errors()); 304} 305 306TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerServicePropertyChanged) { 307 SetupShillPropertyHandler(); 308 message_loop_.RunUntilIdle(); 309 EXPECT_EQ(1, listener_->manager_updates()); 310 EXPECT_EQ(1, listener_->list_updates(flimflam::kServicesProperty)); 311 const size_t kNumShillManagerClientStubImplServices = 4; 312 EXPECT_EQ(kNumShillManagerClientStubImplServices, 313 listener_->entries(flimflam::kServicesProperty).size()); 314 315 // Add an unwatched service. 316 const std::string kTestServicePath("test_wifi_service1"); 317 AddService(flimflam::kTypeWifi, kTestServicePath, 318 flimflam::kStateIdle, false); 319 message_loop_.RunUntilIdle(); 320 EXPECT_EQ(1, listener_->manager_updates()); // No new manager updates. 321 // Only watched services trigger a service list update. 322 EXPECT_EQ(1, listener_->list_updates(flimflam::kServicesProperty)); 323 EXPECT_EQ(kNumShillManagerClientStubImplServices + 1, 324 listener_->entries(flimflam::kServicesProperty).size()); 325 // Change a property. 326 base::FundamentalValue scan_interval(3); 327 DBusThreadManager::Get()->GetShillServiceClient()->SetProperty( 328 dbus::ObjectPath(kTestServicePath), 329 flimflam::kScanIntervalProperty, 330 scan_interval, 331 base::Bind(&base::DoNothing), base::Bind(&ErrorCallbackFunction)); 332 message_loop_.RunUntilIdle(); 333 // Property change should NOT trigger an update. 334 EXPECT_EQ(0, listener_-> 335 property_updates(flimflam::kServicesProperty)[kTestServicePath]); 336 337 // Add the existing service to the watch list. 338 AddService(flimflam::kTypeWifi, kTestServicePath, 339 flimflam::kStateIdle, true); 340 message_loop_.RunUntilIdle(); 341 // Service list update should be received when watch list changes. 342 EXPECT_EQ(2, listener_->list_updates(flimflam::kServicesProperty)); 343 // Number of services shouldn't change. 344 EXPECT_EQ(kNumShillManagerClientStubImplServices + 1, 345 listener_->entries(flimflam::kServicesProperty).size()); 346 // Property update should be received when watched service is added. 347 EXPECT_EQ(1, listener_-> 348 property_updates(flimflam::kServicesProperty)[kTestServicePath]); 349 350 // Change a property. 351 DBusThreadManager::Get()->GetShillServiceClient()->SetProperty( 352 dbus::ObjectPath(kTestServicePath), 353 flimflam::kScanIntervalProperty, 354 scan_interval, 355 base::Bind(&base::DoNothing), base::Bind(&ErrorCallbackFunction)); 356 message_loop_.RunUntilIdle(); 357 // Property change should trigger another update. 358 EXPECT_EQ(2, listener_-> 359 property_updates(flimflam::kServicesProperty)[kTestServicePath]); 360 361 // Remove a service 362 RemoveService(kTestServicePath); 363 message_loop_.RunUntilIdle(); 364 EXPECT_EQ(3, listener_->list_updates(flimflam::kServicesProperty)); 365 EXPECT_EQ(kNumShillManagerClientStubImplServices, 366 listener_->entries(flimflam::kServicesProperty).size()); 367 368 EXPECT_EQ(0, listener_->errors()); 369} 370 371// TODO(stevenjb): Test IP Configs. 372 373} // namespace chromeos 374