managed_network_configuration_handler_unittest.cc revision 558790d6acca3451cf3a6b497803a5f07d0bec58
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, SetEmptyPolicyIgnoreUnmanaged) {
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, SetPolicyIgnoreUnmanaged) {
527  InitializeStandardProfiles();
528  SetUpEntry("policy/shill_unmanaged_user_wifi2.json",
529             kUser1ProfilePath,
530             "wifi2_entry_path");
531
532  EXPECT_CALL(mock_profile_client_,
533              GetProperties(dbus::ObjectPath(kUser1ProfilePath), _, _));
534
535  EXPECT_CALL(
536      mock_profile_client_,
537      GetEntry(dbus::ObjectPath(kUser1ProfilePath), "wifi2_entry_path", _, _));
538
539  scoped_ptr<base::DictionaryValue> expected_shill_properties =
540      test_utils::ReadTestDictionary(
541          "policy/shill_policy_on_unconfigured_wifi1.json");
542
543  EXPECT_CALL(mock_manager_client_,
544              ConfigureServiceForProfile(
545                  dbus::ObjectPath(kUser1ProfilePath),
546                  IsEqualTo(expected_shill_properties.get()),
547                  _, _));
548
549  SetPolicy(onc::ONC_SOURCE_USER_POLICY, kUser1, "policy/policy_wifi1.onc");
550  message_loop_.RunUntilIdle();
551}
552
553TEST_F(ManagedNetworkConfigurationHandlerTest, LateProfileLoading) {
554  SetPolicy(onc::ONC_SOURCE_USER_POLICY, kUser1, "policy/policy_wifi1.onc");
555
556  message_loop_.RunUntilIdle();
557  VerifyAndClearExpectations();
558
559  scoped_ptr<base::DictionaryValue> expected_shill_properties =
560      test_utils::ReadTestDictionary(
561          "policy/shill_policy_on_unconfigured_wifi1.json");
562
563  EXPECT_CALL(mock_profile_client_,
564              GetProperties(dbus::ObjectPath(kUser1ProfilePath), _, _));
565
566  EXPECT_CALL(mock_manager_client_,
567              ConfigureServiceForProfile(
568                  dbus::ObjectPath(kUser1ProfilePath),
569                  IsEqualTo(expected_shill_properties.get()),
570                  _, _));
571
572  InitializeStandardProfiles();
573  message_loop_.RunUntilIdle();
574}
575
576}  // namespace chromeos
577