managed_network_configuration_handler_unittest.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
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.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 virtual ~TestNetworkProfileHandler() {} 137 138 void AddProfileForTest(const NetworkProfile& profile) { 139 AddProfile(profile); 140 } 141 142 private: 143 DISALLOW_COPY_AND_ASSIGN(TestNetworkProfileHandler); 144}; 145 146} // namespace 147 148class ManagedNetworkConfigurationHandlerTest : public testing::Test { 149 public: 150 ManagedNetworkConfigurationHandlerTest() { 151 } 152 153 virtual ~ManagedNetworkConfigurationHandlerTest() { 154 } 155 156 virtual void SetUp() OVERRIDE { 157 MockDBusThreadManager* dbus_thread_manager = new MockDBusThreadManager; 158 EXPECT_CALL(*dbus_thread_manager, GetSystemBus()) 159 .WillRepeatedly(Return(static_cast<dbus::Bus*>(NULL))); 160 DBusThreadManager::InitializeForTesting(dbus_thread_manager); 161 162 SetNetworkConfigurationHandlerExpectations(); 163 164 EXPECT_CALL(*dbus_thread_manager, GetShillManagerClient()) 165 .WillRepeatedly(Return(&mock_manager_client_)); 166 EXPECT_CALL(*dbus_thread_manager, GetShillServiceClient()) 167 .WillRepeatedly(Return(&mock_service_client_)); 168 EXPECT_CALL(*dbus_thread_manager, GetShillProfileClient()) 169 .WillRepeatedly(Return(&mock_profile_client_)); 170 171 ON_CALL(mock_profile_client_, GetProperties(_,_,_)) 172 .WillByDefault(Invoke(&profiles_stub_, 173 &ShillProfileTestClient::GetProperties)); 174 175 ON_CALL(mock_profile_client_, GetEntry(_,_,_,_)) 176 .WillByDefault(Invoke(&profiles_stub_, 177 &ShillProfileTestClient::GetEntry)); 178 179 network_profile_handler_.reset(new TestNetworkProfileHandler()); 180 network_configuration_handler_.reset( 181 NetworkConfigurationHandler::InitializeForTest( 182 NULL /* no NetworkStateHandler */)); 183 managed_network_configuration_handler_.reset( 184 new ManagedNetworkConfigurationHandler()); 185 managed_network_configuration_handler_->Init( 186 NULL /* no NetworkStateHandler */, 187 network_profile_handler_.get(), 188 network_configuration_handler_.get()); 189 190 message_loop_.RunUntilIdle(); 191 } 192 193 virtual void TearDown() OVERRIDE { 194 managed_network_configuration_handler_.reset(); 195 network_configuration_handler_.reset(); 196 network_profile_handler_.reset(); 197 DBusThreadManager::Shutdown(); 198 } 199 200 void VerifyAndClearExpectations() { 201 Mock::VerifyAndClearExpectations(&mock_manager_client_); 202 Mock::VerifyAndClearExpectations(&mock_service_client_); 203 Mock::VerifyAndClearExpectations(&mock_profile_client_); 204 SetNetworkConfigurationHandlerExpectations(); 205 } 206 207 void InitializeStandardProfiles() { 208 profiles_stub_.AddProfile(kUser1ProfilePath, kUser1); 209 network_profile_handler_-> 210 AddProfileForTest(NetworkProfile(kUser1ProfilePath, kUser1)); 211 network_profile_handler_-> 212 AddProfileForTest(NetworkProfile(kSharedProfilePath, std::string())); 213 } 214 215 void SetUpEntry(const std::string& path_to_shill_json, 216 const std::string& profile_path, 217 const std::string& entry_path) { 218 scoped_ptr<base::DictionaryValue> entry = 219 test_utils::ReadTestDictionary(path_to_shill_json); 220 profiles_stub_.AddEntry(profile_path, entry_path, *entry); 221 } 222 223 void SetPolicy(onc::ONCSource onc_source, 224 const std::string& userhash, 225 const std::string& path_to_onc) { 226 scoped_ptr<base::DictionaryValue> policy; 227 if (path_to_onc.empty()) 228 policy = onc::ReadDictionaryFromJson(onc::kEmptyUnencryptedConfiguration); 229 else 230 policy = test_utils::ReadTestDictionary(path_to_onc); 231 232 base::ListValue* network_configs = NULL; 233 policy->GetListWithoutPathExpansion( 234 onc::toplevel_config::kNetworkConfigurations, &network_configs); 235 236 managed_handler()->SetPolicy( 237 onc::ONC_SOURCE_USER_POLICY, userhash, *network_configs); 238 } 239 240 void SetNetworkConfigurationHandlerExpectations() { 241 // These calls occur in NetworkConfigurationHandler. 242 EXPECT_CALL(mock_manager_client_, GetProperties(_)).Times(AnyNumber()); 243 EXPECT_CALL(mock_manager_client_, 244 AddPropertyChangedObserver(_)).Times(AnyNumber()); 245 EXPECT_CALL(mock_manager_client_, 246 RemovePropertyChangedObserver(_)).Times(AnyNumber()); 247 } 248 249 ManagedNetworkConfigurationHandler* managed_handler() { 250 return managed_network_configuration_handler_.get(); 251 } 252 253 protected: 254 StrictMock<MockShillManagerClient> mock_manager_client_; 255 StrictMock<MockShillServiceClient> mock_service_client_; 256 StrictMock<MockShillProfileClient> mock_profile_client_; 257 ShillProfileTestClient profiles_stub_; 258 scoped_ptr<TestNetworkProfileHandler> network_profile_handler_; 259 scoped_ptr<NetworkConfigurationHandler> network_configuration_handler_; 260 scoped_ptr<ManagedNetworkConfigurationHandler> 261 managed_network_configuration_handler_; 262 MessageLoop message_loop_; 263 264 private: 265 DISALLOW_COPY_AND_ASSIGN(ManagedNetworkConfigurationHandlerTest); 266}; 267 268TEST_F(ManagedNetworkConfigurationHandlerTest, ProfileInitialization) { 269 InitializeStandardProfiles(); 270 message_loop_.RunUntilIdle(); 271} 272 273TEST_F(ManagedNetworkConfigurationHandlerTest, SetPolicyManageUnconfigured) { 274 InitializeStandardProfiles(); 275 scoped_ptr<base::DictionaryValue> expected_shill_properties = 276 test_utils::ReadTestDictionary( 277 "policy/shill_policy_on_unconfigured_wifi1.json"); 278 279 EXPECT_CALL(mock_profile_client_, 280 GetProperties(dbus::ObjectPath(kUser1ProfilePath), _, _)); 281 282 EXPECT_CALL(mock_manager_client_, 283 ConfigureServiceForProfile( 284 dbus::ObjectPath(kUser1ProfilePath), 285 IsEqualTo(expected_shill_properties.get()), 286 _, _)); 287 288 SetPolicy(onc::ONC_SOURCE_USER_POLICY, kUser1, "policy/policy_wifi1.onc"); 289 message_loop_.RunUntilIdle(); 290} 291 292TEST_F(ManagedNetworkConfigurationHandlerTest, SetPolicyIgnoreUnmodified) { 293 InitializeStandardProfiles(); 294 EXPECT_CALL(mock_profile_client_, GetProperties(_, _, _)); 295 296 EXPECT_CALL(mock_manager_client_, ConfigureServiceForProfile(_, _, _, _)); 297 298 SetPolicy(onc::ONC_SOURCE_USER_POLICY, kUser1, "policy/policy_wifi1.onc"); 299 message_loop_.RunUntilIdle(); 300 VerifyAndClearExpectations(); 301 302 SetUpEntry("policy/shill_policy_on_unmanaged_user_wifi1.json", 303 kUser1ProfilePath, 304 "some_entry_path"); 305 306 EXPECT_CALL(mock_profile_client_, GetProperties(_, _, _)); 307 308 EXPECT_CALL(mock_profile_client_, 309 GetEntry(dbus::ObjectPath(kUser1ProfilePath), 310 "some_entry_path", 311 _, _)); 312 313 SetPolicy(onc::ONC_SOURCE_USER_POLICY, kUser1, "policy/policy_wifi1.onc"); 314 message_loop_.RunUntilIdle(); 315} 316 317TEST_F(ManagedNetworkConfigurationHandlerTest, SetPolicyManageUnmanaged) { 318 InitializeStandardProfiles(); 319 SetUpEntry("policy/shill_unmanaged_user_wifi1.json", 320 kUser1ProfilePath, 321 "old_entry_path"); 322 323 scoped_ptr<base::DictionaryValue> expected_shill_properties = 324 test_utils::ReadTestDictionary( 325 "policy/shill_policy_on_unmanaged_user_wifi1.json"); 326 327 EXPECT_CALL(mock_profile_client_, 328 GetProperties(dbus::ObjectPath(kUser1ProfilePath), _, _)); 329 330 EXPECT_CALL(mock_profile_client_, 331 GetEntry(dbus::ObjectPath(kUser1ProfilePath), 332 "old_entry_path", 333 _, _)); 334 335 EXPECT_CALL(mock_manager_client_, 336 ConfigureServiceForProfile( 337 dbus::ObjectPath(kUser1ProfilePath), 338 IsEqualTo(expected_shill_properties.get()), 339 _, _)); 340 341 SetPolicy(onc::ONC_SOURCE_USER_POLICY, kUser1, "policy/policy_wifi1.onc"); 342 message_loop_.RunUntilIdle(); 343} 344 345TEST_F(ManagedNetworkConfigurationHandlerTest, SetPolicyUpdateManagedNewGUID) { 346 InitializeStandardProfiles(); 347 SetUpEntry("policy/shill_managed_wifi1.json", 348 kUser1ProfilePath, 349 "old_entry_path"); 350 351 scoped_ptr<base::DictionaryValue> expected_shill_properties = 352 test_utils::ReadTestDictionary( 353 "policy/shill_policy_on_unmanaged_user_wifi1.json"); 354 355 // The passphrase isn't sent again, because it's configured by the user and 356 // Shill doesn't sent it on GetProperties calls. 357 expected_shill_properties->RemoveWithoutPathExpansion( 358 flimflam::kPassphraseProperty, NULL); 359 360 EXPECT_CALL(mock_profile_client_, 361 GetProperties(dbus::ObjectPath(kUser1ProfilePath), _, _)); 362 363 EXPECT_CALL(mock_profile_client_, 364 GetEntry(dbus::ObjectPath(kUser1ProfilePath), 365 "old_entry_path", 366 _, _)); 367 368 EXPECT_CALL(mock_manager_client_, 369 ConfigureServiceForProfile( 370 dbus::ObjectPath(kUser1ProfilePath), 371 IsEqualTo(expected_shill_properties.get()), 372 _, _)); 373 374 SetPolicy(onc::ONC_SOURCE_USER_POLICY, kUser1, "policy/policy_wifi1.onc"); 375 message_loop_.RunUntilIdle(); 376} 377 378TEST_F(ManagedNetworkConfigurationHandlerTest, SetPolicyReapplyToManaged) { 379 InitializeStandardProfiles(); 380 SetUpEntry("policy/shill_policy_on_unmanaged_user_wifi1.json", 381 kUser1ProfilePath, 382 "old_entry_path"); 383 384 scoped_ptr<base::DictionaryValue> expected_shill_properties = 385 test_utils::ReadTestDictionary( 386 "policy/shill_policy_on_unmanaged_user_wifi1.json"); 387 388 // The passphrase isn't sent again, because it's configured by the user and 389 // Shill doesn't sent it on GetProperties calls. 390 expected_shill_properties->RemoveWithoutPathExpansion( 391 flimflam::kPassphraseProperty, NULL); 392 393 EXPECT_CALL(mock_profile_client_, 394 GetProperties(dbus::ObjectPath(kUser1ProfilePath), _, _)); 395 396 EXPECT_CALL(mock_profile_client_, 397 GetEntry(dbus::ObjectPath(kUser1ProfilePath), 398 "old_entry_path", 399 _, _)); 400 401 EXPECT_CALL(mock_manager_client_, 402 ConfigureServiceForProfile( 403 dbus::ObjectPath(kUser1ProfilePath), 404 IsEqualTo(expected_shill_properties.get()), 405 _, _)); 406 407 SetPolicy(onc::ONC_SOURCE_USER_POLICY, kUser1, "policy/policy_wifi1.onc"); 408 message_loop_.RunUntilIdle(); 409} 410 411TEST_F(ManagedNetworkConfigurationHandlerTest, SetPolicyUnmanageManaged) { 412 InitializeStandardProfiles(); 413 SetUpEntry("policy/shill_policy_on_unmanaged_user_wifi1.json", 414 kUser1ProfilePath, 415 "old_entry_path"); 416 417 EXPECT_CALL(mock_profile_client_, 418 GetProperties(dbus::ObjectPath(kUser1ProfilePath), _, _)); 419 420 EXPECT_CALL(mock_profile_client_, 421 GetEntry(dbus::ObjectPath(kUser1ProfilePath), 422 "old_entry_path", 423 _, _)); 424 425 EXPECT_CALL(mock_profile_client_, 426 DeleteEntry(dbus::ObjectPath(kUser1ProfilePath), 427 "old_entry_path", 428 _, _)); 429 430 SetPolicy(onc::ONC_SOURCE_USER_POLICY, kUser1, ""); 431 message_loop_.RunUntilIdle(); 432} 433 434TEST_F(ManagedNetworkConfigurationHandlerTest, SetPolicyIgnoreUnmanaged) { 435 InitializeStandardProfiles(); 436 SetUpEntry("policy/shill_unmanaged_user_wifi1.json", 437 kUser1ProfilePath, 438 "old_entry_path"); 439 440 EXPECT_CALL(mock_profile_client_, 441 GetProperties(dbus::ObjectPath(kUser1ProfilePath), _, _)); 442 443 EXPECT_CALL(mock_profile_client_, 444 GetEntry(dbus::ObjectPath(kUser1ProfilePath), 445 "old_entry_path", 446 _, _)); 447 448 SetPolicy(onc::ONC_SOURCE_USER_POLICY, kUser1, ""); 449 message_loop_.RunUntilIdle(); 450} 451 452TEST_F(ManagedNetworkConfigurationHandlerTest, LateProfileLoading) { 453 SetPolicy(onc::ONC_SOURCE_USER_POLICY, kUser1, "policy/policy_wifi1.onc"); 454 455 message_loop_.RunUntilIdle(); 456 VerifyAndClearExpectations(); 457 458 scoped_ptr<base::DictionaryValue> expected_shill_properties = 459 test_utils::ReadTestDictionary( 460 "policy/shill_policy_on_unconfigured_wifi1.json"); 461 462 EXPECT_CALL(mock_profile_client_, 463 GetProperties(dbus::ObjectPath(kUser1ProfilePath), _, _)); 464 465 EXPECT_CALL(mock_manager_client_, 466 ConfigureServiceForProfile( 467 dbus::ObjectPath(kUser1ProfilePath), 468 IsEqualTo(expected_shill_properties.get()), 469 _, _)); 470 471 InitializeStandardProfiles(); 472 message_loop_.RunUntilIdle(); 473} 474 475} // namespace chromeos 476