managed_network_configuration_handler_unittest.cc revision ca12bfac764ba476d6cd062bf1dde12cc64c3f40
1// Copyright (c) 2013 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/managed_network_configuration_handler.h" 6 7#include <iostream> 8#include <sstream> 9 10#include "base/message_loop/message_loop.h" 11#include "chromeos/dbus/dbus_thread_manager.h" 12#include "chromeos/dbus/mock_dbus_thread_manager.h" 13#include "chromeos/dbus/mock_shill_manager_client.h" 14#include "chromeos/dbus/mock_shill_profile_client.h" 15#include "chromeos/dbus/mock_shill_service_client.h" 16#include "chromeos/dbus/shill_profile_client_stub.h" 17#include "chromeos/network/network_configuration_handler.h" 18#include "chromeos/network/network_profile_handler.h" 19#include "chromeos/network/onc/onc_test_utils.h" 20#include "chromeos/network/onc/onc_utils.h" 21#include "dbus/object_path.h" 22#include "testing/gmock/include/gmock/gmock.h" 23#include "testing/gtest/include/gtest/gtest.h" 24#include "third_party/cros_system_api/dbus/service_constants.h" 25 26using ::testing::AnyNumber; 27using ::testing::Invoke; 28using ::testing::Mock; 29using ::testing::Pointee; 30using ::testing::Return; 31using ::testing::SaveArg; 32using ::testing::StrEq; 33using ::testing::StrictMock; 34using ::testing::_; 35 36namespace test_utils = ::chromeos::onc::test_utils; 37 38namespace chromeos { 39 40namespace { 41 42std::string ValueToString(const base::Value* value) { 43 std::stringstream str; 44 str << *value; 45 return str.str(); 46} 47 48const char kSharedProfilePath[] = "/profile/default"; 49const char kUser1[] = "user1"; 50const char kUser1ProfilePath[] = "/profile/user1/shill"; 51 52// Matcher to match base::Value. 53MATCHER_P(IsEqualTo, 54 value, 55 std::string(negation ? "isn't" : "is") + " equal to " + 56 ValueToString(value)) { 57 return value->Equals(&arg); 58} 59 60class ShillProfileTestClient { 61 public: 62 typedef ShillClientHelper::DictionaryValueCallbackWithoutStatus 63 DictionaryValueCallbackWithoutStatus; 64 typedef ShillClientHelper::ErrorCallback ErrorCallback; 65 66 void AddProfile(const std::string& profile_path, 67 const std::string& userhash) { 68 if (profile_entries_.HasKey(profile_path)) 69 return; 70 71 base::DictionaryValue* profile = new base::DictionaryValue; 72 profile_entries_.SetWithoutPathExpansion(profile_path, profile); 73 profile_to_user_[profile_path] = userhash; 74 } 75 76 void AddEntry(const std::string& profile_path, 77 const std::string& entry_path, 78 const base::DictionaryValue& entry) { 79 base::DictionaryValue* entries = NULL; 80 profile_entries_.GetDictionaryWithoutPathExpansion(profile_path, &entries); 81 ASSERT_TRUE(entries); 82 83 base::DictionaryValue* new_entry = entry.DeepCopy(); 84 new_entry->SetStringWithoutPathExpansion(flimflam::kProfileProperty, 85 profile_path); 86 entries->SetWithoutPathExpansion(entry_path, new_entry); 87 } 88 89 void GetProperties(const dbus::ObjectPath& profile_path, 90 const DictionaryValueCallbackWithoutStatus& callback, 91 const ErrorCallback& error_callback) { 92 base::DictionaryValue* entries = NULL; 93 profile_entries_.GetDictionaryWithoutPathExpansion(profile_path.value(), 94 &entries); 95 ASSERT_TRUE(entries); 96 97 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue); 98 base::ListValue* entry_paths = new base::ListValue; 99 result->SetWithoutPathExpansion(flimflam::kEntriesProperty, 100 entry_paths); 101 for (base::DictionaryValue::Iterator it(*entries); !it.IsAtEnd(); 102 it.Advance()) { 103 entry_paths->AppendString(it.key()); 104 } 105 106 ASSERT_GT(profile_to_user_.count(profile_path.value()), 0UL); 107 const std::string& userhash = profile_to_user_[profile_path.value()]; 108 result->SetStringWithoutPathExpansion(shill::kUserHashProperty, userhash); 109 110 callback.Run(*result); 111 } 112 113 void GetEntry(const dbus::ObjectPath& profile_path, 114 const std::string& entry_path, 115 const DictionaryValueCallbackWithoutStatus& callback, 116 const ErrorCallback& error_callback) { 117 base::DictionaryValue* entries = NULL; 118 profile_entries_.GetDictionaryWithoutPathExpansion(profile_path.value(), 119 &entries); 120 ASSERT_TRUE(entries); 121 122 base::DictionaryValue* entry = NULL; 123 entries->GetDictionaryWithoutPathExpansion(entry_path, &entry); 124 ASSERT_TRUE(entry); 125 callback.Run(*entry); 126 } 127 128 protected: 129 base::DictionaryValue profile_entries_; 130 std::map<std::string, std::string> profile_to_user_; 131}; 132 133class TestNetworkProfileHandler : public NetworkProfileHandler { 134 public: 135 TestNetworkProfileHandler() { 136 Init(NULL /* No NetworkStateHandler */); 137 } 138 virtual ~TestNetworkProfileHandler() {} 139 140 void AddProfileForTest(const NetworkProfile& profile) { 141 AddProfile(profile); 142 } 143 144 private: 145 DISALLOW_COPY_AND_ASSIGN(TestNetworkProfileHandler); 146}; 147 148} // namespace 149 150class ManagedNetworkConfigurationHandlerTest : public testing::Test { 151 public: 152 ManagedNetworkConfigurationHandlerTest() { 153 } 154 155 virtual ~ManagedNetworkConfigurationHandlerTest() { 156 } 157 158 virtual void SetUp() OVERRIDE { 159 MockDBusThreadManager* dbus_thread_manager = new MockDBusThreadManager; 160 EXPECT_CALL(*dbus_thread_manager, GetSystemBus()) 161 .WillRepeatedly(Return(static_cast<dbus::Bus*>(NULL))); 162 DBusThreadManager::InitializeForTesting(dbus_thread_manager); 163 164 SetNetworkConfigurationHandlerExpectations(); 165 166 EXPECT_CALL(*dbus_thread_manager, GetShillManagerClient()) 167 .WillRepeatedly(Return(&mock_manager_client_)); 168 EXPECT_CALL(*dbus_thread_manager, GetShillServiceClient()) 169 .WillRepeatedly(Return(&mock_service_client_)); 170 EXPECT_CALL(*dbus_thread_manager, GetShillProfileClient()) 171 .WillRepeatedly(Return(&mock_profile_client_)); 172 173 ON_CALL(mock_profile_client_, GetProperties(_,_,_)) 174 .WillByDefault(Invoke(&profiles_stub_, 175 &ShillProfileTestClient::GetProperties)); 176 177 ON_CALL(mock_profile_client_, GetEntry(_,_,_,_)) 178 .WillByDefault(Invoke(&profiles_stub_, 179 &ShillProfileTestClient::GetEntry)); 180 181 network_profile_handler_.reset(new TestNetworkProfileHandler()); 182 network_configuration_handler_.reset( 183 NetworkConfigurationHandler::InitializeForTest( 184 NULL /* no NetworkStateHandler */)); 185 managed_network_configuration_handler_.reset( 186 new ManagedNetworkConfigurationHandler()); 187 managed_network_configuration_handler_->Init( 188 NULL /* no NetworkStateHandler */, 189 network_profile_handler_.get(), 190 network_configuration_handler_.get()); 191 192 message_loop_.RunUntilIdle(); 193 } 194 195 virtual void TearDown() OVERRIDE { 196 managed_network_configuration_handler_.reset(); 197 network_configuration_handler_.reset(); 198 network_profile_handler_.reset(); 199 DBusThreadManager::Shutdown(); 200 } 201 202 void VerifyAndClearExpectations() { 203 Mock::VerifyAndClearExpectations(&mock_manager_client_); 204 Mock::VerifyAndClearExpectations(&mock_service_client_); 205 Mock::VerifyAndClearExpectations(&mock_profile_client_); 206 SetNetworkConfigurationHandlerExpectations(); 207 } 208 209 void InitializeStandardProfiles() { 210 profiles_stub_.AddProfile(kUser1ProfilePath, kUser1); 211 network_profile_handler_-> 212 AddProfileForTest(NetworkProfile(kUser1ProfilePath, kUser1)); 213 network_profile_handler_-> 214 AddProfileForTest(NetworkProfile(kSharedProfilePath, std::string())); 215 } 216 217 void SetUpEntry(const std::string& path_to_shill_json, 218 const std::string& profile_path, 219 const std::string& entry_path) { 220 scoped_ptr<base::DictionaryValue> entry = 221 test_utils::ReadTestDictionary(path_to_shill_json); 222 profiles_stub_.AddEntry(profile_path, entry_path, *entry); 223 } 224 225 void SetPolicy(onc::ONCSource onc_source, 226 const std::string& userhash, 227 const std::string& path_to_onc) { 228 scoped_ptr<base::DictionaryValue> policy; 229 if (path_to_onc.empty()) 230 policy = onc::ReadDictionaryFromJson(onc::kEmptyUnencryptedConfiguration); 231 else 232 policy = test_utils::ReadTestDictionary(path_to_onc); 233 234 base::ListValue* network_configs = NULL; 235 policy->GetListWithoutPathExpansion( 236 onc::toplevel_config::kNetworkConfigurations, &network_configs); 237 238 managed_handler()->SetPolicy( 239 onc::ONC_SOURCE_USER_POLICY, userhash, *network_configs); 240 } 241 242 void SetNetworkConfigurationHandlerExpectations() { 243 // These calls occur in NetworkConfigurationHandler. 244 EXPECT_CALL(mock_manager_client_, GetProperties(_)).Times(AnyNumber()); 245 EXPECT_CALL(mock_manager_client_, 246 AddPropertyChangedObserver(_)).Times(AnyNumber()); 247 EXPECT_CALL(mock_manager_client_, 248 RemovePropertyChangedObserver(_)).Times(AnyNumber()); 249 } 250 251 ManagedNetworkConfigurationHandler* managed_handler() { 252 return managed_network_configuration_handler_.get(); 253 } 254 255 protected: 256 StrictMock<MockShillManagerClient> mock_manager_client_; 257 StrictMock<MockShillServiceClient> mock_service_client_; 258 StrictMock<MockShillProfileClient> mock_profile_client_; 259 ShillProfileTestClient profiles_stub_; 260 scoped_ptr<TestNetworkProfileHandler> network_profile_handler_; 261 scoped_ptr<NetworkConfigurationHandler> network_configuration_handler_; 262 scoped_ptr<ManagedNetworkConfigurationHandler> 263 managed_network_configuration_handler_; 264 base::MessageLoop message_loop_; 265 266 private: 267 DISALLOW_COPY_AND_ASSIGN(ManagedNetworkConfigurationHandlerTest); 268}; 269 270TEST_F(ManagedNetworkConfigurationHandlerTest, ProfileInitialization) { 271 InitializeStandardProfiles(); 272 message_loop_.RunUntilIdle(); 273} 274 275TEST_F(ManagedNetworkConfigurationHandlerTest, RemoveIrrelevantFields) { 276 InitializeStandardProfiles(); 277 scoped_ptr<base::DictionaryValue> expected_shill_properties = 278 test_utils::ReadTestDictionary( 279 "policy/shill_policy_on_unconfigured_wifi1.json"); 280 281 EXPECT_CALL(mock_profile_client_, 282 GetProperties(dbus::ObjectPath(kUser1ProfilePath), _, _)); 283 284 EXPECT_CALL(mock_manager_client_, 285 ConfigureServiceForProfile( 286 dbus::ObjectPath(kUser1ProfilePath), 287 IsEqualTo(expected_shill_properties.get()), 288 _, _)); 289 290 SetPolicy(onc::ONC_SOURCE_USER_POLICY, 291 kUser1, 292 "policy/policy_wifi1_with_redundant_fields.onc"); 293 message_loop_.RunUntilIdle(); 294} 295 296TEST_F(ManagedNetworkConfigurationHandlerTest, SetPolicyManageUnconfigured) { 297 InitializeStandardProfiles(); 298 scoped_ptr<base::DictionaryValue> expected_shill_properties = 299 test_utils::ReadTestDictionary( 300 "policy/shill_policy_on_unconfigured_wifi1.json"); 301 302 EXPECT_CALL(mock_profile_client_, 303 GetProperties(dbus::ObjectPath(kUser1ProfilePath), _, _)); 304 305 EXPECT_CALL(mock_manager_client_, 306 ConfigureServiceForProfile( 307 dbus::ObjectPath(kUser1ProfilePath), 308 IsEqualTo(expected_shill_properties.get()), 309 _, _)); 310 311 SetPolicy(onc::ONC_SOURCE_USER_POLICY, kUser1, "policy/policy_wifi1.onc"); 312 message_loop_.RunUntilIdle(); 313} 314 315TEST_F(ManagedNetworkConfigurationHandlerTest, SetPolicyIgnoreUnmodified) { 316 InitializeStandardProfiles(); 317 EXPECT_CALL(mock_profile_client_, GetProperties(_, _, _)); 318 319 EXPECT_CALL(mock_manager_client_, ConfigureServiceForProfile(_, _, _, _)); 320 321 SetPolicy(onc::ONC_SOURCE_USER_POLICY, kUser1, "policy/policy_wifi1.onc"); 322 message_loop_.RunUntilIdle(); 323 VerifyAndClearExpectations(); 324 325 SetUpEntry("policy/shill_policy_on_unmanaged_user_wifi1.json", 326 kUser1ProfilePath, 327 "some_entry_path"); 328 329 EXPECT_CALL(mock_profile_client_, GetProperties(_, _, _)); 330 331 EXPECT_CALL(mock_profile_client_, 332 GetEntry(dbus::ObjectPath(kUser1ProfilePath), 333 "some_entry_path", 334 _, _)); 335 336 SetPolicy(onc::ONC_SOURCE_USER_POLICY, kUser1, "policy/policy_wifi1.onc"); 337 message_loop_.RunUntilIdle(); 338} 339 340TEST_F(ManagedNetworkConfigurationHandlerTest, SetPolicyManageUnmanaged) { 341 InitializeStandardProfiles(); 342 SetUpEntry("policy/shill_unmanaged_user_wifi1.json", 343 kUser1ProfilePath, 344 "old_entry_path"); 345 346 scoped_ptr<base::DictionaryValue> expected_shill_properties = 347 test_utils::ReadTestDictionary( 348 "policy/shill_policy_on_unmanaged_user_wifi1.json"); 349 350 EXPECT_CALL(mock_profile_client_, 351 GetProperties(dbus::ObjectPath(kUser1ProfilePath), _, _)); 352 353 EXPECT_CALL( 354 mock_profile_client_, 355 GetEntry(dbus::ObjectPath(kUser1ProfilePath), "old_entry_path", _, _)); 356 357 EXPECT_CALL( 358 mock_profile_client_, 359 DeleteEntry(dbus::ObjectPath(kUser1ProfilePath), "old_entry_path", _, _)); 360 361 EXPECT_CALL(mock_manager_client_, 362 ConfigureServiceForProfile( 363 dbus::ObjectPath(kUser1ProfilePath), 364 IsEqualTo(expected_shill_properties.get()), 365 _, _)); 366 367 SetPolicy(onc::ONC_SOURCE_USER_POLICY, kUser1, "policy/policy_wifi1.onc"); 368 message_loop_.RunUntilIdle(); 369} 370 371// Old ChromeOS versions may not have used the UIData property 372TEST_F(ManagedNetworkConfigurationHandlerTest, 373 SetPolicyManageUnmanagedWithoutUIData) { 374 InitializeStandardProfiles(); 375 SetUpEntry("policy/shill_unmanaged_user_wifi1.json", 376 kUser1ProfilePath, 377 "old_entry_path"); 378 379 scoped_ptr<base::DictionaryValue> expected_shill_properties = 380 test_utils::ReadTestDictionary( 381 "policy/shill_policy_on_unmanaged_user_wifi1.json"); 382 383 EXPECT_CALL(mock_profile_client_, 384 GetProperties(dbus::ObjectPath(kUser1ProfilePath), _, _)); 385 386 EXPECT_CALL( 387 mock_profile_client_, 388 GetEntry(dbus::ObjectPath(kUser1ProfilePath), "old_entry_path", _, _)); 389 390 EXPECT_CALL( 391 mock_profile_client_, 392 DeleteEntry(dbus::ObjectPath(kUser1ProfilePath), "old_entry_path", _, _)); 393 394 EXPECT_CALL(mock_manager_client_, 395 ConfigureServiceForProfile( 396 dbus::ObjectPath(kUser1ProfilePath), 397 IsEqualTo(expected_shill_properties.get()), 398 _, _)); 399 400 SetPolicy(onc::ONC_SOURCE_USER_POLICY, kUser1, "policy/policy_wifi1.onc"); 401 message_loop_.RunUntilIdle(); 402} 403 404TEST_F(ManagedNetworkConfigurationHandlerTest, SetPolicyUpdateManagedNewGUID) { 405 InitializeStandardProfiles(); 406 SetUpEntry("policy/shill_managed_wifi1.json", 407 kUser1ProfilePath, 408 "old_entry_path"); 409 410 scoped_ptr<base::DictionaryValue> expected_shill_properties = 411 test_utils::ReadTestDictionary( 412 "policy/shill_policy_on_unmanaged_user_wifi1.json"); 413 414 // The passphrase isn't sent again, because it's configured by the user and 415 // Shill doesn't sent it on GetProperties calls. 416 expected_shill_properties->RemoveWithoutPathExpansion( 417 flimflam::kPassphraseProperty, NULL); 418 419 EXPECT_CALL(mock_profile_client_, 420 GetProperties(dbus::ObjectPath(kUser1ProfilePath), _, _)); 421 422 EXPECT_CALL( 423 mock_profile_client_, 424 GetEntry(dbus::ObjectPath(kUser1ProfilePath), "old_entry_path", _, _)); 425 426 EXPECT_CALL( 427 mock_profile_client_, 428 DeleteEntry(dbus::ObjectPath(kUser1ProfilePath), "old_entry_path", _, _)); 429 430 EXPECT_CALL(mock_manager_client_, 431 ConfigureServiceForProfile( 432 dbus::ObjectPath(kUser1ProfilePath), 433 IsEqualTo(expected_shill_properties.get()), 434 _, _)); 435 436 SetPolicy(onc::ONC_SOURCE_USER_POLICY, kUser1, "policy/policy_wifi1.onc"); 437 message_loop_.RunUntilIdle(); 438} 439 440TEST_F(ManagedNetworkConfigurationHandlerTest, SetPolicyReapplyToManaged) { 441 InitializeStandardProfiles(); 442 SetUpEntry("policy/shill_policy_on_unmanaged_user_wifi1.json", 443 kUser1ProfilePath, 444 "old_entry_path"); 445 446 scoped_ptr<base::DictionaryValue> expected_shill_properties = 447 test_utils::ReadTestDictionary( 448 "policy/shill_policy_on_unmanaged_user_wifi1.json"); 449 450 // The passphrase isn't sent again, because it's configured by the user and 451 // Shill doesn't sent it on GetProperties calls. 452 expected_shill_properties->RemoveWithoutPathExpansion( 453 flimflam::kPassphraseProperty, NULL); 454 455 EXPECT_CALL(mock_profile_client_, 456 GetProperties(dbus::ObjectPath(kUser1ProfilePath), _, _)); 457 458 EXPECT_CALL( 459 mock_profile_client_, 460 GetEntry(dbus::ObjectPath(kUser1ProfilePath), "old_entry_path", _, _)); 461 462 EXPECT_CALL(mock_manager_client_, 463 ConfigureServiceForProfile( 464 dbus::ObjectPath(kUser1ProfilePath), 465 IsEqualTo(expected_shill_properties.get()), 466 _, _)); 467 468 SetPolicy(onc::ONC_SOURCE_USER_POLICY, kUser1, "policy/policy_wifi1.onc"); 469 message_loop_.RunUntilIdle(); 470 VerifyAndClearExpectations(); 471 472 // If we apply the policy again, without change, then the Shill profile will 473 // not be modified. 474 EXPECT_CALL(mock_profile_client_, 475 GetProperties(dbus::ObjectPath(kUser1ProfilePath), _, _)); 476 477 EXPECT_CALL( 478 mock_profile_client_, 479 GetEntry(dbus::ObjectPath(kUser1ProfilePath), "old_entry_path", _, _)); 480 481 SetPolicy(onc::ONC_SOURCE_USER_POLICY, kUser1, "policy/policy_wifi1.onc"); 482 message_loop_.RunUntilIdle(); 483} 484 485TEST_F(ManagedNetworkConfigurationHandlerTest, SetPolicyUnmanageManaged) { 486 InitializeStandardProfiles(); 487 SetUpEntry("policy/shill_policy_on_unmanaged_user_wifi1.json", 488 kUser1ProfilePath, 489 "old_entry_path"); 490 491 EXPECT_CALL(mock_profile_client_, 492 GetProperties(dbus::ObjectPath(kUser1ProfilePath), _, _)); 493 494 EXPECT_CALL(mock_profile_client_, 495 GetEntry(dbus::ObjectPath(kUser1ProfilePath), 496 "old_entry_path", 497 _, _)); 498 499 EXPECT_CALL(mock_profile_client_, 500 DeleteEntry(dbus::ObjectPath(kUser1ProfilePath), 501 "old_entry_path", 502 _, _)); 503 504 SetPolicy(onc::ONC_SOURCE_USER_POLICY, kUser1, ""); 505 message_loop_.RunUntilIdle(); 506} 507 508TEST_F(ManagedNetworkConfigurationHandlerTest, SetPolicyIgnoreUnmanaged) { 509 InitializeStandardProfiles(); 510 SetUpEntry("policy/shill_unmanaged_user_wifi1.json", 511 kUser1ProfilePath, 512 "old_entry_path"); 513 514 EXPECT_CALL(mock_profile_client_, 515 GetProperties(dbus::ObjectPath(kUser1ProfilePath), _, _)); 516 517 EXPECT_CALL(mock_profile_client_, 518 GetEntry(dbus::ObjectPath(kUser1ProfilePath), 519 "old_entry_path", 520 _, _)); 521 522 SetPolicy(onc::ONC_SOURCE_USER_POLICY, kUser1, ""); 523 message_loop_.RunUntilIdle(); 524} 525 526TEST_F(ManagedNetworkConfigurationHandlerTest, LateProfileLoading) { 527 SetPolicy(onc::ONC_SOURCE_USER_POLICY, kUser1, "policy/policy_wifi1.onc"); 528 529 message_loop_.RunUntilIdle(); 530 VerifyAndClearExpectations(); 531 532 scoped_ptr<base::DictionaryValue> expected_shill_properties = 533 test_utils::ReadTestDictionary( 534 "policy/shill_policy_on_unconfigured_wifi1.json"); 535 536 EXPECT_CALL(mock_profile_client_, 537 GetProperties(dbus::ObjectPath(kUser1ProfilePath), _, _)); 538 539 EXPECT_CALL(mock_manager_client_, 540 ConfigureServiceForProfile( 541 dbus::ObjectPath(kUser1ProfilePath), 542 IsEqualTo(expected_shill_properties.get()), 543 _, _)); 544 545 InitializeStandardProfiles(); 546 message_loop_.RunUntilIdle(); 547} 548 549} // namespace chromeos 550