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 VLOG(1) << "UpdateManagedList[" << ManagedState::TypeToString(type
) << "]: "
47 UpdateEntries(GetTypeString(type
), entries
);
50 virtual void UpdateManagedStateProperties(
51 ManagedState::ManagedType type
,
52 const std::string
& path
,
53 const base::DictionaryValue
& properties
) OVERRIDE
{
54 VLOG(2) << "UpdateManagedStateProperties: " << GetTypeString(type
);
55 initial_property_updates(GetTypeString(type
))[path
] += 1;
58 virtual void ProfileListChanged() OVERRIDE
{
61 virtual void UpdateNetworkServiceProperty(
62 const std::string
& service_path
,
63 const std::string
& key
,
64 const base::Value
& value
) OVERRIDE
{
65 AddPropertyUpdate(shill::kServiceCompleteListProperty
, service_path
);
68 virtual void UpdateDeviceProperty(
69 const std::string
& device_path
,
70 const std::string
& key
,
71 const base::Value
& value
) OVERRIDE
{
72 AddPropertyUpdate(shill::kDevicesProperty
, device_path
);
75 virtual void UpdateIPConfigProperties(
76 ManagedState::ManagedType type
,
77 const std::string
& path
,
78 const std::string
& ip_config_path
,
79 const base::DictionaryValue
& properties
) OVERRIDE
{
80 AddPropertyUpdate(shill::kIPConfigsProperty
, ip_config_path
);
83 virtual void TechnologyListChanged() OVERRIDE
{
84 VLOG(1) << "TechnologyListChanged.";
85 ++technology_list_updates_
;
88 virtual void CheckPortalListChanged(
89 const std::string
& check_portal_list
) OVERRIDE
{
92 virtual void ManagedStateListChanged(
93 ManagedState::ManagedType type
) OVERRIDE
{
94 VLOG(1) << "ManagedStateListChanged: " << GetTypeString(type
);
95 AddStateListUpdate(GetTypeString(type
));
98 virtual void DefaultNetworkServiceChanged(
99 const std::string
& service_path
) OVERRIDE
{
102 std::vector
<std::string
>& entries(const std::string
& type
) {
103 return entries_
[type
];
105 std::map
<std::string
, int>& property_updates(const std::string
& type
) {
106 return property_updates_
[type
];
108 std::map
<std::string
, int>& initial_property_updates(
109 const std::string
& type
) {
110 return initial_property_updates_
[type
];
112 int list_updates(const std::string
& type
) { return list_updates_
[type
]; }
113 int technology_list_updates() { return technology_list_updates_
; }
114 void reset_list_updates() {
115 VLOG(1) << "=== RESET LIST UPDATES ===";
116 list_updates_
.clear();
117 technology_list_updates_
= 0;
119 int errors() { return errors_
; }
122 std::string
GetTypeString(ManagedState::ManagedType type
) {
123 if (type
== ManagedState::MANAGED_TYPE_NETWORK
)
124 return shill::kServiceCompleteListProperty
;
125 if (type
== ManagedState::MANAGED_TYPE_DEVICE
)
126 return shill::kDevicesProperty
;
128 return std::string();
131 void UpdateEntries(const std::string
& type
, const base::ListValue
& entries
) {
134 entries_
[type
].clear();
135 for (base::ListValue::const_iterator iter
= entries
.begin();
136 iter
!= entries
.end(); ++iter
) {
138 if ((*iter
)->GetAsString(&path
))
139 entries_
[type
].push_back(path
);
143 void AddPropertyUpdate(const std::string
& type
, const std::string
& path
) {
144 DCHECK(!type
.empty());
145 VLOG(2) << "AddPropertyUpdate: " << type
;
146 property_updates(type
)[path
] += 1;
149 void AddStateListUpdate(const std::string
& type
) {
150 DCHECK(!type
.empty());
151 list_updates_
[type
] += 1;
154 // Map of list-type -> paths
155 std::map
<std::string
, std::vector
<std::string
> > entries_
;
156 // Map of list-type -> map of paths -> update counts
157 std::map
<std::string
, std::map
<std::string
, int> > property_updates_
;
158 std::map
<std::string
, std::map
<std::string
, int> > initial_property_updates_
;
159 // Map of list-type -> list update counts
160 std::map
<std::string
, int > list_updates_
;
161 int technology_list_updates_
;
167 class ShillPropertyHandlerTest
: public testing::Test
{
169 ShillPropertyHandlerTest()
170 : manager_test_(NULL
),
173 profile_test_(NULL
) {
175 virtual ~ShillPropertyHandlerTest() {
178 virtual void SetUp() OVERRIDE
{
179 // Initialize DBusThreadManager with a stub implementation.
180 DBusThreadManager::Initialize();
181 // Get the test interface for manager / device / service and clear the
182 // default stub properties.
184 DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface();
185 ASSERT_TRUE(manager_test_
);
187 DBusThreadManager::Get()->GetShillDeviceClient()->GetTestInterface();
188 ASSERT_TRUE(device_test_
);
190 DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
191 ASSERT_TRUE(service_test_
);
193 DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface();
194 ASSERT_TRUE(profile_test_
);
195 SetupShillPropertyHandler();
196 message_loop_
.RunUntilIdle();
199 virtual void TearDown() OVERRIDE
{
200 shill_property_handler_
.reset();
202 DBusThreadManager::Shutdown();
205 void AddDevice(const std::string
& type
, const std::string
& id
) {
206 ASSERT_TRUE(IsValidType(type
));
207 device_test_
->AddDevice(id
, type
, id
);
210 void RemoveDevice(const std::string
& id
) {
211 device_test_
->RemoveDevice(id
);
214 void AddService(const std::string
& type
,
215 const std::string
& id
,
216 const std::string
& state
) {
217 VLOG(2) << "AddService: " << type
<< ": " << id
<< ": " << state
;
218 ASSERT_TRUE(IsValidType(type
));
219 service_test_
->AddService(id
/* service_path */,
227 void AddServiceWithIPConfig(const std::string
& type
,
228 const std::string
& id
,
229 const std::string
& state
,
230 const std::string
& ipconfig_path
) {
231 ASSERT_TRUE(IsValidType(type
));
232 service_test_
->AddServiceWithIPConfig(id
, /* service_path */
241 void AddServiceToProfile(const std::string
& type
,
242 const std::string
& id
,
244 service_test_
->AddService(id
/* service_path */,
250 std::vector
<std::string
> profiles
;
251 profile_test_
->GetProfilePaths(&profiles
);
252 ASSERT_TRUE(profiles
.size() > 0);
253 base::DictionaryValue properties
; // Empty entry
254 profile_test_
->AddService(profiles
[0], id
);
257 void RemoveService(const std::string
& id
) {
258 service_test_
->RemoveService(id
);
261 // Call this after any initial Shill client setup
262 void SetupShillPropertyHandler() {
263 SetupDefaultShillState();
264 listener_
.reset(new TestListener
);
265 shill_property_handler_
.reset(
266 new internal::ShillPropertyHandler(listener_
.get()));
267 shill_property_handler_
->Init();
270 bool IsValidType(const std::string
& type
) {
271 return (type
== shill::kTypeEthernet
||
272 type
== shill::kTypeEthernetEap
||
273 type
== shill::kTypeWifi
||
274 type
== shill::kTypeWimax
||
275 type
== shill::kTypeBluetooth
||
276 type
== shill::kTypeCellular
||
277 type
== shill::kTypeVPN
);
281 void SetupDefaultShillState() {
282 message_loop_
.RunUntilIdle(); // Process any pending updates
283 device_test_
->ClearDevices();
284 AddDevice(shill::kTypeWifi
, "stub_wifi_device1");
285 AddDevice(shill::kTypeCellular
, "stub_cellular_device1");
286 service_test_
->ClearServices();
287 AddService(shill::kTypeEthernet
, "stub_ethernet", shill::kStateOnline
);
288 AddService(shill::kTypeWifi
, "stub_wifi1", shill::kStateOnline
);
289 AddService(shill::kTypeWifi
, "stub_wifi2", shill::kStateIdle
);
290 AddService(shill::kTypeCellular
, "stub_cellular1", shill::kStateIdle
);
293 base::MessageLoopForUI message_loop_
;
294 scoped_ptr
<TestListener
> listener_
;
295 scoped_ptr
<internal::ShillPropertyHandler
> shill_property_handler_
;
296 ShillManagerClient::TestInterface
* manager_test_
;
297 ShillDeviceClient::TestInterface
* device_test_
;
298 ShillServiceClient::TestInterface
* service_test_
;
299 ShillProfileClient::TestInterface
* profile_test_
;
302 DISALLOW_COPY_AND_ASSIGN(ShillPropertyHandlerTest
);
305 TEST_F(ShillPropertyHandlerTest
, ShillPropertyHandlerStub
) {
306 EXPECT_TRUE(shill_property_handler_
->IsTechnologyAvailable(shill::kTypeWifi
));
307 EXPECT_TRUE(shill_property_handler_
->IsTechnologyEnabled(shill::kTypeWifi
));
308 const size_t kNumShillManagerClientStubImplDevices
= 2;
309 EXPECT_EQ(kNumShillManagerClientStubImplDevices
,
310 listener_
->entries(shill::kDevicesProperty
).size());
311 const size_t kNumShillManagerClientStubImplServices
= 4;
312 EXPECT_EQ(kNumShillManagerClientStubImplServices
,
313 listener_
->entries(shill::kServiceCompleteListProperty
).size());
315 EXPECT_EQ(0, listener_
->errors());
318 TEST_F(ShillPropertyHandlerTest
, ShillPropertyHandlerTechnologyChanged
) {
319 const int initial_technology_updates
= 2; // Available and Enabled lists
320 EXPECT_EQ(initial_technology_updates
, listener_
->technology_list_updates());
322 // Remove an enabled technology. Updates both the Available and Enabled lists.
323 listener_
->reset_list_updates();
324 manager_test_
->RemoveTechnology(shill::kTypeWifi
);
325 message_loop_
.RunUntilIdle();
326 EXPECT_EQ(2, listener_
->technology_list_updates());
328 // Add a disabled technology.
329 listener_
->reset_list_updates();
330 manager_test_
->AddTechnology(shill::kTypeWifi
, false);
331 message_loop_
.RunUntilIdle();
332 EXPECT_EQ(1, listener_
->technology_list_updates());
333 EXPECT_TRUE(shill_property_handler_
->IsTechnologyAvailable(
335 EXPECT_FALSE(shill_property_handler_
->IsTechnologyEnabled(shill::kTypeWifi
));
337 // Enable the technology.
338 listener_
->reset_list_updates();
339 DBusThreadManager::Get()->GetShillManagerClient()->EnableTechnology(
341 base::Bind(&base::DoNothing
), base::Bind(&ErrorCallbackFunction
));
342 message_loop_
.RunUntilIdle();
343 EXPECT_EQ(1, listener_
->technology_list_updates());
344 EXPECT_TRUE(shill_property_handler_
->IsTechnologyEnabled(shill::kTypeWifi
));
346 EXPECT_EQ(0, listener_
->errors());
349 TEST_F(ShillPropertyHandlerTest
, ShillPropertyHandlerDevicePropertyChanged
) {
350 const size_t kNumShillManagerClientStubImplDevices
= 2;
351 EXPECT_EQ(kNumShillManagerClientStubImplDevices
,
352 listener_
->entries(shill::kDevicesProperty
).size());
354 listener_
->reset_list_updates();
355 const std::string
kTestDevicePath("test_wifi_device1");
356 AddDevice(shill::kTypeWifi
, kTestDevicePath
);
357 message_loop_
.RunUntilIdle();
358 EXPECT_EQ(1, listener_
->list_updates(shill::kDevicesProperty
));
359 EXPECT_EQ(kNumShillManagerClientStubImplDevices
+ 1,
360 listener_
->entries(shill::kDevicesProperty
).size());
363 listener_
->reset_list_updates();
364 RemoveDevice(kTestDevicePath
);
365 message_loop_
.RunUntilIdle();
366 EXPECT_EQ(1, listener_
->list_updates(shill::kDevicesProperty
));
367 EXPECT_EQ(kNumShillManagerClientStubImplDevices
,
368 listener_
->entries(shill::kDevicesProperty
).size());
370 EXPECT_EQ(0, listener_
->errors());
373 TEST_F(ShillPropertyHandlerTest
, ShillPropertyHandlerServicePropertyChanged
) {
374 const size_t kNumShillManagerClientStubImplServices
= 4;
375 EXPECT_EQ(kNumShillManagerClientStubImplServices
,
376 listener_
->entries(shill::kServiceCompleteListProperty
).size());
379 listener_
->reset_list_updates();
380 const std::string
kTestServicePath("test_wifi_service1");
381 AddService(shill::kTypeWifi
, kTestServicePath
, shill::kStateIdle
);
382 message_loop_
.RunUntilIdle();
383 // Add should trigger a service list update and update entries.
384 EXPECT_EQ(1, listener_
->list_updates(shill::kServiceCompleteListProperty
));
385 EXPECT_EQ(kNumShillManagerClientStubImplServices
+ 1,
386 listener_
->entries(shill::kServiceCompleteListProperty
).size());
387 // Service receives an initial property update.
388 EXPECT_EQ(1, listener_
->initial_property_updates(
389 shill::kServiceCompleteListProperty
)[kTestServicePath
]);
390 // Change a property.
391 base::FundamentalValue
scan_interval(3);
392 DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
393 dbus::ObjectPath(kTestServicePath
),
394 shill::kScanIntervalProperty
,
396 base::Bind(&base::DoNothing
), base::Bind(&ErrorCallbackFunction
));
397 message_loop_
.RunUntilIdle();
398 // Property change triggers an update (but not a service list update).
399 EXPECT_EQ(1, listener_
->property_updates(
400 shill::kServiceCompleteListProperty
)[kTestServicePath
]);
402 // Change the visibility of a service. This will trigger a service list
404 listener_
->reset_list_updates();
405 DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
406 dbus::ObjectPath(kTestServicePath
),
407 shill::kVisibleProperty
,
408 base::FundamentalValue(false),
409 base::Bind(&base::DoNothing
), base::Bind(&ErrorCallbackFunction
));
410 message_loop_
.RunUntilIdle();
411 EXPECT_EQ(1, listener_
->list_updates(shill::kServiceCompleteListProperty
));
413 // Remove a service. This will update the entries and signal a service list
415 listener_
->reset_list_updates();
416 RemoveService(kTestServicePath
);
417 message_loop_
.RunUntilIdle();
418 EXPECT_EQ(1, listener_
->list_updates(shill::kServiceCompleteListProperty
));
419 EXPECT_EQ(kNumShillManagerClientStubImplServices
,
420 listener_
->entries(shill::kServiceCompleteListProperty
).size());
422 EXPECT_EQ(0, listener_
->errors());
425 TEST_F(ShillPropertyHandlerTest
, ShillPropertyHandlerIPConfigPropertyChanged
) {
426 // Set the properties for an IP Config object.
427 const std::string
kTestIPConfigPath("test_ip_config_path");
429 base::StringValue
ip_address("192.168.1.1");
430 DBusThreadManager::Get()->GetShillIPConfigClient()->SetProperty(
431 dbus::ObjectPath(kTestIPConfigPath
),
432 shill::kAddressProperty
, ip_address
,
433 base::Bind(&DoNothingWithCallStatus
));
434 base::ListValue dns_servers
;
435 dns_servers
.Append(new base::StringValue("192.168.1.100"));
436 dns_servers
.Append(new base::StringValue("192.168.1.101"));
437 DBusThreadManager::Get()->GetShillIPConfigClient()->SetProperty(
438 dbus::ObjectPath(kTestIPConfigPath
),
439 shill::kNameServersProperty
, dns_servers
,
440 base::Bind(&DoNothingWithCallStatus
));
441 base::FundamentalValue
prefixlen(8);
442 DBusThreadManager::Get()->GetShillIPConfigClient()->SetProperty(
443 dbus::ObjectPath(kTestIPConfigPath
),
444 shill::kPrefixlenProperty
, prefixlen
,
445 base::Bind(&DoNothingWithCallStatus
));
446 base::StringValue
gateway("192.0.0.1");
447 DBusThreadManager::Get()->GetShillIPConfigClient()->SetProperty(
448 dbus::ObjectPath(kTestIPConfigPath
),
449 shill::kGatewayProperty
, gateway
,
450 base::Bind(&DoNothingWithCallStatus
));
451 message_loop_
.RunUntilIdle();
453 // Add a service with an empty ipconfig and then update
454 // its ipconfig property.
455 const std::string
kTestServicePath1("test_wifi_service1");
456 AddService(shill::kTypeWifi
, kTestServicePath1
, shill::kStateIdle
);
457 message_loop_
.RunUntilIdle();
458 // This is the initial property update.
459 EXPECT_EQ(1, listener_
->initial_property_updates(
460 shill::kServiceCompleteListProperty
)[kTestServicePath1
]);
461 DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
462 dbus::ObjectPath(kTestServicePath1
),
463 shill::kIPConfigProperty
,
464 base::StringValue(kTestIPConfigPath
),
465 base::Bind(&base::DoNothing
), base::Bind(&ErrorCallbackFunction
));
466 message_loop_
.RunUntilIdle();
467 // IPConfig property change on the service should trigger an IPConfigs update.
468 EXPECT_EQ(1, listener_
->property_updates(
469 shill::kIPConfigsProperty
)[kTestIPConfigPath
]);
471 // Now, Add a new service with the IPConfig already set.
472 const std::string
kTestServicePath2("test_wifi_service2");
473 AddServiceWithIPConfig(shill::kTypeWifi
, kTestServicePath2
,
474 shill::kStateIdle
, kTestIPConfigPath
);
475 message_loop_
.RunUntilIdle();
476 // A service with the IPConfig property already set should trigger an
477 // additional IPConfigs update.
478 EXPECT_EQ(2, listener_
->property_updates(
479 shill::kIPConfigsProperty
)[kTestIPConfigPath
]);
482 TEST_F(ShillPropertyHandlerTest
, ShillPropertyHandlerServiceList
) {
483 // Add an entry to the profile only.
484 const std::string
kTestServicePath1("stub_wifi_profile_only1");
485 AddServiceToProfile(shill::kTypeWifi
, kTestServicePath1
, false /* visible */);
486 message_loop_
.RunUntilIdle();
488 // Update the Manager properties. This should trigger a single list update,
489 // an initial property update, and a regular property update.
490 listener_
->reset_list_updates();
491 shill_property_handler_
->UpdateManagerProperties();
492 message_loop_
.RunUntilIdle();
493 EXPECT_EQ(1, listener_
->list_updates(shill::kServiceCompleteListProperty
));
494 EXPECT_EQ(1, listener_
->initial_property_updates(
495 shill::kServiceCompleteListProperty
)[kTestServicePath1
]);
496 EXPECT_EQ(1, listener_
->property_updates(
497 shill::kServiceCompleteListProperty
)[kTestServicePath1
]);
499 // Add a new entry to the services and the profile; should also trigger a
500 // service list update, and a property update.
501 listener_
->reset_list_updates();
502 const std::string
kTestServicePath2("stub_wifi_profile_only2");
503 AddServiceToProfile(shill::kTypeWifi
, kTestServicePath2
, true);
504 shill_property_handler_
->UpdateManagerProperties();
505 message_loop_
.RunUntilIdle();
506 EXPECT_EQ(1, listener_
->list_updates(shill::kServiceCompleteListProperty
));
507 EXPECT_EQ(1, listener_
->initial_property_updates(
508 shill::kServiceCompleteListProperty
)[kTestServicePath2
]);
509 EXPECT_EQ(1, listener_
->property_updates(
510 shill::kServiceCompleteListProperty
)[kTestServicePath2
]);
513 } // namespace chromeos