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.
5 #include "chromeos/network/shill_property_handler.h"
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_ipconfig_client.h"
18 #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"
28 void DoNothingWithCallStatus(DBusMethodCallStatus call_status
) {
31 void ErrorCallbackFunction(const std::string
& error_name
,
32 const std::string
& error_message
) {
33 LOG(ERROR
) << "Shill Error: " << error_name
<< " : " << error_message
;
36 class TestListener
: public internal::ShillPropertyHandler::Listener
{
38 TestListener() : manager_updates_(0), errors_(0) {
41 virtual void UpdateManagedList(ManagedState::ManagedType type
,
42 const base::ListValue
& entries
) OVERRIDE
{
43 UpdateEntries(GetTypeString(type
), entries
);
46 virtual void UpdateManagedStateProperties(
47 ManagedState::ManagedType type
,
48 const std::string
& path
,
49 const base::DictionaryValue
& properties
) OVERRIDE
{
50 AddPropertyUpdate(GetTypeString(type
), path
);
53 virtual void ProfileListChanged() OVERRIDE
{
56 virtual void UpdateNetworkServiceProperty(
57 const std::string
& service_path
,
58 const std::string
& key
,
59 const base::Value
& value
) OVERRIDE
{
60 AddPropertyUpdate(flimflam::kServicesProperty
, service_path
);
63 virtual void UpdateDeviceProperty(
64 const std::string
& device_path
,
65 const std::string
& key
,
66 const base::Value
& value
) OVERRIDE
{
67 AddPropertyUpdate(flimflam::kDevicesProperty
, device_path
);
70 virtual void ManagerPropertyChanged() OVERRIDE
{
74 virtual void ManagedStateListChanged(
75 ManagedState::ManagedType type
) OVERRIDE
{
76 AddStateListUpdate(GetTypeString(type
));
79 std::vector
<std::string
>& entries(const std::string
& type
) {
80 return entries_
[type
];
82 std::map
<std::string
, int>& property_updates(const std::string
& type
) {
83 return property_updates_
[type
];
85 int list_updates(const std::string
& type
) { return list_updates_
[type
]; }
86 int manager_updates() { return manager_updates_
; }
87 int errors() { return errors_
; }
90 std::string
GetTypeString(ManagedState::ManagedType type
) {
91 if (type
== ManagedState::MANAGED_TYPE_NETWORK
) {
92 return flimflam::kServicesProperty
;
93 } else if (type
== ManagedState::MANAGED_TYPE_DEVICE
) {
94 return flimflam::kDevicesProperty
;
96 LOG(ERROR
) << "UpdateManagedList called with unrecognized type: " << type
;
101 void UpdateEntries(const std::string
& type
, const base::ListValue
& entries
) {
104 entries_
[type
].clear();
105 for (base::ListValue::const_iterator iter
= entries
.begin();
106 iter
!= entries
.end(); ++iter
) {
108 if ((*iter
)->GetAsString(&path
))
109 entries_
[type
].push_back(path
);
113 void AddPropertyUpdate(const std::string
& type
, const std::string
& path
) {
116 property_updates(type
)[path
] += 1;
119 void AddStateListUpdate(const std::string
& type
) {
122 list_updates_
[type
] += 1;
125 // Map of list-type -> paths
126 std::map
<std::string
, std::vector
<std::string
> > entries_
;
127 // Map of list-type -> map of paths -> update counts
128 std::map
<std::string
, std::map
<std::string
, int> > property_updates_
;
129 // Map of list-type -> list update counts
130 std::map
<std::string
, int > list_updates_
;
131 int manager_updates_
;
137 class ShillPropertyHandlerTest
: public testing::Test
{
139 ShillPropertyHandlerTest()
140 : manager_test_(NULL
),
142 service_test_(NULL
) {
144 virtual ~ShillPropertyHandlerTest() {
147 virtual void SetUp() OVERRIDE
{
148 // Initialize DBusThreadManager with a stub implementation.
149 DBusThreadManager::InitializeWithStub();
150 // Get the test interface for manager / device / service and clear the
151 // default stub properties.
153 DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface();
154 ASSERT_TRUE(manager_test_
);
156 DBusThreadManager::Get()->GetShillDeviceClient()->GetTestInterface();
157 ASSERT_TRUE(device_test_
);
159 DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
160 ASSERT_TRUE(service_test_
);
161 SetupShillPropertyHandler();
162 message_loop_
.RunUntilIdle();
165 virtual void TearDown() OVERRIDE
{
166 shill_property_handler_
.reset();
168 DBusThreadManager::Shutdown();
171 void AddDevice(const std::string
& type
, const std::string
& id
) {
172 ASSERT_TRUE(IsValidType(type
));
173 device_test_
->AddDevice(id
, type
, std::string("/device/" + id
));
176 void RemoveDevice(const std::string
& id
) {
177 device_test_
->RemoveDevice(id
);
180 void AddService(const std::string
& type
,
181 const std::string
& id
,
182 const std::string
& state
,
183 bool add_to_watch_list
) {
184 ASSERT_TRUE(IsValidType(type
));
185 service_test_
->AddService(id
, id
, type
, state
,
189 void AddServiceWithIPConfig(const std::string
& type
,
190 const std::string
& id
,
191 const std::string
& state
,
192 const std::string
& ipconfig_path
,
193 bool add_to_watch_list
) {
194 ASSERT_TRUE(IsValidType(type
));
195 service_test_
->AddServiceWithIPConfig(id
, id
, type
, state
,
196 ipconfig_path
, add_to_watch_list
);
199 void RemoveService(const std::string
& id
) {
200 service_test_
->RemoveService(id
);
203 // Call this after any initial Shill client setup
204 void SetupShillPropertyHandler() {
205 SetupDefaultShillState();
206 listener_
.reset(new TestListener
);
207 shill_property_handler_
.reset(
208 new internal::ShillPropertyHandler(listener_
.get()));
209 shill_property_handler_
->Init();
212 bool IsValidType(const std::string
& type
) {
213 return (type
== flimflam::kTypeEthernet
||
214 type
== flimflam::kTypeWifi
||
215 type
== flimflam::kTypeWimax
||
216 type
== flimflam::kTypeBluetooth
||
217 type
== flimflam::kTypeCellular
||
218 type
== flimflam::kTypeVPN
);
222 void SetupDefaultShillState() {
223 message_loop_
.RunUntilIdle(); // Process any pending updates
224 device_test_
->ClearDevices();
225 AddDevice(flimflam::kTypeWifi
, "stub_wifi_device1");
226 AddDevice(flimflam::kTypeCellular
, "stub_cellular_device1");
227 service_test_
->ClearServices();
228 const bool add_to_watchlist
= true;
229 AddService(flimflam::kTypeEthernet
, "stub_ethernet",
230 flimflam::kStateOnline
, add_to_watchlist
);
231 AddService(flimflam::kTypeWifi
, "stub_wifi1",
232 flimflam::kStateOnline
, add_to_watchlist
);
233 AddService(flimflam::kTypeWifi
, "stub_wifi2",
234 flimflam::kStateIdle
, add_to_watchlist
);
235 AddService(flimflam::kTypeCellular
, "stub_cellular1",
236 flimflam::kStateIdle
, add_to_watchlist
);
239 MessageLoopForUI message_loop_
;
240 scoped_ptr
<TestListener
> listener_
;
241 scoped_ptr
<internal::ShillPropertyHandler
> shill_property_handler_
;
242 ShillManagerClient::TestInterface
* manager_test_
;
243 ShillDeviceClient::TestInterface
* device_test_
;
244 ShillServiceClient::TestInterface
* service_test_
;
247 DISALLOW_COPY_AND_ASSIGN(ShillPropertyHandlerTest
);
250 TEST_F(ShillPropertyHandlerTest
, ShillPropertyHandlerStub
) {
251 EXPECT_EQ(1, listener_
->manager_updates());
252 EXPECT_TRUE(shill_property_handler_
->IsTechnologyAvailable(
253 flimflam::kTypeWifi
));
254 EXPECT_TRUE(shill_property_handler_
->IsTechnologyEnabled(
255 flimflam::kTypeWifi
));
256 const size_t kNumShillManagerClientStubImplDevices
= 2;
257 EXPECT_EQ(kNumShillManagerClientStubImplDevices
,
258 listener_
->entries(flimflam::kDevicesProperty
).size());
259 const size_t kNumShillManagerClientStubImplServices
= 4;
260 EXPECT_EQ(kNumShillManagerClientStubImplServices
,
261 listener_
->entries(flimflam::kServicesProperty
).size());
263 EXPECT_EQ(0, listener_
->errors());
266 TEST_F(ShillPropertyHandlerTest
, ShillPropertyHandlerTechnologyChanged
) {
267 EXPECT_EQ(1, listener_
->manager_updates());
268 // Add a disabled technology.
269 manager_test_
->AddTechnology(flimflam::kTypeWimax
, false);
270 message_loop_
.RunUntilIdle();
271 EXPECT_EQ(2, listener_
->manager_updates());
272 EXPECT_TRUE(shill_property_handler_
->IsTechnologyAvailable(
273 flimflam::kTypeWimax
));
274 EXPECT_FALSE(shill_property_handler_
->IsTechnologyEnabled(
275 flimflam::kTypeWimax
));
277 // Enable the technology.
278 DBusThreadManager::Get()->GetShillManagerClient()->EnableTechnology(
279 flimflam::kTypeWimax
,
280 base::Bind(&base::DoNothing
), base::Bind(&ErrorCallbackFunction
));
281 message_loop_
.RunUntilIdle();
282 EXPECT_EQ(3, listener_
->manager_updates());
283 EXPECT_TRUE(shill_property_handler_
->IsTechnologyEnabled(
284 flimflam::kTypeWimax
));
286 EXPECT_EQ(0, listener_
->errors());
289 TEST_F(ShillPropertyHandlerTest
, ShillPropertyHandlerDevicePropertyChanged
) {
290 EXPECT_EQ(1, listener_
->manager_updates());
291 EXPECT_EQ(1, listener_
->list_updates(flimflam::kDevicesProperty
));
292 const size_t kNumShillManagerClientStubImplDevices
= 2;
293 EXPECT_EQ(kNumShillManagerClientStubImplDevices
,
294 listener_
->entries(flimflam::kDevicesProperty
).size());
296 const std::string
kTestDevicePath("test_wifi_device1");
297 AddDevice(flimflam::kTypeWifi
, kTestDevicePath
);
298 message_loop_
.RunUntilIdle();
299 EXPECT_EQ(1, listener_
->manager_updates()); // No new manager updates.
300 EXPECT_EQ(2, listener_
->list_updates(flimflam::kDevicesProperty
));
301 EXPECT_EQ(kNumShillManagerClientStubImplDevices
+ 1,
302 listener_
->entries(flimflam::kDevicesProperty
).size());
303 // Device changes are not observed.
305 RemoveDevice(kTestDevicePath
);
306 message_loop_
.RunUntilIdle();
307 EXPECT_EQ(3, listener_
->list_updates(flimflam::kDevicesProperty
));
308 EXPECT_EQ(kNumShillManagerClientStubImplDevices
,
309 listener_
->entries(flimflam::kDevicesProperty
).size());
311 EXPECT_EQ(0, listener_
->errors());
314 TEST_F(ShillPropertyHandlerTest
, ShillPropertyHandlerServicePropertyChanged
) {
315 EXPECT_EQ(1, listener_
->manager_updates());
316 EXPECT_EQ(1, listener_
->list_updates(flimflam::kServicesProperty
));
317 const size_t kNumShillManagerClientStubImplServices
= 4;
318 EXPECT_EQ(kNumShillManagerClientStubImplServices
,
319 listener_
->entries(flimflam::kServicesProperty
).size());
321 // Add an unwatched service.
322 const std::string
kTestServicePath("test_wifi_service1");
323 AddService(flimflam::kTypeWifi
, kTestServicePath
,
324 flimflam::kStateIdle
, false);
325 message_loop_
.RunUntilIdle();
326 EXPECT_EQ(1, listener_
->manager_updates()); // No new manager updates.
327 // Only watched services trigger a service list update.
328 EXPECT_EQ(1, listener_
->list_updates(flimflam::kServicesProperty
));
329 EXPECT_EQ(kNumShillManagerClientStubImplServices
+ 1,
330 listener_
->entries(flimflam::kServicesProperty
).size());
331 // Change a property.
332 base::FundamentalValue
scan_interval(3);
333 DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
334 dbus::ObjectPath(kTestServicePath
),
335 flimflam::kScanIntervalProperty
,
337 base::Bind(&base::DoNothing
), base::Bind(&ErrorCallbackFunction
));
338 message_loop_
.RunUntilIdle();
339 // Property change should NOT trigger an update.
340 EXPECT_EQ(0, listener_
->
341 property_updates(flimflam::kServicesProperty
)[kTestServicePath
]);
343 // Add the existing service to the watch list.
344 AddService(flimflam::kTypeWifi
, kTestServicePath
,
345 flimflam::kStateIdle
, true);
346 message_loop_
.RunUntilIdle();
347 // Service list update should be received when watch list changes.
348 EXPECT_EQ(2, listener_
->list_updates(flimflam::kServicesProperty
));
349 // Number of services shouldn't change.
350 EXPECT_EQ(kNumShillManagerClientStubImplServices
+ 1,
351 listener_
->entries(flimflam::kServicesProperty
).size());
352 // Property update should be received when watched service is added.
353 EXPECT_EQ(1, listener_
->
354 property_updates(flimflam::kServicesProperty
)[kTestServicePath
]);
356 // Change a property.
357 DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
358 dbus::ObjectPath(kTestServicePath
),
359 flimflam::kScanIntervalProperty
,
361 base::Bind(&base::DoNothing
), base::Bind(&ErrorCallbackFunction
));
362 message_loop_
.RunUntilIdle();
363 // Property change should trigger another update.
364 EXPECT_EQ(2, listener_
->
365 property_updates(flimflam::kServicesProperty
)[kTestServicePath
]);
368 RemoveService(kTestServicePath
);
369 message_loop_
.RunUntilIdle();
370 EXPECT_EQ(3, listener_
->list_updates(flimflam::kServicesProperty
));
371 EXPECT_EQ(kNumShillManagerClientStubImplServices
,
372 listener_
->entries(flimflam::kServicesProperty
).size());
374 EXPECT_EQ(0, listener_
->errors());
377 TEST_F(ShillPropertyHandlerTest
, ShillPropertyHandlerIPConfigPropertyChanged
) {
378 // Set the properties for an IP Config object.
379 const std::string
kTestIPConfigPath("test_ip_config_path");
380 base::StringValue
ip_address("192.168.1.1");
381 DBusThreadManager::Get()->GetShillIPConfigClient()->SetProperty(
382 dbus::ObjectPath(kTestIPConfigPath
),
383 flimflam::kAddressProperty
,
385 base::Bind(&DoNothingWithCallStatus
));
386 base::ListValue dns_servers
;
387 dns_servers
.Append(base::Value::CreateStringValue("192.168.1.100"));
388 dns_servers
.Append(base::Value::CreateStringValue("192.168.1.101"));
389 DBusThreadManager::Get()->GetShillIPConfigClient()->SetProperty(
390 dbus::ObjectPath(kTestIPConfigPath
),
391 flimflam::kNameServersProperty
,
393 base::Bind(&DoNothingWithCallStatus
));
394 message_loop_
.RunUntilIdle();
396 // Add a service with an empty ipconfig and then update
397 // its ipconfig property.
398 const std::string
kTestServicePath1("test_wifi_service1");
399 AddService(flimflam::kTypeWifi
, kTestServicePath1
,
400 flimflam::kStateIdle
, true);
401 message_loop_
.RunUntilIdle();
402 // This is the initial property update.
403 EXPECT_EQ(1, listener_
->
404 property_updates(flimflam::kServicesProperty
)[kTestServicePath1
]);
405 DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
406 dbus::ObjectPath(kTestServicePath1
),
407 shill::kIPConfigProperty
,
408 base::StringValue(kTestIPConfigPath
),
409 base::Bind(&base::DoNothing
), base::Bind(&ErrorCallbackFunction
));
410 message_loop_
.RunUntilIdle();
411 // IPConfig property change on the service should trigger property updates for
412 // IP Address and DNS.
413 EXPECT_EQ(3, listener_
->
414 property_updates(flimflam::kServicesProperty
)[kTestServicePath1
]);
416 // Now, Add a new watched service with the IPConfig already set.
417 const std::string
kTestServicePath2("test_wifi_service2");
418 AddServiceWithIPConfig(flimflam::kTypeWifi
, kTestServicePath2
,
419 flimflam::kStateIdle
, kTestIPConfigPath
, true);
420 message_loop_
.RunUntilIdle();
421 // A watched service with the IPConfig property already set must
422 // trigger property updates for IP Address and DNS when added.
423 EXPECT_EQ(3, listener_
->
424 property_updates(flimflam::kServicesProperty
)[kTestServicePath2
]);
427 } // namespace chromeos