1// Copyright (c) 2012 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 "base/bind.h"
6#include "base/json/json_writer.h"
7#include "base/message_loop/message_loop.h"
8#include "base/strings/string_piece.h"
9#include "base/values.h"
10#include "chromeos/dbus/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/network_configuration_handler.h"
15#include "chromeos/network/network_profile_handler.h"
16#include "chromeos/network/network_state.h"
17#include "chromeos/network/network_state_handler.h"
18#include "chromeos/network/network_state_handler_observer.h"
19#include "chromeos/network/shill_property_util.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::_;
25using ::testing::AnyNumber;
26using ::testing::Invoke;
27using ::testing::Pointee;
28using ::testing::Return;
29using ::testing::SaveArg;
30using ::testing::StrEq;
31
32// Matcher to match base::Value.
33MATCHER_P(IsEqualTo, value, "") { return arg.Equals(value); }
34
35namespace chromeos {
36
37namespace {
38
39static std::string PrettyJson(const base::DictionaryValue& value) {
40  std::string pretty;
41  base::JSONWriter::WriteWithOptions(&value,
42                                     base::JSONWriter::OPTIONS_PRETTY_PRINT,
43                                     &pretty);
44  return pretty;
45}
46
47void DictionaryValueCallback(
48    const std::string& expected_id,
49    const std::string& expected_json,
50    const std::string& service_path,
51    const base::DictionaryValue& dictionary) {
52  std::string dict_str = PrettyJson(dictionary);
53  EXPECT_EQ(expected_json, dict_str);
54  EXPECT_EQ(expected_id, service_path);
55}
56
57void ErrorCallback(bool error_expected,
58                   const std::string& expected_id,
59                   const std::string& error_name,
60                   scoped_ptr<base::DictionaryValue> error_data) {
61  EXPECT_TRUE(error_expected) << "Unexpected error: " << error_name
62      << " with associated data: \n"
63      << PrettyJson(*error_data);
64}
65
66void StringResultCallback(const std::string& expected_result,
67                          const std::string& result) {
68  EXPECT_EQ(expected_result, result);
69}
70
71void DBusErrorCallback(const std::string& error_name,
72                       const std::string& error_message) {
73  EXPECT_TRUE(false) << "DBus Error: " << error_name << "("
74      << error_message << ")";
75}
76
77class TestCallback {
78 public:
79  TestCallback() : run_count_(0) {}
80  void Run() {
81    ++run_count_;
82  }
83  int run_count() const { return run_count_; }
84
85 private:
86  int run_count_;
87};
88
89}  // namespace
90
91class NetworkConfigurationHandlerTest : public testing::Test {
92 public:
93  NetworkConfigurationHandlerTest()
94      : mock_manager_client_(NULL),
95        mock_profile_client_(NULL),
96        mock_service_client_(NULL),
97        dictionary_value_result_(NULL) {}
98  virtual ~NetworkConfigurationHandlerTest() {}
99
100  virtual void SetUp() OVERRIDE {
101    scoped_ptr<DBusThreadManagerSetter> dbus_setter =
102        DBusThreadManager::GetSetterForTesting();
103    mock_manager_client_ = new MockShillManagerClient();
104    mock_profile_client_ = new MockShillProfileClient();
105    mock_service_client_ = new MockShillServiceClient();
106    dbus_setter->SetShillManagerClient(
107        scoped_ptr<ShillManagerClient>(mock_manager_client_).Pass());
108    dbus_setter->SetShillProfileClient(
109        scoped_ptr<ShillProfileClient>(mock_profile_client_).Pass());
110    dbus_setter->SetShillServiceClient(
111        scoped_ptr<ShillServiceClient>(mock_service_client_).Pass());
112
113    EXPECT_CALL(*mock_service_client_, GetProperties(_, _))
114        .Times(AnyNumber());
115    EXPECT_CALL(*mock_manager_client_, GetProperties(_))
116        .Times(AnyNumber());
117    EXPECT_CALL(*mock_manager_client_, AddPropertyChangedObserver(_))
118        .Times(AnyNumber());
119    EXPECT_CALL(*mock_manager_client_, RemovePropertyChangedObserver(_))
120        .Times(AnyNumber());
121
122    network_state_handler_.reset(NetworkStateHandler::InitializeForTest());
123    network_configuration_handler_.reset(new NetworkConfigurationHandler());
124    network_configuration_handler_->Init(network_state_handler_.get());
125    message_loop_.RunUntilIdle();
126  }
127
128  virtual void TearDown() OVERRIDE {
129    network_configuration_handler_.reset();
130    network_state_handler_.reset();
131    DBusThreadManager::Shutdown();
132  }
133
134  // Handles responses for GetProperties method calls.
135  void OnGetProperties(
136      const dbus::ObjectPath& path,
137      const ShillClientHelper::DictionaryValueCallback& callback) {
138    callback.Run(DBUS_METHOD_CALL_SUCCESS, *dictionary_value_result_);
139  }
140
141  // Handles responses for SetProperties method calls.
142  void OnSetProperties(const dbus::ObjectPath& service_path,
143                       const base::DictionaryValue& properties,
144                       const base::Closure& callback,
145                       const ShillClientHelper::ErrorCallback& error_callback) {
146    callback.Run();
147  }
148
149  // Handles responses for ClearProperties method calls.
150  void OnClearProperties(
151      const dbus::ObjectPath& service_path,
152      const std::vector<std::string>& names,
153      const ShillClientHelper::ListValueCallback& callback,
154      const ShillClientHelper::ErrorCallback& error_callback) {
155    base::ListValue result;
156    result.AppendBoolean(true);
157    callback.Run(result);
158  }
159
160  // Handles responses for ClearProperties method calls, and simulates an error
161  // result.
162  void OnClearPropertiesError(
163      const dbus::ObjectPath& service_path,
164      const std::vector<std::string>& names,
165      const ShillClientHelper::ListValueCallback& callback,
166      const ShillClientHelper::ErrorCallback& error_callback) {
167    base::ListValue result;
168    result.AppendBoolean(false);
169    callback.Run(result);
170  }
171
172  void OnConfigureService(
173      const dbus::ObjectPath& profile_path,
174      const base::DictionaryValue& properties,
175      const ObjectPathCallback& callback,
176      const ShillClientHelper::ErrorCallback& error_callback) {
177    callback.Run(dbus::ObjectPath("/service/2"));
178  }
179
180  void OnGetLoadableProfileEntries(
181      const dbus::ObjectPath& service_path,
182      const ShillClientHelper::DictionaryValueCallback& callback) {
183    base::DictionaryValue entries;
184    entries.SetString("profile1", "entry1");
185    entries.SetString("profile2", "entry2");
186    callback.Run(DBUS_METHOD_CALL_SUCCESS, entries);
187  }
188
189  void OnDeleteEntry(const dbus::ObjectPath& profile_path,
190                     const std::string& entry_path,
191                     const base::Closure& callback,
192                     const ShillClientHelper::ErrorCallback& error_callback) {
193    // Don't run the callback immediately to emulate actual behavior.
194    message_loop_.PostTask(FROM_HERE, callback);
195  }
196
197  bool PendingProfileEntryDeleterForTest(const std::string& service_path) {
198    return network_configuration_handler_->
199        PendingProfileEntryDeleterForTest(service_path);
200  }
201
202 protected:
203  MockShillManagerClient* mock_manager_client_;
204  MockShillProfileClient* mock_profile_client_;
205  MockShillServiceClient* mock_service_client_;
206  scoped_ptr<NetworkStateHandler> network_state_handler_;
207  scoped_ptr<NetworkConfigurationHandler> network_configuration_handler_;
208  base::MessageLoopForUI message_loop_;
209  base::DictionaryValue* dictionary_value_result_;
210};
211
212TEST_F(NetworkConfigurationHandlerTest, GetProperties) {
213  std::string service_path = "/service/1";
214  std::string expected_json = "{\n   \"SSID\": \"MyNetwork\"\n}\n";
215  std::string networkName = "MyNetwork";
216  std::string key = "SSID";
217  scoped_ptr<base::StringValue> networkNameValue(
218      new base::StringValue(networkName));
219
220  base::DictionaryValue value;
221  value.Set(key, new base::StringValue(networkName));
222  dictionary_value_result_ = &value;
223  EXPECT_CALL(*mock_service_client_,
224              SetProperty(dbus::ObjectPath(service_path), key,
225                          IsEqualTo(networkNameValue.get()), _, _)).Times(1);
226  mock_service_client_->SetProperty(dbus::ObjectPath(service_path),
227                                    key,
228                                    *networkNameValue,
229                                    base::Bind(&base::DoNothing),
230                                    base::Bind(&DBusErrorCallback));
231  message_loop_.RunUntilIdle();
232
233  ShillServiceClient::DictionaryValueCallback get_properties_callback;
234  EXPECT_CALL(*mock_service_client_,
235              GetProperties(_, _)).WillOnce(
236                  Invoke(this,
237                         &NetworkConfigurationHandlerTest::OnGetProperties));
238  network_configuration_handler_->GetProperties(
239      service_path,
240      base::Bind(&DictionaryValueCallback,
241                 service_path,
242                 expected_json),
243                 base::Bind(&ErrorCallback, false, service_path));
244  message_loop_.RunUntilIdle();
245}
246
247TEST_F(NetworkConfigurationHandlerTest, SetProperties) {
248  std::string service_path = "/service/1";
249  std::string networkName = "MyNetwork";
250  std::string key = "SSID";
251  scoped_ptr<base::StringValue> networkNameValue(
252      new base::StringValue(networkName));
253
254  base::DictionaryValue value;
255  value.Set(key, new base::StringValue(networkName));
256  dictionary_value_result_ = &value;
257  EXPECT_CALL(*mock_service_client_,
258              SetProperties(_, _, _, _)).WillOnce(
259                  Invoke(this,
260                         &NetworkConfigurationHandlerTest::OnSetProperties));
261  network_configuration_handler_->SetProperties(
262      service_path,
263      value,
264      base::Bind(&base::DoNothing),
265      base::Bind(&ErrorCallback, false, service_path));
266  message_loop_.RunUntilIdle();
267}
268
269TEST_F(NetworkConfigurationHandlerTest, ClearProperties) {
270  std::string service_path = "/service/1";
271  std::string networkName = "MyNetwork";
272  std::string key = "SSID";
273  scoped_ptr<base::StringValue> networkNameValue(
274      new base::StringValue(networkName));
275
276  // First set up a value to clear.
277  base::DictionaryValue value;
278  value.Set(key, new base::StringValue(networkName));
279  dictionary_value_result_ = &value;
280  EXPECT_CALL(*mock_service_client_,
281              SetProperties(_, _, _, _)).WillOnce(
282                  Invoke(this,
283                         &NetworkConfigurationHandlerTest::OnSetProperties));
284  network_configuration_handler_->SetProperties(
285      service_path,
286      value,
287      base::Bind(&base::DoNothing),
288      base::Bind(&ErrorCallback, false, service_path));
289  message_loop_.RunUntilIdle();
290
291  // Now clear it.
292  std::vector<std::string> values_to_clear;
293  values_to_clear.push_back(key);
294  EXPECT_CALL(*mock_service_client_,
295              ClearProperties(_, _, _, _)).WillOnce(
296                  Invoke(this,
297                         &NetworkConfigurationHandlerTest::OnClearProperties));
298  network_configuration_handler_->ClearProperties(
299      service_path,
300      values_to_clear,
301      base::Bind(&base::DoNothing),
302      base::Bind(&ErrorCallback, false, service_path));
303  message_loop_.RunUntilIdle();
304}
305
306TEST_F(NetworkConfigurationHandlerTest, ClearPropertiesError) {
307  std::string service_path = "/service/1";
308  std::string networkName = "MyNetwork";
309  std::string key = "SSID";
310  scoped_ptr<base::StringValue> networkNameValue(
311      new base::StringValue(networkName));
312
313  // First set up a value to clear.
314  base::DictionaryValue value;
315  value.Set(key, new base::StringValue(networkName));
316  dictionary_value_result_ = &value;
317  EXPECT_CALL(*mock_service_client_,
318              SetProperties(_, _, _, _)).WillOnce(
319                  Invoke(this,
320                         &NetworkConfigurationHandlerTest::OnSetProperties));
321  network_configuration_handler_->SetProperties(
322      service_path,
323      value,
324      base::Bind(&base::DoNothing),
325      base::Bind(&ErrorCallback, false, service_path));
326  message_loop_.RunUntilIdle();
327
328  // Now clear it.
329  std::vector<std::string> values_to_clear;
330  values_to_clear.push_back(key);
331  EXPECT_CALL(
332      *mock_service_client_,
333      ClearProperties(_, _, _, _)).WillOnce(
334          Invoke(this,
335                 &NetworkConfigurationHandlerTest::OnClearPropertiesError));
336  network_configuration_handler_->ClearProperties(
337      service_path,
338      values_to_clear,
339      base::Bind(&base::DoNothing),
340      base::Bind(&ErrorCallback, true, service_path));
341  message_loop_.RunUntilIdle();
342}
343
344TEST_F(NetworkConfigurationHandlerTest, CreateConfiguration) {
345  std::string networkName = "MyNetwork";
346  std::string key = "SSID";
347  std::string type = "wifi";
348  std::string profile = "profile path";
349  base::DictionaryValue value;
350  shill_property_util::SetSSID(networkName, &value);
351  value.SetWithoutPathExpansion(shill::kTypeProperty,
352                                new base::StringValue(type));
353  value.SetWithoutPathExpansion(shill::kProfileProperty,
354                                new base::StringValue(profile));
355
356  EXPECT_CALL(*mock_manager_client_,
357              ConfigureServiceForProfile(dbus::ObjectPath(profile), _, _, _))
358      .WillOnce(
359           Invoke(this, &NetworkConfigurationHandlerTest::OnConfigureService));
360  network_configuration_handler_->CreateConfiguration(
361      value,
362      base::Bind(&StringResultCallback, std::string("/service/2")),
363      base::Bind(&ErrorCallback, false, std::string()));
364  message_loop_.RunUntilIdle();
365}
366
367TEST_F(NetworkConfigurationHandlerTest, RemoveConfiguration) {
368  std::string service_path = "/service/1";
369
370  TestCallback test_callback;
371  EXPECT_CALL(
372      *mock_service_client_,
373      GetLoadableProfileEntries(_, _)).WillOnce(Invoke(
374          this,
375          &NetworkConfigurationHandlerTest::OnGetLoadableProfileEntries));
376  EXPECT_CALL(
377      *mock_profile_client_,
378      DeleteEntry(_, _, _, _)).WillRepeatedly(Invoke(
379          this,
380          &NetworkConfigurationHandlerTest::OnDeleteEntry));
381
382  network_configuration_handler_->RemoveConfiguration(
383      service_path,
384      base::Bind(&TestCallback::Run, base::Unretained(&test_callback)),
385      base::Bind(&ErrorCallback, false, service_path));
386  message_loop_.RunUntilIdle();
387  EXPECT_EQ(1, test_callback.run_count());
388  EXPECT_FALSE(PendingProfileEntryDeleterForTest(service_path));
389}
390
391////////////////////////////////////////////////////////////////////////////////
392// Stub based tests
393
394namespace {
395
396class TestObserver : public chromeos::NetworkStateHandlerObserver {
397 public:
398  TestObserver() : network_list_changed_count_(0) {}
399  virtual ~TestObserver() {}
400
401  virtual void NetworkListChanged() OVERRIDE {
402    ++network_list_changed_count_;
403  }
404
405  virtual void NetworkPropertiesUpdated(const NetworkState* network) OVERRIDE {
406    property_updates_[network->path()]++;
407  }
408
409  size_t network_list_changed_count() { return network_list_changed_count_; }
410
411  int PropertyUpdatesForService(const std::string& service_path) {
412    return property_updates_[service_path];
413  }
414
415  void ClearPropertyUpdates() {
416    property_updates_.clear();
417  }
418
419 private:
420  size_t network_list_changed_count_;
421  std::map<std::string, int> property_updates_;
422
423  DISALLOW_COPY_AND_ASSIGN(TestObserver);
424};
425
426}  // namespace
427
428class NetworkConfigurationHandlerStubTest : public testing::Test {
429 public:
430  NetworkConfigurationHandlerStubTest()  {
431  }
432
433  virtual ~NetworkConfigurationHandlerStubTest() {
434  }
435
436  virtual void SetUp() OVERRIDE {
437    DBusThreadManager::Initialize();
438
439    network_state_handler_.reset(NetworkStateHandler::InitializeForTest());
440    test_observer_.reset(new TestObserver());
441    network_state_handler_->AddObserver(test_observer_.get(), FROM_HERE);
442
443    network_configuration_handler_.reset(new NetworkConfigurationHandler());
444    network_configuration_handler_->Init(network_state_handler_.get());
445
446    message_loop_.RunUntilIdle();
447    test_observer_->ClearPropertyUpdates();
448  }
449
450  virtual void TearDown() OVERRIDE {
451    network_configuration_handler_.reset();
452    network_state_handler_->RemoveObserver(test_observer_.get(), FROM_HERE);
453    network_state_handler_.reset();
454    DBusThreadManager::Shutdown();
455  }
456
457  void SuccessCallback(const std::string& callback_name) {
458    success_callback_name_ = callback_name;
459  }
460
461  void GetPropertiesCallback(const std::string& service_path,
462                             const base::DictionaryValue& dictionary) {
463    get_properties_path_ = service_path;
464    get_properties_.reset(dictionary.DeepCopy());
465  }
466
467  void CreateConfigurationCallback(const std::string& service_path) {
468    create_service_path_ = service_path;
469  }
470
471 protected:
472  bool GetServiceStringProperty(const std::string& service_path,
473                                const std::string& key,
474                                std::string* result) {
475    ShillServiceClient::TestInterface* service_test =
476        DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
477    const base::DictionaryValue* properties =
478        service_test->GetServiceProperties(service_path);
479    if (properties && properties->GetStringWithoutPathExpansion(key, result))
480      return true;
481    return false;
482  }
483
484  bool GetReceivedStringProperty(const std::string& service_path,
485                                 const std::string& key,
486                                 std::string* result) {
487    if (get_properties_path_ != service_path)
488      return false;
489    if (get_properties_ &&
490        get_properties_->GetStringWithoutPathExpansion(key, result))
491      return true;
492    return false;
493  }
494
495  scoped_ptr<NetworkStateHandler> network_state_handler_;
496  scoped_ptr<NetworkConfigurationHandler> network_configuration_handler_;
497  scoped_ptr<TestObserver> test_observer_;
498  base::MessageLoopForUI message_loop_;
499  std::string success_callback_name_;
500  std::string get_properties_path_;
501  scoped_ptr<base::DictionaryValue> get_properties_;
502  std::string create_service_path_;
503};
504
505TEST_F(NetworkConfigurationHandlerStubTest, StubSetAndClearProperties) {
506  // TODO(stevenjb): Remove dependency on default Stub service.
507  const std::string service_path("/service/wifi1");
508  const std::string test_identity("test_identity");
509  const std::string test_passphrase("test_passphrase");
510
511  // Set Properties
512  base::DictionaryValue properties_to_set;
513  properties_to_set.SetStringWithoutPathExpansion(
514      shill::kIdentityProperty, test_identity);
515  properties_to_set.SetStringWithoutPathExpansion(
516      shill::kPassphraseProperty, test_passphrase);
517  network_configuration_handler_->SetProperties(
518      service_path,
519      properties_to_set,
520      base::Bind(
521          &NetworkConfigurationHandlerStubTest::SuccessCallback,
522          base::Unretained(this), "SetProperties"),
523      base::Bind(&ErrorCallback, false, service_path));
524  message_loop_.RunUntilIdle();
525
526  EXPECT_EQ("SetProperties", success_callback_name_);
527  std::string identity, passphrase;
528  EXPECT_TRUE(GetServiceStringProperty(
529      service_path, shill::kIdentityProperty, &identity));
530  EXPECT_TRUE(GetServiceStringProperty(
531      service_path, shill::kPassphraseProperty, &passphrase));
532  EXPECT_EQ(test_identity, identity);
533  EXPECT_EQ(test_passphrase, passphrase);
534  EXPECT_EQ(1, test_observer_->PropertyUpdatesForService(service_path));
535
536  // Clear Properties
537  std::vector<std::string> properties_to_clear;
538  properties_to_clear.push_back(shill::kIdentityProperty);
539  properties_to_clear.push_back(shill::kPassphraseProperty);
540  network_configuration_handler_->ClearProperties(
541      service_path,
542      properties_to_clear,
543      base::Bind(
544          &NetworkConfigurationHandlerStubTest::SuccessCallback,
545          base::Unretained(this), "ClearProperties"),
546      base::Bind(&ErrorCallback, false, service_path));
547  message_loop_.RunUntilIdle();
548
549  EXPECT_EQ("ClearProperties", success_callback_name_);
550  EXPECT_FALSE(GetServiceStringProperty(
551      service_path, shill::kIdentityProperty, &identity));
552  EXPECT_FALSE(GetServiceStringProperty(
553      service_path, shill::kIdentityProperty, &passphrase));
554  EXPECT_EQ(2, test_observer_->PropertyUpdatesForService(service_path));
555}
556
557TEST_F(NetworkConfigurationHandlerStubTest, StubGetNameFromWifiHex) {
558  // TODO(stevenjb): Remove dependency on default Stub service.
559  const std::string service_path("/service/wifi1");
560  std::string wifi_hex = "5468697320697320484558205353494421";
561  std::string expected_name = "This is HEX SSID!";
562
563  // Set Properties
564  base::DictionaryValue properties_to_set;
565  properties_to_set.SetStringWithoutPathExpansion(
566      shill::kWifiHexSsid, wifi_hex);
567  network_configuration_handler_->SetProperties(
568      service_path,
569      properties_to_set,
570      base::Bind(&base::DoNothing),
571      base::Bind(&ErrorCallback, false, service_path));
572  message_loop_.RunUntilIdle();
573  std::string wifi_hex_result;
574  EXPECT_TRUE(GetServiceStringProperty(
575      service_path, shill::kWifiHexSsid, &wifi_hex_result));
576  EXPECT_EQ(wifi_hex, wifi_hex_result);
577
578  // Get Properties
579  network_configuration_handler_->GetProperties(
580      service_path,
581      base::Bind(&NetworkConfigurationHandlerStubTest::GetPropertiesCallback,
582                 base::Unretained(this)),
583      base::Bind(&ErrorCallback, false, service_path));
584  message_loop_.RunUntilIdle();
585
586  EXPECT_EQ(service_path, get_properties_path_);
587  std::string name_result;
588  EXPECT_TRUE(GetReceivedStringProperty(
589      service_path, shill::kNameProperty, &name_result));
590  EXPECT_EQ(expected_name, name_result);
591}
592
593TEST_F(NetworkConfigurationHandlerStubTest, StubCreateConfiguration) {
594  const std::string service_path("/service/test_wifi");
595  base::DictionaryValue properties;
596  shill_property_util::SetSSID(service_path, &properties);
597  properties.SetStringWithoutPathExpansion(shill::kNameProperty, service_path);
598  properties.SetStringWithoutPathExpansion(shill::kGuidProperty, service_path);
599  properties.SetStringWithoutPathExpansion(
600      shill::kTypeProperty, shill::kTypeWifi);
601  properties.SetStringWithoutPathExpansion(
602      shill::kStateProperty, shill::kStateIdle);
603  properties.SetStringWithoutPathExpansion(
604      shill::kProfileProperty, NetworkProfileHandler::GetSharedProfilePath());
605
606  network_configuration_handler_->CreateConfiguration(
607      properties,
608      base::Bind(
609          &NetworkConfigurationHandlerStubTest::CreateConfigurationCallback,
610          base::Unretained(this)),
611      base::Bind(&ErrorCallback, false, service_path));
612  message_loop_.RunUntilIdle();
613
614  EXPECT_FALSE(create_service_path_.empty());
615
616  std::string guid;
617  EXPECT_TRUE(GetServiceStringProperty(
618      create_service_path_, shill::kGuidProperty, &guid));
619  EXPECT_EQ(service_path, guid);
620
621  std::string actual_profile;
622  EXPECT_TRUE(GetServiceStringProperty(
623      create_service_path_, shill::kProfileProperty, &actual_profile));
624  EXPECT_EQ(NetworkProfileHandler::GetSharedProfilePath(), actual_profile);
625}
626
627}  // namespace chromeos
628