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