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