blob: 01fb282a5a36afd177314ab1c8fb8c1522d4153d [file] [log] [blame]
[email protected]3c8bd112012-11-07 10:14:591// 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"
[email protected]362fb222013-04-02 23:24:2817#include "chromeos/dbus/shill_ipconfig_client.h"
[email protected]3c8bd112012-11-07 10:14:5918#include "chromeos/dbus/shill_manager_client.h"
19#include "chromeos/dbus/shill_service_client.h"
20#include "dbus/object_path.h"
21#include "testing/gtest/include/gtest/gtest.h"
22#include "third_party/cros_system_api/dbus/service_constants.h"
23
24namespace chromeos {
25
26namespace {
27
[email protected]362fb222013-04-02 23:24:2828void DoNothingWithCallStatus(DBusMethodCallStatus call_status) {
29}
30
[email protected]3c8bd112012-11-07 10:14:5931void ErrorCallbackFunction(const std::string& error_name,
32 const std::string& error_message) {
33 LOG(ERROR) << "Shill Error: " << error_name << " : " << error_message;
34}
35
36class TestListener : public internal::ShillPropertyHandler::Listener {
37 public:
38 TestListener() : manager_updates_(0), errors_(0) {
39 }
40
41 virtual void UpdateManagedList(ManagedState::ManagedType type,
42 const base::ListValue& entries) OVERRIDE {
43 UpdateEntries(GetTypeString(type), entries);
44 }
45
[email protected]3c8bd112012-11-07 10:14:5946 virtual void UpdateManagedStateProperties(
47 ManagedState::ManagedType type,
48 const std::string& path,
49 const base::DictionaryValue& properties) OVERRIDE {
50 AddPropertyUpdate(GetTypeString(type), path);
51 }
52
[email protected]3c8bd112012-11-07 10:14:5953 virtual void UpdateNetworkServiceProperty(
54 const std::string& service_path,
55 const std::string& key,
56 const base::Value& value) OVERRIDE {
57 AddPropertyUpdate(flimflam::kServicesProperty, service_path);
58 }
59
[email protected]b16d79d72013-02-07 08:14:4660 virtual void UpdateDeviceProperty(
61 const std::string& device_path,
62 const std::string& key,
63 const base::Value& value) OVERRIDE {
64 AddPropertyUpdate(flimflam::kDevicesProperty, device_path);
65 }
66
[email protected]3c8bd112012-11-07 10:14:5967 virtual void ManagerPropertyChanged() OVERRIDE {
68 ++manager_updates_;
69 }
70
[email protected]3c8bd112012-11-07 10:14:5971 virtual void ManagedStateListChanged(
72 ManagedState::ManagedType type) OVERRIDE {
73 AddStateListUpdate(GetTypeString(type));
74 }
75
76 std::vector<std::string>& entries(const std::string& type) {
77 return entries_[type];
78 }
79 std::map<std::string, int>& property_updates(const std::string& type) {
80 return property_updates_[type];
81 }
82 int list_updates(const std::string& type) { return list_updates_[type]; }
83 int manager_updates() { return manager_updates_; }
84 int errors() { return errors_; }
85
86 private:
87 std::string GetTypeString(ManagedState::ManagedType type) {
88 if (type == ManagedState::MANAGED_TYPE_NETWORK) {
89 return flimflam::kServicesProperty;
90 } else if (type == ManagedState::MANAGED_TYPE_DEVICE) {
91 return flimflam::kDevicesProperty;
92 }
93 LOG(ERROR) << "UpdateManagedList called with unrecognized type: " << type;
94 ++errors_;
95 return std::string();
96 }
97
98 void UpdateEntries(const std::string& type, const base::ListValue& entries) {
99 if (type.empty())
100 return;
101 entries_[type].clear();
102 for (base::ListValue::const_iterator iter = entries.begin();
103 iter != entries.end(); ++iter) {
104 std::string path;
105 if ((*iter)->GetAsString(&path))
106 entries_[type].push_back(path);
107 }
108 }
109
110 void AddPropertyUpdate(const std::string& type, const std::string& path) {
111 if (type.empty())
112 return;
113 property_updates(type)[path] += 1;
114 }
115
116 void AddStateListUpdate(const std::string& type) {
117 if (type.empty())
118 return;
119 list_updates_[type] += 1;
120 }
121
122 // Map of list-type -> paths
123 std::map<std::string, std::vector<std::string> > entries_;
124 // Map of list-type -> map of paths -> update counts
125 std::map<std::string, std::map<std::string, int> > property_updates_;
126 // Map of list-type -> list update counts
127 std::map<std::string, int > list_updates_;
128 int manager_updates_;
129 int errors_;
130};
131
132} // namespace
133
134class ShillPropertyHandlerTest : public testing::Test {
135 public:
136 ShillPropertyHandlerTest()
137 : manager_test_(NULL),
138 device_test_(NULL),
139 service_test_(NULL) {
140 }
141 virtual ~ShillPropertyHandlerTest() {
142 }
143
144 virtual void SetUp() OVERRIDE {
145 // Initialize DBusThreadManager with a stub implementation.
146 DBusThreadManager::InitializeWithStub();
147 // Get the test interface for manager / device / service and clear the
148 // default stub properties.
149 manager_test_ =
150 DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface();
151 ASSERT_TRUE(manager_test_);
152 device_test_ =
153 DBusThreadManager::Get()->GetShillDeviceClient()->GetTestInterface();
154 ASSERT_TRUE(device_test_);
155 service_test_ =
156 DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
157 ASSERT_TRUE(service_test_);
[email protected]362fb222013-04-02 23:24:28158 SetupShillPropertyHandler();
159 message_loop_.RunUntilIdle();
[email protected]3c8bd112012-11-07 10:14:59160 }
161
162 virtual void TearDown() OVERRIDE {
163 shill_property_handler_.reset();
164 listener_.reset();
165 DBusThreadManager::Shutdown();
166 }
167
168 void AddDevice(const std::string& type, const std::string& id) {
169 ASSERT_TRUE(IsValidType(type));
[email protected]b7c377e2013-01-15 10:00:39170 device_test_->AddDevice(id, type, std::string("/device/" + id));
[email protected]3c8bd112012-11-07 10:14:59171 }
172
173 void RemoveDevice(const std::string& id) {
[email protected]3c8bd112012-11-07 10:14:59174 device_test_->RemoveDevice(id);
175 }
176
177 void AddService(const std::string& type,
178 const std::string& id,
179 const std::string& state,
180 bool add_to_watch_list) {
181 ASSERT_TRUE(IsValidType(type));
[email protected]362fb222013-04-02 23:24:28182 service_test_->AddService(id, id, type, state,
183 add_to_watch_list);
184 }
185
186 void AddServiceWithIPConfig(const std::string& type,
187 const std::string& id,
188 const std::string& state,
189 const std::string& ipconfig_path,
190 bool add_to_watch_list) {
191 ASSERT_TRUE(IsValidType(type));
192 service_test_->AddServiceWithIPConfig(id, id, type, state,
193 ipconfig_path, add_to_watch_list);
[email protected]3c8bd112012-11-07 10:14:59194 }
195
196 void RemoveService(const std::string& id) {
[email protected]3c8bd112012-11-07 10:14:59197 service_test_->RemoveService(id);
198 }
199
200 // Call this after any initial Shill client setup
201 void SetupShillPropertyHandler() {
[email protected]1c86dbf2013-03-06 17:42:26202 SetupDefaultShillState();
[email protected]3c8bd112012-11-07 10:14:59203 listener_.reset(new TestListener);
204 shill_property_handler_.reset(
205 new internal::ShillPropertyHandler(listener_.get()));
206 shill_property_handler_->Init();
207 }
208
209 bool IsValidType(const std::string& type) {
210 return (type == flimflam::kTypeEthernet ||
211 type == flimflam::kTypeWifi ||
212 type == flimflam::kTypeWimax ||
213 type == flimflam::kTypeBluetooth ||
214 type == flimflam::kTypeCellular ||
215 type == flimflam::kTypeVPN);
216 }
217
218 protected:
[email protected]1c86dbf2013-03-06 17:42:26219 void SetupDefaultShillState() {
220 message_loop_.RunUntilIdle(); // Process any pending updates
221 device_test_->ClearDevices();
222 AddDevice(flimflam::kTypeWifi, "stub_wifi_device1");
223 AddDevice(flimflam::kTypeCellular, "stub_cellular_device1");
224 service_test_->ClearServices();
225 const bool add_to_watchlist = true;
226 AddService(flimflam::kTypeEthernet, "stub_ethernet",
227 flimflam::kStateOnline, add_to_watchlist);
228 AddService(flimflam::kTypeWifi, "stub_wifi1",
229 flimflam::kStateOnline, add_to_watchlist);
230 AddService(flimflam::kTypeWifi, "stub_wifi2",
231 flimflam::kStateIdle, add_to_watchlist);
232 AddService(flimflam::kTypeCellular, "stub_cellular1",
233 flimflam::kStateIdle, add_to_watchlist);
234 }
235
[email protected]3c8bd112012-11-07 10:14:59236 MessageLoopForUI message_loop_;
237 scoped_ptr<TestListener> listener_;
238 scoped_ptr<internal::ShillPropertyHandler> shill_property_handler_;
239 ShillManagerClient::TestInterface* manager_test_;
240 ShillDeviceClient::TestInterface* device_test_;
241 ShillServiceClient::TestInterface* service_test_;
242
243 private:
244 DISALLOW_COPY_AND_ASSIGN(ShillPropertyHandlerTest);
245};
246
247TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerStub) {
[email protected]3c8bd112012-11-07 10:14:59248 EXPECT_EQ(1, listener_->manager_updates());
[email protected]b16d79d72013-02-07 08:14:46249 EXPECT_TRUE(shill_property_handler_->TechnologyAvailable(
250 flimflam::kTypeWifi));
251 EXPECT_TRUE(shill_property_handler_->TechnologyEnabled(
252 flimflam::kTypeWifi));
[email protected]3c8bd112012-11-07 10:14:59253 const size_t kNumShillManagerClientStubImplDevices = 2;
254 EXPECT_EQ(kNumShillManagerClientStubImplDevices,
255 listener_->entries(flimflam::kDevicesProperty).size());
256 const size_t kNumShillManagerClientStubImplServices = 4;
257 EXPECT_EQ(kNumShillManagerClientStubImplServices,
258 listener_->entries(flimflam::kServicesProperty).size());
259
260 EXPECT_EQ(0, listener_->errors());
261}
262
263TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerTechnologyChanged) {
[email protected]3c8bd112012-11-07 10:14:59264 EXPECT_EQ(1, listener_->manager_updates());
265 // Add a disabled technology.
266 manager_test_->AddTechnology(flimflam::kTypeWimax, false);
267 message_loop_.RunUntilIdle();
268 EXPECT_EQ(2, listener_->manager_updates());
[email protected]b16d79d72013-02-07 08:14:46269 EXPECT_TRUE(shill_property_handler_->TechnologyAvailable(
270 flimflam::kTypeWimax));
271 EXPECT_FALSE(shill_property_handler_->TechnologyEnabled(
272 flimflam::kTypeWimax));
273
[email protected]3c8bd112012-11-07 10:14:59274 // Enable the technology.
275 DBusThreadManager::Get()->GetShillManagerClient()->EnableTechnology(
276 flimflam::kTypeWimax,
277 base::Bind(&base::DoNothing), base::Bind(&ErrorCallbackFunction));
278 message_loop_.RunUntilIdle();
279 EXPECT_EQ(3, listener_->manager_updates());
[email protected]b16d79d72013-02-07 08:14:46280 EXPECT_TRUE(shill_property_handler_->TechnologyEnabled(
281 flimflam::kTypeWimax));
[email protected]3c8bd112012-11-07 10:14:59282
283 EXPECT_EQ(0, listener_->errors());
284}
285
286TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerDevicePropertyChanged) {
[email protected]3c8bd112012-11-07 10:14:59287 EXPECT_EQ(1, listener_->manager_updates());
288 EXPECT_EQ(1, listener_->list_updates(flimflam::kDevicesProperty));
289 const size_t kNumShillManagerClientStubImplDevices = 2;
290 EXPECT_EQ(kNumShillManagerClientStubImplDevices,
291 listener_->entries(flimflam::kDevicesProperty).size());
292 // Add a device.
293 const std::string kTestDevicePath("test_wifi_device1");
294 AddDevice(flimflam::kTypeWifi, kTestDevicePath);
295 message_loop_.RunUntilIdle();
296 EXPECT_EQ(1, listener_->manager_updates()); // No new manager updates.
297 EXPECT_EQ(2, listener_->list_updates(flimflam::kDevicesProperty));
298 EXPECT_EQ(kNumShillManagerClientStubImplDevices + 1,
299 listener_->entries(flimflam::kDevicesProperty).size());
300 // Device changes are not observed.
301 // Remove a device
302 RemoveDevice(kTestDevicePath);
303 message_loop_.RunUntilIdle();
304 EXPECT_EQ(3, listener_->list_updates(flimflam::kDevicesProperty));
305 EXPECT_EQ(kNumShillManagerClientStubImplDevices,
306 listener_->entries(flimflam::kDevicesProperty).size());
307
308 EXPECT_EQ(0, listener_->errors());
309}
310
311TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerServicePropertyChanged) {
[email protected]3c8bd112012-11-07 10:14:59312 EXPECT_EQ(1, listener_->manager_updates());
313 EXPECT_EQ(1, listener_->list_updates(flimflam::kServicesProperty));
314 const size_t kNumShillManagerClientStubImplServices = 4;
315 EXPECT_EQ(kNumShillManagerClientStubImplServices,
316 listener_->entries(flimflam::kServicesProperty).size());
317
318 // Add an unwatched service.
319 const std::string kTestServicePath("test_wifi_service1");
320 AddService(flimflam::kTypeWifi, kTestServicePath,
321 flimflam::kStateIdle, false);
322 message_loop_.RunUntilIdle();
323 EXPECT_EQ(1, listener_->manager_updates()); // No new manager updates.
[email protected]b16d79d72013-02-07 08:14:46324 // Only watched services trigger a service list update.
325 EXPECT_EQ(1, listener_->list_updates(flimflam::kServicesProperty));
[email protected]3c8bd112012-11-07 10:14:59326 EXPECT_EQ(kNumShillManagerClientStubImplServices + 1,
327 listener_->entries(flimflam::kServicesProperty).size());
328 // Change a property.
329 base::FundamentalValue scan_interval(3);
330 DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
331 dbus::ObjectPath(kTestServicePath),
332 flimflam::kScanIntervalProperty,
333 scan_interval,
334 base::Bind(&base::DoNothing), base::Bind(&ErrorCallbackFunction));
335 message_loop_.RunUntilIdle();
336 // Property change should NOT trigger an update.
337 EXPECT_EQ(0, listener_->
338 property_updates(flimflam::kServicesProperty)[kTestServicePath]);
339
340 // Add the existing service to the watch list.
341 AddService(flimflam::kTypeWifi, kTestServicePath,
342 flimflam::kStateIdle, true);
343 message_loop_.RunUntilIdle();
[email protected]fa6797e2012-11-28 15:15:44344 // Service list update should be received when watch list changes.
[email protected]b16d79d72013-02-07 08:14:46345 EXPECT_EQ(2, listener_->list_updates(flimflam::kServicesProperty));
[email protected]fa6797e2012-11-28 15:15:44346 // Number of services shouldn't change.
[email protected]3c8bd112012-11-07 10:14:59347 EXPECT_EQ(kNumShillManagerClientStubImplServices + 1,
348 listener_->entries(flimflam::kServicesProperty).size());
[email protected]fa6797e2012-11-28 15:15:44349 // Property update should be received when watched service is added.
350 EXPECT_EQ(1, listener_->
351 property_updates(flimflam::kServicesProperty)[kTestServicePath]);
352
[email protected]3c8bd112012-11-07 10:14:59353 // Change a property.
354 DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
355 dbus::ObjectPath(kTestServicePath),
356 flimflam::kScanIntervalProperty,
357 scan_interval,
358 base::Bind(&base::DoNothing), base::Bind(&ErrorCallbackFunction));
359 message_loop_.RunUntilIdle();
[email protected]fa6797e2012-11-28 15:15:44360 // Property change should trigger another update.
361 EXPECT_EQ(2, listener_->
[email protected]3c8bd112012-11-07 10:14:59362 property_updates(flimflam::kServicesProperty)[kTestServicePath]);
363
364 // Remove a service
365 RemoveService(kTestServicePath);
366 message_loop_.RunUntilIdle();
[email protected]b16d79d72013-02-07 08:14:46367 EXPECT_EQ(3, listener_->list_updates(flimflam::kServicesProperty));
[email protected]3c8bd112012-11-07 10:14:59368 EXPECT_EQ(kNumShillManagerClientStubImplServices,
369 listener_->entries(flimflam::kServicesProperty).size());
370
371 EXPECT_EQ(0, listener_->errors());
372}
373
[email protected]362fb222013-04-02 23:24:28374TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerIPConfigPropertyChanged) {
375 // Set the properties for an IP Config object.
376 const std::string kTestIPConfigPath("test_ip_config_path");
377 base::StringValue ip_address("192.168.1.1");
378 DBusThreadManager::Get()->GetShillIPConfigClient()->SetProperty(
379 dbus::ObjectPath(kTestIPConfigPath),
380 flimflam::kAddressProperty,
381 ip_address,
382 base::Bind(&DoNothingWithCallStatus));
383 base::ListValue dns_servers;
384 dns_servers.Append(base::Value::CreateStringValue("192.168.1.100"));
385 dns_servers.Append(base::Value::CreateStringValue("192.168.1.101"));
386 DBusThreadManager::Get()->GetShillIPConfigClient()->SetProperty(
387 dbus::ObjectPath(kTestIPConfigPath),
388 flimflam::kNameServersProperty,
389 dns_servers,
390 base::Bind(&DoNothingWithCallStatus));
391 message_loop_.RunUntilIdle();
392
393 // Add a service with an empty ipconfig and then update
394 // its ipconfig property.
395 const std::string kTestServicePath1("test_wifi_service1");
396 AddService(flimflam::kTypeWifi, kTestServicePath1,
397 flimflam::kStateIdle, true);
398 message_loop_.RunUntilIdle();
399 // This is the initial property update.
400 EXPECT_EQ(1, listener_->
401 property_updates(flimflam::kServicesProperty)[kTestServicePath1]);
402 DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
403 dbus::ObjectPath(kTestServicePath1),
404 shill::kIPConfigProperty,
405 base::StringValue(kTestIPConfigPath),
406 base::Bind(&base::DoNothing), base::Bind(&ErrorCallbackFunction));
407 message_loop_.RunUntilIdle();
408 // IPConfig property change on the service should trigger property updates for
409 // IP Address and DNS.
410 EXPECT_EQ(3, listener_->
411 property_updates(flimflam::kServicesProperty)[kTestServicePath1]);
412
413 // Now, Add a new watched service with the IPConfig already set.
414 const std::string kTestServicePath2("test_wifi_service2");
415 AddServiceWithIPConfig(flimflam::kTypeWifi, kTestServicePath2,
416 flimflam::kStateIdle, kTestIPConfigPath, true);
417 message_loop_.RunUntilIdle();
418 // A watched service with the IPConfig property already set must
419 // trigger property updates for IP Address and DNS when added.
420 EXPECT_EQ(3, listener_->
421 property_updates(flimflam::kServicesProperty)[kTestServicePath2]);
422}
[email protected]3c8bd112012-11-07 10:14:59423
424} // namespace chromeos