managed_network_configuration_handler_unittest.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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    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, SetPolicyManageUnconfigured) {
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, kUser1, "policy/policy_wifi1.onc");
291  message_loop_.RunUntilIdle();
292}
293
294TEST_F(ManagedNetworkConfigurationHandlerTest, SetPolicyIgnoreUnmodified) {
295  InitializeStandardProfiles();
296  EXPECT_CALL(mock_profile_client_, GetProperties(_, _, _));
297
298  EXPECT_CALL(mock_manager_client_, ConfigureServiceForProfile(_, _, _, _));
299
300  SetPolicy(onc::ONC_SOURCE_USER_POLICY, kUser1, "policy/policy_wifi1.onc");
301  message_loop_.RunUntilIdle();
302  VerifyAndClearExpectations();
303
304  SetUpEntry("policy/shill_policy_on_unmanaged_user_wifi1.json",
305             kUser1ProfilePath,
306             "some_entry_path");
307
308  EXPECT_CALL(mock_profile_client_, GetProperties(_, _, _));
309
310  EXPECT_CALL(mock_profile_client_,
311              GetEntry(dbus::ObjectPath(kUser1ProfilePath),
312                       "some_entry_path",
313                       _, _));
314
315  SetPolicy(onc::ONC_SOURCE_USER_POLICY, kUser1, "policy/policy_wifi1.onc");
316  message_loop_.RunUntilIdle();
317}
318
319TEST_F(ManagedNetworkConfigurationHandlerTest, SetPolicyManageUnmanaged) {
320  InitializeStandardProfiles();
321  SetUpEntry("policy/shill_unmanaged_user_wifi1.json",
322             kUser1ProfilePath,
323             "old_entry_path");
324
325  scoped_ptr<base::DictionaryValue> expected_shill_properties =
326      test_utils::ReadTestDictionary(
327          "policy/shill_policy_on_unmanaged_user_wifi1.json");
328
329  EXPECT_CALL(mock_profile_client_,
330              GetProperties(dbus::ObjectPath(kUser1ProfilePath), _, _));
331
332  EXPECT_CALL(mock_profile_client_,
333              GetEntry(dbus::ObjectPath(kUser1ProfilePath),
334                       "old_entry_path",
335                       _, _));
336
337  EXPECT_CALL(mock_manager_client_,
338              ConfigureServiceForProfile(
339                  dbus::ObjectPath(kUser1ProfilePath),
340                  IsEqualTo(expected_shill_properties.get()),
341                  _, _));
342
343  SetPolicy(onc::ONC_SOURCE_USER_POLICY, kUser1, "policy/policy_wifi1.onc");
344  message_loop_.RunUntilIdle();
345}
346
347TEST_F(ManagedNetworkConfigurationHandlerTest, SetPolicyUpdateManagedNewGUID) {
348  InitializeStandardProfiles();
349  SetUpEntry("policy/shill_managed_wifi1.json",
350             kUser1ProfilePath,
351             "old_entry_path");
352
353  scoped_ptr<base::DictionaryValue> expected_shill_properties =
354      test_utils::ReadTestDictionary(
355          "policy/shill_policy_on_unmanaged_user_wifi1.json");
356
357  // The passphrase isn't sent again, because it's configured by the user and
358  // Shill doesn't sent it on GetProperties calls.
359  expected_shill_properties->RemoveWithoutPathExpansion(
360      flimflam::kPassphraseProperty, NULL);
361
362  EXPECT_CALL(mock_profile_client_,
363              GetProperties(dbus::ObjectPath(kUser1ProfilePath), _, _));
364
365  EXPECT_CALL(mock_profile_client_,
366              GetEntry(dbus::ObjectPath(kUser1ProfilePath),
367                       "old_entry_path",
368                       _, _));
369
370  EXPECT_CALL(mock_manager_client_,
371              ConfigureServiceForProfile(
372                  dbus::ObjectPath(kUser1ProfilePath),
373                  IsEqualTo(expected_shill_properties.get()),
374                  _, _));
375
376  SetPolicy(onc::ONC_SOURCE_USER_POLICY, kUser1, "policy/policy_wifi1.onc");
377  message_loop_.RunUntilIdle();
378}
379
380TEST_F(ManagedNetworkConfigurationHandlerTest, SetPolicyReapplyToManaged) {
381  InitializeStandardProfiles();
382  SetUpEntry("policy/shill_policy_on_unmanaged_user_wifi1.json",
383             kUser1ProfilePath,
384             "old_entry_path");
385
386  scoped_ptr<base::DictionaryValue> expected_shill_properties =
387      test_utils::ReadTestDictionary(
388          "policy/shill_policy_on_unmanaged_user_wifi1.json");
389
390  // The passphrase isn't sent again, because it's configured by the user and
391  // Shill doesn't sent it on GetProperties calls.
392  expected_shill_properties->RemoveWithoutPathExpansion(
393      flimflam::kPassphraseProperty, NULL);
394
395  EXPECT_CALL(mock_profile_client_,
396              GetProperties(dbus::ObjectPath(kUser1ProfilePath), _, _));
397
398  EXPECT_CALL(mock_profile_client_,
399              GetEntry(dbus::ObjectPath(kUser1ProfilePath),
400                       "old_entry_path",
401                       _, _));
402
403  EXPECT_CALL(mock_manager_client_,
404              ConfigureServiceForProfile(
405                  dbus::ObjectPath(kUser1ProfilePath),
406                  IsEqualTo(expected_shill_properties.get()),
407                  _, _));
408
409  SetPolicy(onc::ONC_SOURCE_USER_POLICY, kUser1, "policy/policy_wifi1.onc");
410  message_loop_.RunUntilIdle();
411}
412
413TEST_F(ManagedNetworkConfigurationHandlerTest, SetPolicyUnmanageManaged) {
414  InitializeStandardProfiles();
415  SetUpEntry("policy/shill_policy_on_unmanaged_user_wifi1.json",
416             kUser1ProfilePath,
417             "old_entry_path");
418
419  EXPECT_CALL(mock_profile_client_,
420              GetProperties(dbus::ObjectPath(kUser1ProfilePath), _, _));
421
422  EXPECT_CALL(mock_profile_client_,
423              GetEntry(dbus::ObjectPath(kUser1ProfilePath),
424                       "old_entry_path",
425                       _, _));
426
427  EXPECT_CALL(mock_profile_client_,
428              DeleteEntry(dbus::ObjectPath(kUser1ProfilePath),
429                          "old_entry_path",
430                          _, _));
431
432  SetPolicy(onc::ONC_SOURCE_USER_POLICY, kUser1, "");
433  message_loop_.RunUntilIdle();
434}
435
436TEST_F(ManagedNetworkConfigurationHandlerTest, SetPolicyIgnoreUnmanaged) {
437  InitializeStandardProfiles();
438  SetUpEntry("policy/shill_unmanaged_user_wifi1.json",
439             kUser1ProfilePath,
440             "old_entry_path");
441
442  EXPECT_CALL(mock_profile_client_,
443              GetProperties(dbus::ObjectPath(kUser1ProfilePath), _, _));
444
445  EXPECT_CALL(mock_profile_client_,
446              GetEntry(dbus::ObjectPath(kUser1ProfilePath),
447                       "old_entry_path",
448                       _, _));
449
450  SetPolicy(onc::ONC_SOURCE_USER_POLICY, kUser1, "");
451  message_loop_.RunUntilIdle();
452}
453
454TEST_F(ManagedNetworkConfigurationHandlerTest, LateProfileLoading) {
455  SetPolicy(onc::ONC_SOURCE_USER_POLICY, kUser1, "policy/policy_wifi1.onc");
456
457  message_loop_.RunUntilIdle();
458  VerifyAndClearExpectations();
459
460  scoped_ptr<base::DictionaryValue> expected_shill_properties =
461      test_utils::ReadTestDictionary(
462          "policy/shill_policy_on_unconfigured_wifi1.json");
463
464  EXPECT_CALL(mock_profile_client_,
465              GetProperties(dbus::ObjectPath(kUser1ProfilePath), _, _));
466
467  EXPECT_CALL(mock_manager_client_,
468              ConfigureServiceForProfile(
469                  dbus::ObjectPath(kUser1ProfilePath),
470                  IsEqualTo(expected_shill_properties.get()),
471                  _, _));
472
473  InitializeStandardProfiles();
474  message_loop_.RunUntilIdle();
475}
476
477}  // namespace chromeos
478