shill_property_handler_unittest.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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 "chromeos/network/shill_property_handler.h"
6
7#include <map>
8#include <set>
9#include <string>
10
11#include "base/bind.h"
12#include "base/memory/scoped_ptr.h"
13#include "base/message_loop.h"
14#include "base/values.h"
15#include "chromeos/dbus/dbus_thread_manager.h"
16#include "chromeos/dbus/shill_device_client.h"
17#include "chromeos/dbus/shill_manager_client.h"
18#include "chromeos/dbus/shill_service_client.h"
19#include "dbus/object_path.h"
20#include "testing/gtest/include/gtest/gtest.h"
21#include "third_party/cros_system_api/dbus/service_constants.h"
22
23namespace chromeos {
24
25namespace {
26
27void ErrorCallbackFunction(const std::string& error_name,
28                           const std::string& error_message) {
29  LOG(ERROR) << "Shill Error: " << error_name << " : " << error_message;
30}
31
32class TestListener : public internal::ShillPropertyHandler::Listener {
33 public:
34  TestListener() : manager_updates_(0), errors_(0) {
35  }
36
37  virtual void UpdateManagedList(ManagedState::ManagedType type,
38                                 const base::ListValue& entries) OVERRIDE {
39    UpdateEntries(GetTypeString(type), entries);
40  }
41
42  virtual void UpdateAvailableTechnologies(
43      const base::ListValue& technologies) OVERRIDE {
44    UpdateEntries(flimflam::kAvailableTechnologiesProperty, technologies);
45  }
46
47  virtual void UpdateEnabledTechnologies(
48      const base::ListValue& technologies) OVERRIDE {
49    UpdateEntries(flimflam::kEnabledTechnologiesProperty, technologies);
50  }
51
52  virtual void UpdateManagedStateProperties(
53      ManagedState::ManagedType type,
54      const std::string& path,
55      const base::DictionaryValue& properties) OVERRIDE {
56    AddPropertyUpdate(GetTypeString(type), path);
57  }
58
59  virtual void UpdateNetworkServiceProperty(
60      const std::string& service_path,
61      const std::string& key,
62      const base::Value& value) OVERRIDE {
63    AddPropertyUpdate(flimflam::kServicesProperty, service_path);
64  }
65
66  virtual void ManagerPropertyChanged() OVERRIDE {
67    ++manager_updates_;
68  }
69
70  virtual void UpdateNetworkServiceIPAddress(
71      const std::string& service_path,
72      const std::string& ip_address) OVERRIDE {
73    AddPropertyUpdate(flimflam::kServicesProperty, service_path);
74  }
75
76  virtual void ManagedStateListChanged(
77      ManagedState::ManagedType type) OVERRIDE {
78    AddStateListUpdate(GetTypeString(type));
79  }
80
81  std::vector<std::string>& entries(const std::string& type) {
82    return entries_[type];
83  }
84  std::map<std::string, int>& property_updates(const std::string& type) {
85    return property_updates_[type];
86  }
87  int list_updates(const std::string& type) { return list_updates_[type]; }
88  int manager_updates() { return manager_updates_; }
89  int errors() { return errors_; }
90
91 private:
92  std::string GetTypeString(ManagedState::ManagedType type) {
93    if (type == ManagedState::MANAGED_TYPE_NETWORK) {
94      return flimflam::kServicesProperty;
95    } else if (type == ManagedState::MANAGED_TYPE_DEVICE) {
96      return flimflam::kDevicesProperty;
97    }
98    LOG(ERROR) << "UpdateManagedList called with unrecognized type: " << type;
99    ++errors_;
100    return std::string();
101  }
102
103  void UpdateEntries(const std::string& type, const base::ListValue& entries) {
104    if (type.empty())
105      return;
106    entries_[type].clear();
107    for (base::ListValue::const_iterator iter = entries.begin();
108         iter != entries.end(); ++iter) {
109      std::string path;
110      if ((*iter)->GetAsString(&path))
111        entries_[type].push_back(path);
112    }
113  }
114
115  void AddPropertyUpdate(const std::string& type, const std::string& path) {
116    if (type.empty())
117      return;
118    property_updates(type)[path] += 1;
119  }
120
121  void AddStateListUpdate(const std::string& type) {
122    if (type.empty())
123      return;
124    list_updates_[type] += 1;
125  }
126
127  // Map of list-type -> paths
128  std::map<std::string, std::vector<std::string> > entries_;
129  // Map of list-type -> map of paths -> update counts
130  std::map<std::string, std::map<std::string, int> > property_updates_;
131  // Map of list-type -> list update counts
132  std::map<std::string, int > list_updates_;
133  int manager_updates_;
134  int errors_;
135};
136
137}  // namespace
138
139class ShillPropertyHandlerTest : public testing::Test {
140 public:
141  ShillPropertyHandlerTest()
142      : manager_test_(NULL),
143        device_test_(NULL),
144        service_test_(NULL) {
145  }
146  virtual ~ShillPropertyHandlerTest() {
147  }
148
149  virtual void SetUp() OVERRIDE {
150    // Initialize DBusThreadManager with a stub implementation.
151    DBusThreadManager::InitializeWithStub();
152    // Get the test interface for manager / device / service and clear the
153    // default stub properties.
154    manager_test_ =
155        DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface();
156    ASSERT_TRUE(manager_test_);
157    device_test_ =
158        DBusThreadManager::Get()->GetShillDeviceClient()->GetTestInterface();
159    ASSERT_TRUE(device_test_);
160    service_test_ =
161        DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
162    ASSERT_TRUE(service_test_);
163  }
164
165  virtual void TearDown() OVERRIDE {
166    shill_property_handler_.reset();
167    listener_.reset();
168    DBusThreadManager::Shutdown();
169  }
170
171  void AddDevice(const std::string& type, const std::string& id) {
172    ASSERT_TRUE(IsValidType(type));
173    manager_test_->AddDevice(id);
174    device_test_->AddDevice(id, type, std::string("/device/" + id), "/stub");
175  }
176
177  void RemoveDevice(const std::string& id) {
178    manager_test_->RemoveDevice(id);
179    device_test_->RemoveDevice(id);
180  }
181
182  void AddService(const std::string& type,
183                  const std::string& id,
184                  const std::string& state,
185                  bool add_to_watch_list) {
186    ASSERT_TRUE(IsValidType(type));
187    manager_test_->AddService(id, add_to_watch_list);
188    service_test_->AddService(id, id, type, state);
189  }
190
191  void RemoveService(const std::string& id) {
192    manager_test_->RemoveService(id);
193    service_test_->RemoveService(id);
194  }
195
196  // Call this after any initial Shill client setup
197  void SetupShillPropertyHandler() {
198    listener_.reset(new TestListener);
199    shill_property_handler_.reset(
200        new internal::ShillPropertyHandler(listener_.get()));
201    shill_property_handler_->Init();
202  }
203
204  bool IsValidType(const std::string& type) {
205    return (type == flimflam::kTypeEthernet ||
206            type == flimflam::kTypeWifi ||
207            type == flimflam::kTypeWimax ||
208            type == flimflam::kTypeBluetooth ||
209            type == flimflam::kTypeCellular ||
210            type == flimflam::kTypeVPN);
211  }
212
213 protected:
214  MessageLoopForUI message_loop_;
215  scoped_ptr<TestListener> listener_;
216  scoped_ptr<internal::ShillPropertyHandler> shill_property_handler_;
217  ShillManagerClient::TestInterface* manager_test_;
218  ShillDeviceClient::TestInterface* device_test_;
219  ShillServiceClient::TestInterface* service_test_;
220
221 private:
222  DISALLOW_COPY_AND_ASSIGN(ShillPropertyHandlerTest);
223};
224
225TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerStub) {
226  SetupShillPropertyHandler();
227  message_loop_.RunUntilIdle();
228  EXPECT_EQ(1, listener_->manager_updates());
229  // ShillManagerClient default stub entries are in shill_manager_client.cc.
230  // TODO(stevenjb): Eliminate default stub entries and add them explicitly.
231  const size_t kNumShillManagerClientStubImplTechnologies = 3;
232  EXPECT_EQ(kNumShillManagerClientStubImplTechnologies,
233            listener_->entries(
234                flimflam::kAvailableTechnologiesProperty).size());
235  EXPECT_EQ(kNumShillManagerClientStubImplTechnologies,
236            listener_->entries(
237                flimflam::kEnabledTechnologiesProperty).size());
238  const size_t kNumShillManagerClientStubImplDevices = 2;
239  EXPECT_EQ(kNumShillManagerClientStubImplDevices,
240            listener_->entries(flimflam::kDevicesProperty).size());
241  const size_t kNumShillManagerClientStubImplServices = 4;
242  EXPECT_EQ(kNumShillManagerClientStubImplServices,
243            listener_->entries(flimflam::kServicesProperty).size());
244
245  EXPECT_EQ(0, listener_->errors());
246}
247
248TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerTechnologyChanged) {
249  // This relies on the stub dbus implementations for ShillManagerClient,
250  SetupShillPropertyHandler();
251  message_loop_.RunUntilIdle();
252  EXPECT_EQ(1, listener_->manager_updates());
253  // Add a disabled technology.
254  manager_test_->AddTechnology(flimflam::kTypeWimax, false);
255  message_loop_.RunUntilIdle();
256  EXPECT_EQ(2, listener_->manager_updates());
257  const size_t kNumShillManagerClientStubImplTechnologies = 3;
258  EXPECT_EQ(kNumShillManagerClientStubImplTechnologies + 1,
259            listener_->entries(
260                flimflam::kAvailableTechnologiesProperty).size());
261  EXPECT_EQ(kNumShillManagerClientStubImplTechnologies,
262            listener_->entries(
263                flimflam::kEnabledTechnologiesProperty).size());
264  // Enable the technology.
265  DBusThreadManager::Get()->GetShillManagerClient()->EnableTechnology(
266      flimflam::kTypeWimax,
267      base::Bind(&base::DoNothing), base::Bind(&ErrorCallbackFunction));
268  message_loop_.RunUntilIdle();
269  EXPECT_EQ(3, listener_->manager_updates());
270  EXPECT_EQ(kNumShillManagerClientStubImplTechnologies + 1,
271            listener_->entries(
272                flimflam::kEnabledTechnologiesProperty).size());
273
274  EXPECT_EQ(0, listener_->errors());
275}
276
277TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerDevicePropertyChanged) {
278  // This relies on the stub dbus implementations for ShillManagerClient,
279  SetupShillPropertyHandler();
280  message_loop_.RunUntilIdle();
281  EXPECT_EQ(1, listener_->manager_updates());
282  EXPECT_EQ(1, listener_->list_updates(flimflam::kDevicesProperty));
283  const size_t kNumShillManagerClientStubImplDevices = 2;
284  EXPECT_EQ(kNumShillManagerClientStubImplDevices,
285            listener_->entries(flimflam::kDevicesProperty).size());
286  // Add a device.
287  const std::string kTestDevicePath("test_wifi_device1");
288  AddDevice(flimflam::kTypeWifi, kTestDevicePath);
289  message_loop_.RunUntilIdle();
290  EXPECT_EQ(1, listener_->manager_updates());  // No new manager updates.
291  EXPECT_EQ(2, listener_->list_updates(flimflam::kDevicesProperty));
292  EXPECT_EQ(kNumShillManagerClientStubImplDevices + 1,
293            listener_->entries(flimflam::kDevicesProperty).size());
294  // Device changes are not observed.
295  // Remove a device
296  RemoveDevice(kTestDevicePath);
297  message_loop_.RunUntilIdle();
298  EXPECT_EQ(3, listener_->list_updates(flimflam::kDevicesProperty));
299  EXPECT_EQ(kNumShillManagerClientStubImplDevices,
300            listener_->entries(flimflam::kDevicesProperty).size());
301
302  EXPECT_EQ(0, listener_->errors());
303}
304
305TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerServicePropertyChanged) {
306  // This relies on the stub dbus implementations for ShillManagerClient,
307  SetupShillPropertyHandler();
308  message_loop_.RunUntilIdle();
309  EXPECT_EQ(1, listener_->manager_updates());
310  EXPECT_EQ(1, listener_->list_updates(flimflam::kServicesProperty));
311  const size_t kNumShillManagerClientStubImplServices = 4;
312  EXPECT_EQ(kNumShillManagerClientStubImplServices,
313            listener_->entries(flimflam::kServicesProperty).size());
314
315  // Add an unwatched service.
316  const std::string kTestServicePath("test_wifi_service1");
317  AddService(flimflam::kTypeWifi, kTestServicePath,
318             flimflam::kStateIdle, false);
319  message_loop_.RunUntilIdle();
320  EXPECT_EQ(1, listener_->manager_updates());  // No new manager updates.
321  EXPECT_EQ(2, listener_->list_updates(flimflam::kServicesProperty));
322  EXPECT_EQ(kNumShillManagerClientStubImplServices + 1,
323            listener_->entries(flimflam::kServicesProperty).size());
324  // Change a property.
325  base::FundamentalValue scan_interval(3);
326  DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
327      dbus::ObjectPath(kTestServicePath),
328      flimflam::kScanIntervalProperty,
329      scan_interval,
330      base::Bind(&base::DoNothing), base::Bind(&ErrorCallbackFunction));
331  message_loop_.RunUntilIdle();
332  // Property change should NOT trigger an update.
333  EXPECT_EQ(0, listener_->
334            property_updates(flimflam::kServicesProperty)[kTestServicePath]);
335
336  // Add the existing service to the watch list.
337  AddService(flimflam::kTypeWifi, kTestServicePath,
338             flimflam::kStateIdle, true);
339  message_loop_.RunUntilIdle();
340  // No new updates or services:
341  EXPECT_EQ(1, listener_->manager_updates());
342  EXPECT_EQ(2, listener_->list_updates(flimflam::kServicesProperty));
343  EXPECT_EQ(kNumShillManagerClientStubImplServices + 1,
344            listener_->entries(flimflam::kServicesProperty).size());
345  // Change a property.
346  DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
347      dbus::ObjectPath(kTestServicePath),
348      flimflam::kScanIntervalProperty,
349      scan_interval,
350      base::Bind(&base::DoNothing), base::Bind(&ErrorCallbackFunction));
351  message_loop_.RunUntilIdle();
352  // Property change SHOULD trigger an update.
353  EXPECT_EQ(1, listener_->
354            property_updates(flimflam::kServicesProperty)[kTestServicePath]);
355
356  // Remove a service
357  RemoveService(kTestServicePath);
358  message_loop_.RunUntilIdle();
359  EXPECT_EQ(3, listener_->list_updates(flimflam::kServicesProperty));
360  EXPECT_EQ(kNumShillManagerClientStubImplServices,
361            listener_->entries(flimflam::kServicesProperty).size());
362
363  EXPECT_EQ(0, listener_->errors());
364}
365
366// TODO(stevenjb): Test IP Configs.
367
368}  // namespace chromeos
369