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