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