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/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_profile_client.h"
20 #include "chromeos/dbus/shill_service_client.h"
21 #include "dbus/object_path.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23 #include "third_party/cros_system_api/dbus/service_constants.h"
29 void DoNothingWithCallStatus(DBusMethodCallStatus call_status
) {
32 void ErrorCallbackFunction(const std::string
& error_name
,
33 const std::string
& error_message
) {
34 LOG(ERROR
) << "Shill Error: " << error_name
<< " : " << error_message
;
37 class TestListener
: public internal::ShillPropertyHandler::Listener
{
39 TestListener() : technology_list_updates_(0),
43 virtual void UpdateManagedList(ManagedState::ManagedType type
,
44 const base::ListValue
& entries
) OVERRIDE
{
45 UpdateEntries(GetTypeString(type
), entries
);
48 virtual void UpdateManagedStateProperties(
49 ManagedState::ManagedType type
,
50 const std::string
& path
,
51 const base::DictionaryValue
& properties
) OVERRIDE
{
52 AddInitialPropertyUpdate(GetTypeString(type
), path
);
55 virtual void ProfileListChanged() OVERRIDE
{
58 virtual void UpdateNetworkServiceProperty(
59 const std::string
& service_path
,
60 const std::string
& key
,
61 const base::Value
& value
) OVERRIDE
{
62 AddPropertyUpdate(shill::kServicesProperty
, service_path
);
65 virtual void UpdateDeviceProperty(
66 const std::string
& device_path
,
67 const std::string
& key
,
68 const base::Value
& value
) OVERRIDE
{
69 AddPropertyUpdate(shill::kDevicesProperty
, device_path
);
72 virtual void TechnologyListChanged() OVERRIDE
{
73 ++technology_list_updates_
;
76 virtual void CheckPortalListChanged(
77 const std::string
& check_portal_list
) OVERRIDE
{
80 virtual void ManagedStateListChanged(
81 ManagedState::ManagedType type
) OVERRIDE
{
82 AddStateListUpdate(GetTypeString(type
));
85 virtual void DefaultNetworkServiceChanged(
86 const std::string
& service_path
) OVERRIDE
{
89 std::vector
<std::string
>& entries(const std::string
& type
) {
90 return entries_
[type
];
92 std::map
<std::string
, int>& property_updates(const std::string
& type
) {
93 return property_updates_
[type
];
95 std::map
<std::string
, int>& initial_property_updates(
96 const std::string
& type
) {
97 return initial_property_updates_
[type
];
99 int list_updates(const std::string
& type
) { return list_updates_
[type
]; }
100 void reset_list_updates() { list_updates_
.clear(); }
101 int technology_list_updates() { return technology_list_updates_
; }
102 int errors() { return errors_
; }
105 std::string
GetTypeString(ManagedState::ManagedType type
) {
106 if (type
== ManagedState::MANAGED_TYPE_NETWORK
) {
107 return shill::kServicesProperty
;
108 } else if (type
== ManagedState::MANAGED_TYPE_FAVORITE
) {
109 return shill::kServiceCompleteListProperty
;
110 } else if (type
== ManagedState::MANAGED_TYPE_DEVICE
) {
111 return shill::kDevicesProperty
;
113 LOG(ERROR
) << "UpdateManagedList called with unrecognized type: " << type
;
115 return std::string();
118 void UpdateEntries(const std::string
& type
, const base::ListValue
& entries
) {
121 entries_
[type
].clear();
122 for (base::ListValue::const_iterator iter
= entries
.begin();
123 iter
!= entries
.end(); ++iter
) {
125 if ((*iter
)->GetAsString(&path
))
126 entries_
[type
].push_back(path
);
130 void AddPropertyUpdate(const std::string
& type
, const std::string
& path
) {
133 property_updates(type
)[path
] += 1;
136 void AddInitialPropertyUpdate(const std::string
& type
,
137 const std::string
& path
) {
140 initial_property_updates(type
)[path
] += 1;
143 void AddStateListUpdate(const std::string
& type
) {
146 list_updates_
[type
] += 1;
149 // Map of list-type -> paths
150 std::map
<std::string
, std::vector
<std::string
> > entries_
;
151 // Map of list-type -> map of paths -> update counts
152 std::map
<std::string
, std::map
<std::string
, int> > property_updates_
;
153 std::map
<std::string
, std::map
<std::string
, int> > initial_property_updates_
;
154 // Map of list-type -> list update counts
155 std::map
<std::string
, int > list_updates_
;
156 int technology_list_updates_
;
162 class ShillPropertyHandlerTest
: public testing::Test
{
164 ShillPropertyHandlerTest()
165 : manager_test_(NULL
),
168 profile_test_(NULL
) {
170 virtual ~ShillPropertyHandlerTest() {
173 virtual void SetUp() OVERRIDE
{
174 // Initialize DBusThreadManager with a stub implementation.
175 DBusThreadManager::InitializeWithStub();
176 // Get the test interface for manager / device / service and clear the
177 // default stub properties.
179 DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface();
180 ASSERT_TRUE(manager_test_
);
182 DBusThreadManager::Get()->GetShillDeviceClient()->GetTestInterface();
183 ASSERT_TRUE(device_test_
);
185 DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
186 ASSERT_TRUE(service_test_
);
188 DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface();
189 ASSERT_TRUE(profile_test_
);
190 SetupShillPropertyHandler();
191 message_loop_
.RunUntilIdle();
194 virtual void TearDown() OVERRIDE
{
195 shill_property_handler_
.reset();
197 DBusThreadManager::Shutdown();
200 void AddDevice(const std::string
& type
, const std::string
& id
) {
201 ASSERT_TRUE(IsValidType(type
));
202 device_test_
->AddDevice(id
, type
, std::string("/device/" + id
));
205 void RemoveDevice(const std::string
& id
) {
206 device_test_
->RemoveDevice(id
);
209 void AddService(const std::string
& type
,
210 const std::string
& id
,
211 const std::string
& state
,
212 bool add_to_watch_list
) {
213 ASSERT_TRUE(IsValidType(type
));
214 service_test_
->AddService(id
, id
, type
, state
,
215 true /* visible */, add_to_watch_list
);
218 void AddServiceWithIPConfig(const std::string
& type
,
219 const std::string
& id
,
220 const std::string
& state
,
221 const std::string
& ipconfig_path
,
222 bool add_to_watch_list
) {
223 ASSERT_TRUE(IsValidType(type
));
224 service_test_
->AddServiceWithIPConfig(id
, id
, type
, state
,
230 void AddServiceToProfile(const std::string
& type
,
231 const std::string
& id
,
233 service_test_
->AddService(id
, id
, type
, shill::kStateIdle
,
234 visible
, false /* watch */);
235 std::vector
<std::string
> profiles
;
236 profile_test_
->GetProfilePaths(&profiles
);
237 ASSERT_TRUE(profiles
.size() > 0);
238 base::DictionaryValue properties
; // Empty entry
239 profile_test_
->AddService(profiles
[0], id
);
242 void RemoveService(const std::string
& id
) {
243 service_test_
->RemoveService(id
);
246 // Call this after any initial Shill client setup
247 void SetupShillPropertyHandler() {
248 SetupDefaultShillState();
249 listener_
.reset(new TestListener
);
250 shill_property_handler_
.reset(
251 new internal::ShillPropertyHandler(listener_
.get()));
252 shill_property_handler_
->Init();
255 bool IsValidType(const std::string
& type
) {
256 return (type
== shill::kTypeEthernet
||
257 type
== shill::kTypeEthernetEap
||
258 type
== shill::kTypeWifi
||
259 type
== shill::kTypeWimax
||
260 type
== shill::kTypeBluetooth
||
261 type
== shill::kTypeCellular
||
262 type
== shill::kTypeVPN
);
266 void SetupDefaultShillState() {
267 message_loop_
.RunUntilIdle(); // Process any pending updates
268 device_test_
->ClearDevices();
269 AddDevice(shill::kTypeWifi
, "stub_wifi_device1");
270 AddDevice(shill::kTypeCellular
, "stub_cellular_device1");
271 service_test_
->ClearServices();
272 const bool add_to_watchlist
= true;
273 AddService(shill::kTypeEthernet
, "stub_ethernet",
274 shill::kStateOnline
, add_to_watchlist
);
275 AddService(shill::kTypeWifi
, "stub_wifi1",
276 shill::kStateOnline
, add_to_watchlist
);
277 AddService(shill::kTypeWifi
, "stub_wifi2",
278 shill::kStateIdle
, add_to_watchlist
);
279 AddService(shill::kTypeCellular
, "stub_cellular1",
280 shill::kStateIdle
, add_to_watchlist
);
283 base::MessageLoopForUI message_loop_
;
284 scoped_ptr
<TestListener
> listener_
;
285 scoped_ptr
<internal::ShillPropertyHandler
> shill_property_handler_
;
286 ShillManagerClient::TestInterface
* manager_test_
;
287 ShillDeviceClient::TestInterface
* device_test_
;
288 ShillServiceClient::TestInterface
* service_test_
;
289 ShillProfileClient::TestInterface
* profile_test_
;
292 DISALLOW_COPY_AND_ASSIGN(ShillPropertyHandlerTest
);
295 TEST_F(ShillPropertyHandlerTest
, ShillPropertyHandlerStub
) {
296 EXPECT_TRUE(shill_property_handler_
->IsTechnologyAvailable(shill::kTypeWifi
));
297 EXPECT_TRUE(shill_property_handler_
->IsTechnologyEnabled(shill::kTypeWifi
));
298 const size_t kNumShillManagerClientStubImplDevices
= 2;
299 EXPECT_EQ(kNumShillManagerClientStubImplDevices
,
300 listener_
->entries(shill::kDevicesProperty
).size());
301 const size_t kNumShillManagerClientStubImplServices
= 4;
302 EXPECT_EQ(kNumShillManagerClientStubImplServices
,
303 listener_
->entries(shill::kServicesProperty
).size());
305 EXPECT_EQ(0, listener_
->errors());
308 TEST_F(ShillPropertyHandlerTest
, ShillPropertyHandlerTechnologyChanged
) {
309 const int initial_technology_updates
= 2; // Available and Enabled lists
310 EXPECT_EQ(initial_technology_updates
, listener_
->technology_list_updates());
312 // Remove an enabled technology. Updates both the Available and Enabled lists.
313 manager_test_
->RemoveTechnology(shill::kTypeWifi
);
314 message_loop_
.RunUntilIdle();
315 EXPECT_EQ(initial_technology_updates
+ 2,
316 listener_
->technology_list_updates());
318 // Add a disabled technology.
319 manager_test_
->AddTechnology(shill::kTypeWifi
, false);
320 message_loop_
.RunUntilIdle();
321 EXPECT_EQ(initial_technology_updates
+ 3,
322 listener_
->technology_list_updates());
323 EXPECT_TRUE(shill_property_handler_
->IsTechnologyAvailable(
325 EXPECT_FALSE(shill_property_handler_
->IsTechnologyEnabled(shill::kTypeWifi
));
327 // Enable the technology.
328 DBusThreadManager::Get()->GetShillManagerClient()->EnableTechnology(
330 base::Bind(&base::DoNothing
), base::Bind(&ErrorCallbackFunction
));
331 message_loop_
.RunUntilIdle();
332 EXPECT_EQ(initial_technology_updates
+ 4,
333 listener_
->technology_list_updates());
334 EXPECT_TRUE(shill_property_handler_
->IsTechnologyEnabled(shill::kTypeWifi
));
336 EXPECT_EQ(0, listener_
->errors());
339 TEST_F(ShillPropertyHandlerTest
, ShillPropertyHandlerDevicePropertyChanged
) {
340 const size_t kNumShillManagerClientStubImplDevices
= 2;
341 EXPECT_EQ(kNumShillManagerClientStubImplDevices
,
342 listener_
->entries(shill::kDevicesProperty
).size());
344 listener_
->reset_list_updates();
345 const std::string
kTestDevicePath("test_wifi_device1");
346 AddDevice(shill::kTypeWifi
, kTestDevicePath
);
347 message_loop_
.RunUntilIdle();
348 EXPECT_EQ(1, listener_
->list_updates(shill::kDevicesProperty
));
349 EXPECT_EQ(kNumShillManagerClientStubImplDevices
+ 1,
350 listener_
->entries(shill::kDevicesProperty
).size());
351 // Device changes are not observed.
353 listener_
->reset_list_updates();
354 RemoveDevice(kTestDevicePath
);
355 message_loop_
.RunUntilIdle();
356 EXPECT_EQ(1, listener_
->list_updates(shill::kDevicesProperty
));
357 EXPECT_EQ(kNumShillManagerClientStubImplDevices
,
358 listener_
->entries(shill::kDevicesProperty
).size());
360 EXPECT_EQ(0, listener_
->errors());
363 TEST_F(ShillPropertyHandlerTest
, ShillPropertyHandlerServicePropertyChanged
) {
364 const size_t kNumShillManagerClientStubImplServices
= 4;
365 EXPECT_EQ(kNumShillManagerClientStubImplServices
,
366 listener_
->entries(shill::kServicesProperty
).size());
368 // Add an unwatched service.
369 listener_
->reset_list_updates();
370 const std::string
kTestServicePath("test_wifi_service1");
371 AddService(shill::kTypeWifi
, kTestServicePath
, shill::kStateIdle
, false);
372 message_loop_
.RunUntilIdle();
373 // Watched and unwatched services trigger a service list update.
374 EXPECT_EQ(1, listener_
->list_updates(shill::kServicesProperty
));
375 EXPECT_EQ(kNumShillManagerClientStubImplServices
+ 1,
376 listener_
->entries(shill::kServicesProperty
).size());
377 // Service receives an initial property update.
378 EXPECT_EQ(1, listener_
->initial_property_updates(
379 shill::kServicesProperty
)[kTestServicePath
]);
380 // Change a property.
381 base::FundamentalValue
scan_interval(3);
382 DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
383 dbus::ObjectPath(kTestServicePath
),
384 shill::kScanIntervalProperty
,
386 base::Bind(&base::DoNothing
), base::Bind(&ErrorCallbackFunction
));
387 message_loop_
.RunUntilIdle();
388 // Property change triggers an update.
389 EXPECT_EQ(1, listener_
->property_updates(
390 shill::kServicesProperty
)[kTestServicePath
]);
392 // Add the existing service to the watch list.
393 listener_
->reset_list_updates();
394 AddService(shill::kTypeWifi
, kTestServicePath
, shill::kStateIdle
, true);
395 message_loop_
.RunUntilIdle();
396 // Service list update should be received when watch list changes.
397 EXPECT_EQ(1, listener_
->list_updates(shill::kServicesProperty
));
398 // Number of services shouldn't change.
399 EXPECT_EQ(kNumShillManagerClientStubImplServices
+ 1,
400 listener_
->entries(shill::kServicesProperty
).size());
402 // Change a property.
403 DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
404 dbus::ObjectPath(kTestServicePath
),
405 shill::kScanIntervalProperty
,
407 base::Bind(&base::DoNothing
), base::Bind(&ErrorCallbackFunction
));
408 message_loop_
.RunUntilIdle();
409 // Property change should trigger another update.
410 EXPECT_EQ(2, listener_
->property_updates(
411 shill::kServicesProperty
)[kTestServicePath
]);
414 listener_
->reset_list_updates();
415 RemoveService(kTestServicePath
);
416 message_loop_
.RunUntilIdle();
417 EXPECT_EQ(1, listener_
->list_updates(shill::kServicesProperty
));
418 EXPECT_EQ(kNumShillManagerClientStubImplServices
,
419 listener_
->entries(shill::kServicesProperty
).size());
421 EXPECT_EQ(0, listener_
->errors());
424 TEST_F(ShillPropertyHandlerTest
, ShillPropertyHandlerIPConfigPropertyChanged
) {
425 // Set the properties for an IP Config object.
426 const std::string
kTestIPConfigPath("test_ip_config_path");
428 base::StringValue
ip_address("192.168.1.1");
429 DBusThreadManager::Get()->GetShillIPConfigClient()->SetProperty(
430 dbus::ObjectPath(kTestIPConfigPath
),
431 shill::kAddressProperty
, ip_address
,
432 base::Bind(&DoNothingWithCallStatus
));
433 base::ListValue dns_servers
;
434 dns_servers
.Append(base::Value::CreateStringValue("192.168.1.100"));
435 dns_servers
.Append(base::Value::CreateStringValue("192.168.1.101"));
436 DBusThreadManager::Get()->GetShillIPConfigClient()->SetProperty(
437 dbus::ObjectPath(kTestIPConfigPath
),
438 shill::kNameServersProperty
, dns_servers
,
439 base::Bind(&DoNothingWithCallStatus
));
440 base::FundamentalValue
prefixlen(8);
441 DBusThreadManager::Get()->GetShillIPConfigClient()->SetProperty(
442 dbus::ObjectPath(kTestIPConfigPath
),
443 shill::kPrefixlenProperty
, prefixlen
,
444 base::Bind(&DoNothingWithCallStatus
));
445 base::StringValue
gateway("192.0.0.1");
446 DBusThreadManager::Get()->GetShillIPConfigClient()->SetProperty(
447 dbus::ObjectPath(kTestIPConfigPath
),
448 shill::kGatewayProperty
, gateway
,
449 base::Bind(&DoNothingWithCallStatus
));
450 message_loop_
.RunUntilIdle();
452 // Add a service with an empty ipconfig and then update
453 // its ipconfig property.
454 const std::string
kTestServicePath1("test_wifi_service1");
455 AddService(shill::kTypeWifi
, kTestServicePath1
, shill::kStateIdle
, true);
456 message_loop_
.RunUntilIdle();
457 // This is the initial property update.
458 EXPECT_EQ(1, listener_
->initial_property_updates(
459 shill::kServicesProperty
)[kTestServicePath1
]);
460 DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
461 dbus::ObjectPath(kTestServicePath1
),
462 shill::kIPConfigProperty
,
463 base::StringValue(kTestIPConfigPath
),
464 base::Bind(&base::DoNothing
), base::Bind(&ErrorCallbackFunction
));
465 message_loop_
.RunUntilIdle();
466 // IPConfig property change on the service should trigger property updates for
467 // IP Address, DNS, prefixlen, and gateway.
468 EXPECT_EQ(4, listener_
->property_updates(
469 shill::kServicesProperty
)[kTestServicePath1
]);
471 // Now, Add a new watched service with the IPConfig already set.
472 const std::string
kTestServicePath2("test_wifi_service2");
473 AddServiceWithIPConfig(shill::kTypeWifi
, kTestServicePath2
,
474 shill::kStateIdle
, kTestIPConfigPath
, true);
475 message_loop_
.RunUntilIdle();
476 // A watched service with the IPConfig property already set must trigger
477 // property updates for IP Address, DNS, prefixlen, and gateway when added.
478 EXPECT_EQ(4, listener_
->property_updates(
479 shill::kServicesProperty
)[kTestServicePath2
]);
482 TEST_F(ShillPropertyHandlerTest
, ShillPropertyHandlerServiceCompleteList
) {
483 // Add a new entry to the profile only (triggers a Services update).
484 const std::string
kTestServicePath1("stub_wifi_profile_only1");
485 AddServiceToProfile(shill::kTypeWifi
, kTestServicePath1
, false);
486 message_loop_
.RunUntilIdle();
488 // Update the Manager properties. This should trigger a single list update
489 // for both Services and ServiceCompleteList, and a single property update
490 // for ServiceCompleteList.
491 listener_
->reset_list_updates();
492 shill_property_handler_
->UpdateManagerProperties();
493 message_loop_
.RunUntilIdle();
494 EXPECT_EQ(1, listener_
->list_updates(shill::kServicesProperty
));
495 EXPECT_EQ(1, listener_
->list_updates(shill::kServiceCompleteListProperty
));
496 EXPECT_EQ(0, listener_
->initial_property_updates(
497 shill::kServicesProperty
)[kTestServicePath1
]);
498 EXPECT_EQ(1, listener_
->initial_property_updates(
499 shill::kServiceCompleteListProperty
)[kTestServicePath1
]);
500 EXPECT_EQ(0, listener_
->property_updates(
501 shill::kServicesProperty
)[kTestServicePath1
]);
502 EXPECT_EQ(0, listener_
->property_updates(
503 shill::kServiceCompleteListProperty
)[kTestServicePath1
]);
505 // Add a new entry to the services and the profile; should also trigger a
506 // single list update for both Services and ServiceCompleteList, and should
507 // trigger tow property updates for Services (one when the Profile propety
508 // changes, and one for the Request) and one ServiceCompleteList change for
510 listener_
->reset_list_updates();
511 const std::string
kTestServicePath2("stub_wifi_profile_only2");
512 AddServiceToProfile(shill::kTypeWifi
, kTestServicePath2
, true);
513 shill_property_handler_
->UpdateManagerProperties();
514 message_loop_
.RunUntilIdle();
515 EXPECT_EQ(1, listener_
->list_updates(shill::kServicesProperty
));
516 EXPECT_EQ(1, listener_
->list_updates(shill::kServiceCompleteListProperty
));
517 EXPECT_EQ(1, listener_
->initial_property_updates(
518 shill::kServicesProperty
)[kTestServicePath2
]);
519 EXPECT_EQ(1, listener_
->initial_property_updates(
520 shill::kServiceCompleteListProperty
)[kTestServicePath2
]);
521 // Expect one property update for the Profile property of the Network.
522 EXPECT_EQ(1, listener_
->property_updates(
523 shill::kServicesProperty
)[kTestServicePath2
]);
524 EXPECT_EQ(0, listener_
->property_updates(
525 shill::kServiceCompleteListProperty
)[kTestServicePath2
]);
527 // Change a property of a Network in a Profile.
528 base::FundamentalValue
scan_interval(3);
529 DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
530 dbus::ObjectPath(kTestServicePath2
),
531 shill::kScanIntervalProperty
,
533 base::Bind(&base::DoNothing
), base::Bind(&ErrorCallbackFunction
));
534 message_loop_
.RunUntilIdle();
535 // Property change should trigger an update for the Network only; no
536 // property updates pushed by Shill affect Favorites.
537 EXPECT_EQ(2, listener_
->property_updates(
538 shill::kServicesProperty
)[kTestServicePath2
]);
539 EXPECT_EQ(0, listener_
->property_updates(
540 shill::kServiceCompleteListProperty
)[kTestServicePath2
]);
543 } // namespace chromeos