network_configuration_handler_unittest.cc revision a36e5920737c6adbddd3e43b760e5de8431db6e0
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 "base/bind.h" 6#include "base/json/json_writer.h" 7#include "base/message_loop/message_loop.h" 8#include "base/strings/string_piece.h" 9#include "base/values.h" 10#include "chromeos/dbus/dbus_thread_manager.h" 11#include "chromeos/dbus/mock_dbus_thread_manager.h" 12#include "chromeos/dbus/mock_shill_manager_client.h" 13#include "chromeos/dbus/mock_shill_profile_client.h" 14#include "chromeos/dbus/mock_shill_service_client.h" 15#include "chromeos/network/network_configuration_handler.h" 16#include "chromeos/network/network_state.h" 17#include "chromeos/network/network_state_handler.h" 18#include "chromeos/network/network_state_handler_observer.h" 19#include "testing/gmock/include/gmock/gmock.h" 20#include "testing/gtest/include/gtest/gtest.h" 21#include "third_party/cros_system_api/dbus/service_constants.h" 22 23using ::testing::_; 24using ::testing::Invoke; 25using ::testing::Pointee; 26using ::testing::Return; 27using ::testing::SaveArg; 28using ::testing::StrEq; 29 30// Matcher to match base::Value. 31MATCHER_P(IsEqualTo, value, "") { return arg.Equals(value); } 32 33namespace chromeos { 34 35namespace { 36 37static std::string PrettyJson(const base::DictionaryValue& value) { 38 std::string pretty; 39 base::JSONWriter::WriteWithOptions(&value, 40 base::JSONWriter::OPTIONS_PRETTY_PRINT, 41 &pretty); 42 return pretty; 43} 44 45void DictionaryValueCallback( 46 const std::string& expected_id, 47 const std::string& expected_json, 48 const std::string& service_path, 49 const base::DictionaryValue& dictionary) { 50 std::string dict_str = PrettyJson(dictionary); 51 EXPECT_EQ(expected_json, dict_str); 52 EXPECT_EQ(expected_id, service_path); 53} 54 55void ErrorCallback(bool error_expected, 56 const std::string& expected_id, 57 const std::string& error_name, 58 scoped_ptr<base::DictionaryValue> error_data) { 59 EXPECT_TRUE(error_expected) << "Unexpected error: " << error_name 60 << " with associated data: \n" 61 << PrettyJson(*error_data); 62} 63 64void StringResultCallback(const std::string& expected_result, 65 const std::string& result) { 66 EXPECT_EQ(expected_result, result); 67} 68 69void DBusErrorCallback(const std::string& error_name, 70 const std::string& error_message) { 71 EXPECT_TRUE(false) << "DBus Error: " << error_name << "(" 72 << error_message << ")"; 73} 74 75class TestCallback { 76 public: 77 TestCallback() : run_count_(0) {} 78 void Run() { 79 ++run_count_; 80 } 81 int run_count() const { return run_count_; } 82 83 private: 84 int run_count_; 85}; 86 87} // namespace 88 89class NetworkConfigurationHandlerTest : public testing::Test { 90 public: 91 NetworkConfigurationHandlerTest() 92 : mock_manager_client_(NULL), 93 mock_profile_client_(NULL), 94 mock_service_client_(NULL), 95 dictionary_value_result_(NULL) {} 96 virtual ~NetworkConfigurationHandlerTest() {} 97 98 virtual void SetUp() OVERRIDE { 99 MockDBusThreadManager* mock_dbus_thread_manager = new MockDBusThreadManager; 100 EXPECT_CALL(*mock_dbus_thread_manager, GetSystemBus()) 101 .WillRepeatedly(Return(reinterpret_cast<dbus::Bus*>(NULL))); 102 DBusThreadManager::InitializeForTesting(mock_dbus_thread_manager); 103 mock_manager_client_ = 104 mock_dbus_thread_manager->mock_shill_manager_client(); 105 mock_profile_client_ = 106 mock_dbus_thread_manager->mock_shill_profile_client(); 107 mock_service_client_ = 108 mock_dbus_thread_manager->mock_shill_service_client(); 109 110 network_state_handler_.reset(NetworkStateHandler::InitializeForTest()); 111 network_configuration_handler_.reset(new NetworkConfigurationHandler()); 112 network_configuration_handler_->Init(network_state_handler_.get()); 113 message_loop_.RunUntilIdle(); 114 } 115 116 virtual void TearDown() OVERRIDE { 117 network_configuration_handler_.reset(); 118 network_state_handler_.reset(); 119 DBusThreadManager::Shutdown(); 120 } 121 122 // Handles responses for GetProperties method calls. 123 void OnGetProperties( 124 const dbus::ObjectPath& path, 125 const ShillClientHelper::DictionaryValueCallback& callback) { 126 callback.Run(DBUS_METHOD_CALL_SUCCESS, *dictionary_value_result_); 127 } 128 129 // Handles responses for SetProperties method calls. 130 void OnSetProperties(const dbus::ObjectPath& service_path, 131 const base::DictionaryValue& properties, 132 const base::Closure& callback, 133 const ShillClientHelper::ErrorCallback& error_callback) { 134 callback.Run(); 135 } 136 137 // Handles responses for ClearProperties method calls. 138 void OnClearProperties( 139 const dbus::ObjectPath& service_path, 140 const std::vector<std::string>& names, 141 const ShillClientHelper::ListValueCallback& callback, 142 const ShillClientHelper::ErrorCallback& error_callback) { 143 base::ListValue result; 144 result.AppendBoolean(true); 145 callback.Run(result); 146 } 147 148 // Handles responses for ClearProperties method calls, and simulates an error 149 // result. 150 void OnClearPropertiesError( 151 const dbus::ObjectPath& service_path, 152 const std::vector<std::string>& names, 153 const ShillClientHelper::ListValueCallback& callback, 154 const ShillClientHelper::ErrorCallback& error_callback) { 155 base::ListValue result; 156 result.AppendBoolean(false); 157 callback.Run(result); 158 } 159 160 void OnConfigureService(const base::DictionaryValue& properties, 161 const ObjectPathCallback& callback, 162 const ShillClientHelper::ErrorCallback& error_callback) { 163 callback.Run(dbus::ObjectPath("/service/2")); 164 } 165 166 void OnGetLoadableProfileEntries( 167 const dbus::ObjectPath& service_path, 168 const ShillClientHelper::DictionaryValueCallback& callback) { 169 base::DictionaryValue entries; 170 entries.SetString("profile1", "entry1"); 171 entries.SetString("profile2", "entry2"); 172 callback.Run(DBUS_METHOD_CALL_SUCCESS, entries); 173 } 174 175 void OnDeleteEntry(const dbus::ObjectPath& profile_path, 176 const std::string& entry_path, 177 const base::Closure& callback, 178 const ShillClientHelper::ErrorCallback& error_callback) { 179 // Don't run the callback immediately to emulate actual behavior. 180 message_loop_.PostTask(FROM_HERE, callback); 181 } 182 183 bool PendingProfileEntryDeleterForTest(const std::string& service_path) { 184 return network_configuration_handler_-> 185 PendingProfileEntryDeleterForTest(service_path); 186 } 187 188 protected: 189 MockShillManagerClient* mock_manager_client_; 190 MockShillProfileClient* mock_profile_client_; 191 MockShillServiceClient* mock_service_client_; 192 scoped_ptr<NetworkStateHandler> network_state_handler_; 193 scoped_ptr<NetworkConfigurationHandler> network_configuration_handler_; 194 base::MessageLoopForUI message_loop_; 195 base::DictionaryValue* dictionary_value_result_; 196}; 197 198TEST_F(NetworkConfigurationHandlerTest, GetProperties) { 199 std::string service_path = "/service/1"; 200 std::string expected_json = "{\n \"SSID\": \"MyNetwork\"\n}\n"; 201 std::string networkName = "MyNetwork"; 202 std::string key = "SSID"; 203 scoped_ptr<base::StringValue> networkNameValue( 204 base::Value::CreateStringValue(networkName)); 205 206 base::DictionaryValue value; 207 value.Set(key, base::Value::CreateStringValue(networkName)); 208 dictionary_value_result_ = &value; 209 EXPECT_CALL(*mock_service_client_, 210 SetProperty(dbus::ObjectPath(service_path), key, 211 IsEqualTo(networkNameValue.get()), _, _)).Times(1); 212 DBusThreadManager::Get()->GetShillServiceClient()->SetProperty( 213 dbus::ObjectPath(service_path), key, *networkNameValue, 214 base::Bind(&base::DoNothing), 215 base::Bind(&DBusErrorCallback)); 216 message_loop_.RunUntilIdle(); 217 218 ShillServiceClient::DictionaryValueCallback get_properties_callback; 219 EXPECT_CALL(*mock_service_client_, 220 GetProperties(_, _)).WillOnce( 221 Invoke(this, 222 &NetworkConfigurationHandlerTest::OnGetProperties)); 223 network_configuration_handler_->GetProperties( 224 service_path, 225 base::Bind(&DictionaryValueCallback, 226 service_path, 227 expected_json), 228 base::Bind(&ErrorCallback, false, service_path)); 229 message_loop_.RunUntilIdle(); 230} 231 232TEST_F(NetworkConfigurationHandlerTest, SetProperties) { 233 std::string service_path = "/service/1"; 234 std::string networkName = "MyNetwork"; 235 std::string key = "SSID"; 236 scoped_ptr<base::StringValue> networkNameValue( 237 base::Value::CreateStringValue(networkName)); 238 239 base::DictionaryValue value; 240 value.Set(key, base::Value::CreateStringValue(networkName)); 241 dictionary_value_result_ = &value; 242 EXPECT_CALL(*mock_service_client_, 243 SetProperties(_, _, _, _)).WillOnce( 244 Invoke(this, 245 &NetworkConfigurationHandlerTest::OnSetProperties)); 246 network_configuration_handler_->SetProperties( 247 service_path, 248 value, 249 base::Bind(&base::DoNothing), 250 base::Bind(&ErrorCallback, false, service_path)); 251 message_loop_.RunUntilIdle(); 252} 253 254TEST_F(NetworkConfigurationHandlerTest, ClearProperties) { 255 std::string service_path = "/service/1"; 256 std::string networkName = "MyNetwork"; 257 std::string key = "SSID"; 258 scoped_ptr<base::StringValue> networkNameValue( 259 base::Value::CreateStringValue(networkName)); 260 261 // First set up a value to clear. 262 base::DictionaryValue value; 263 value.Set(key, base::Value::CreateStringValue(networkName)); 264 dictionary_value_result_ = &value; 265 EXPECT_CALL(*mock_service_client_, 266 SetProperties(_, _, _, _)).WillOnce( 267 Invoke(this, 268 &NetworkConfigurationHandlerTest::OnSetProperties)); 269 network_configuration_handler_->SetProperties( 270 service_path, 271 value, 272 base::Bind(&base::DoNothing), 273 base::Bind(&ErrorCallback, false, service_path)); 274 message_loop_.RunUntilIdle(); 275 276 // Now clear it. 277 std::vector<std::string> values_to_clear; 278 values_to_clear.push_back(key); 279 EXPECT_CALL(*mock_service_client_, 280 ClearProperties(_, _, _, _)).WillOnce( 281 Invoke(this, 282 &NetworkConfigurationHandlerTest::OnClearProperties)); 283 network_configuration_handler_->ClearProperties( 284 service_path, 285 values_to_clear, 286 base::Bind(&base::DoNothing), 287 base::Bind(&ErrorCallback, false, service_path)); 288 message_loop_.RunUntilIdle(); 289} 290 291TEST_F(NetworkConfigurationHandlerTest, ClearPropertiesError) { 292 std::string service_path = "/service/1"; 293 std::string networkName = "MyNetwork"; 294 std::string key = "SSID"; 295 scoped_ptr<base::StringValue> networkNameValue( 296 base::Value::CreateStringValue(networkName)); 297 298 // First set up a value to clear. 299 base::DictionaryValue value; 300 value.Set(key, base::Value::CreateStringValue(networkName)); 301 dictionary_value_result_ = &value; 302 EXPECT_CALL(*mock_service_client_, 303 SetProperties(_, _, _, _)).WillOnce( 304 Invoke(this, 305 &NetworkConfigurationHandlerTest::OnSetProperties)); 306 network_configuration_handler_->SetProperties( 307 service_path, 308 value, 309 base::Bind(&base::DoNothing), 310 base::Bind(&ErrorCallback, false, service_path)); 311 message_loop_.RunUntilIdle(); 312 313 // Now clear it. 314 std::vector<std::string> values_to_clear; 315 values_to_clear.push_back(key); 316 EXPECT_CALL( 317 *mock_service_client_, 318 ClearProperties(_, _, _, _)).WillOnce( 319 Invoke(this, 320 &NetworkConfigurationHandlerTest::OnClearPropertiesError)); 321 network_configuration_handler_->ClearProperties( 322 service_path, 323 values_to_clear, 324 base::Bind(&base::DoNothing), 325 base::Bind(&ErrorCallback, true, service_path)); 326 message_loop_.RunUntilIdle(); 327} 328 329TEST_F(NetworkConfigurationHandlerTest, CreateConfiguration) { 330 std::string expected_json = "{\n \"SSID\": \"MyNetwork\"\n}\n"; 331 std::string networkName = "MyNetwork"; 332 std::string key = "SSID"; 333 scoped_ptr<base::StringValue> networkNameValue( 334 base::Value::CreateStringValue(networkName)); 335 base::DictionaryValue value; 336 value.Set(key, base::Value::CreateStringValue(networkName)); 337 338 EXPECT_CALL( 339 *mock_manager_client_, 340 ConfigureService(_, _, _)).WillOnce( 341 Invoke(this, 342 &NetworkConfigurationHandlerTest::OnConfigureService)); 343 network_configuration_handler_->CreateConfiguration( 344 value, 345 base::Bind(&StringResultCallback, std::string("/service/2")), 346 base::Bind(&ErrorCallback, false, std::string(""))); 347 message_loop_.RunUntilIdle(); 348} 349 350TEST_F(NetworkConfigurationHandlerTest, RemoveConfiguration) { 351 std::string service_path = "/service/1"; 352 353 TestCallback test_callback; 354 EXPECT_CALL( 355 *mock_service_client_, 356 GetLoadableProfileEntries(_, _)).WillOnce(Invoke( 357 this, 358 &NetworkConfigurationHandlerTest::OnGetLoadableProfileEntries)); 359 EXPECT_CALL( 360 *mock_profile_client_, 361 DeleteEntry(_, _, _, _)).WillRepeatedly(Invoke( 362 this, 363 &NetworkConfigurationHandlerTest::OnDeleteEntry)); 364 365 network_configuration_handler_->RemoveConfiguration( 366 service_path, 367 base::Bind(&TestCallback::Run, base::Unretained(&test_callback)), 368 base::Bind(&ErrorCallback, false, service_path)); 369 message_loop_.RunUntilIdle(); 370 EXPECT_EQ(1, test_callback.run_count()); 371 EXPECT_FALSE(PendingProfileEntryDeleterForTest(service_path)); 372} 373 374//////////////////////////////////////////////////////////////////////////////// 375// Stub based tests 376 377namespace { 378 379class TestObserver : public chromeos::NetworkStateHandlerObserver { 380 public: 381 TestObserver() : network_list_changed_count_(0) {} 382 virtual ~TestObserver() {} 383 384 virtual void NetworkListChanged() OVERRIDE { 385 ++network_list_changed_count_; 386 } 387 388 virtual void NetworkPropertiesUpdated(const NetworkState* network) OVERRIDE { 389 property_updates_[network->path()]++; 390 } 391 392 size_t network_list_changed_count() { return network_list_changed_count_; } 393 394 int PropertyUpdatesForService(const std::string& service_path) { 395 return property_updates_[service_path]; 396 } 397 398 void ClearPropertyUpdates() { 399 property_updates_.clear(); 400 } 401 402 private: 403 size_t network_list_changed_count_; 404 std::map<std::string, int> property_updates_; 405 406 DISALLOW_COPY_AND_ASSIGN(TestObserver); 407}; 408 409} 410 411class NetworkConfigurationHandlerStubTest : public testing::Test { 412 public: 413 NetworkConfigurationHandlerStubTest() { 414 } 415 416 virtual ~NetworkConfigurationHandlerStubTest() { 417 } 418 419 virtual void SetUp() OVERRIDE { 420 DBusThreadManager::InitializeWithStub(); 421 422 network_state_handler_.reset(NetworkStateHandler::InitializeForTest()); 423 test_observer_.reset(new TestObserver()); 424 network_state_handler_->AddObserver(test_observer_.get(), FROM_HERE); 425 426 network_configuration_handler_.reset(new NetworkConfigurationHandler()); 427 network_configuration_handler_->Init(network_state_handler_.get()); 428 429 message_loop_.RunUntilIdle(); 430 test_observer_->ClearPropertyUpdates(); 431 } 432 433 virtual void TearDown() OVERRIDE { 434 network_configuration_handler_.reset(); 435 network_state_handler_->RemoveObserver(test_observer_.get(), FROM_HERE); 436 network_state_handler_.reset(); 437 DBusThreadManager::Shutdown(); 438 } 439 440 void SuccessCallback(const std::string& callback_name) { 441 success_callback_name_ = callback_name; 442 } 443 444 void GetPropertiesCallback(const std::string& service_path, 445 const base::DictionaryValue& dictionary) { 446 get_properties_path_ = service_path; 447 get_properties_.reset(dictionary.DeepCopy()); 448 } 449 450 protected: 451 bool GetServiceStringProperty(const std::string& service_path, 452 const std::string& key, 453 std::string* result) { 454 ShillServiceClient::TestInterface* service_test = 455 DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface(); 456 const base::DictionaryValue* properties = 457 service_test->GetServiceProperties(service_path); 458 if (properties && properties->GetStringWithoutPathExpansion(key, result)) 459 return true; 460 return false; 461 } 462 463 bool GetReceivedStringProperty(const std::string& service_path, 464 const std::string& key, 465 std::string* result) { 466 if (get_properties_path_ != service_path) 467 return false; 468 if (get_properties_ && 469 get_properties_->GetStringWithoutPathExpansion(key, result)) 470 return true; 471 return false; 472 } 473 474 scoped_ptr<NetworkStateHandler> network_state_handler_; 475 scoped_ptr<NetworkConfigurationHandler> network_configuration_handler_; 476 scoped_ptr<TestObserver> test_observer_; 477 base::MessageLoopForUI message_loop_; 478 std::string success_callback_name_; 479 std::string get_properties_path_; 480 scoped_ptr<DictionaryValue> get_properties_; 481}; 482 483TEST_F(NetworkConfigurationHandlerStubTest, StubSetAndClearProperties) { 484 // TODO(stevenjb): Remove dependency on default Stub service. 485 const std::string service_path("wifi1"); 486 const std::string test_identity("test_identity"); 487 const std::string test_passphrase("test_passphrase"); 488 489 // Set Properties 490 base::DictionaryValue properties_to_set; 491 properties_to_set.SetStringWithoutPathExpansion( 492 flimflam::kIdentityProperty, test_identity); 493 properties_to_set.SetStringWithoutPathExpansion( 494 flimflam::kPassphraseProperty, test_passphrase); 495 network_configuration_handler_->SetProperties( 496 service_path, 497 properties_to_set, 498 base::Bind( 499 &NetworkConfigurationHandlerStubTest::SuccessCallback, 500 base::Unretained(this), "SetProperties"), 501 base::Bind(&ErrorCallback, false, service_path)); 502 message_loop_.RunUntilIdle(); 503 504 EXPECT_EQ("SetProperties", success_callback_name_); 505 std::string identity, passphrase; 506 EXPECT_TRUE(GetServiceStringProperty( 507 service_path, flimflam::kIdentityProperty, &identity)); 508 EXPECT_TRUE(GetServiceStringProperty( 509 service_path, flimflam::kPassphraseProperty, &passphrase)); 510 EXPECT_EQ(test_identity, identity); 511 EXPECT_EQ(test_passphrase, passphrase); 512 EXPECT_EQ(1, test_observer_->PropertyUpdatesForService(service_path)); 513 514 // Clear Properties 515 std::vector<std::string> properties_to_clear; 516 properties_to_clear.push_back(flimflam::kIdentityProperty); 517 properties_to_clear.push_back(flimflam::kPassphraseProperty); 518 network_configuration_handler_->ClearProperties( 519 service_path, 520 properties_to_clear, 521 base::Bind( 522 &NetworkConfigurationHandlerStubTest::SuccessCallback, 523 base::Unretained(this), "ClearProperties"), 524 base::Bind(&ErrorCallback, false, service_path)); 525 message_loop_.RunUntilIdle(); 526 527 EXPECT_EQ("ClearProperties", success_callback_name_); 528 EXPECT_FALSE(GetServiceStringProperty( 529 service_path, flimflam::kIdentityProperty, &identity)); 530 EXPECT_FALSE(GetServiceStringProperty( 531 service_path, flimflam::kIdentityProperty, &passphrase)); 532 EXPECT_EQ(2, test_observer_->PropertyUpdatesForService(service_path)); 533} 534 535TEST_F(NetworkConfigurationHandlerStubTest, StubGetNameFromWifiHex) { 536 // TODO(stevenjb): Remove dependency on default Stub service. 537 const std::string service_path("wifi1"); 538 std::string wifi_hex = "5468697320697320484558205353494421"; 539 std::string expected_name = "This is HEX SSID!"; 540 541 // Set Properties 542 base::DictionaryValue properties_to_set; 543 properties_to_set.SetStringWithoutPathExpansion( 544 flimflam::kWifiHexSsid, wifi_hex); 545 network_configuration_handler_->SetProperties( 546 service_path, 547 properties_to_set, 548 base::Bind(&base::DoNothing), 549 base::Bind(&ErrorCallback, false, service_path)); 550 message_loop_.RunUntilIdle(); 551 std::string wifi_hex_result; 552 EXPECT_TRUE(GetServiceStringProperty( 553 service_path, flimflam::kWifiHexSsid, &wifi_hex_result)); 554 EXPECT_EQ(wifi_hex, wifi_hex_result); 555 556 // Get Properties 557 network_configuration_handler_->GetProperties( 558 service_path, 559 base::Bind(&NetworkConfigurationHandlerStubTest::GetPropertiesCallback, 560 base::Unretained(this)), 561 base::Bind(&ErrorCallback, false, service_path)); 562 message_loop_.RunUntilIdle(); 563 564 EXPECT_EQ(service_path, get_properties_path_); 565 std::string name_result; 566 EXPECT_TRUE(GetReceivedStringProperty( 567 service_path, flimflam::kNameProperty, &name_result)); 568 EXPECT_EQ(expected_name, name_result); 569} 570 571} // namespace chromeos 572