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 void UpdateManagedList(ManagedState::ManagedType type
,
44 const base::ListValue
& entries
) override
{
45 VLOG(1) << "UpdateManagedList[" << ManagedState::TypeToString(type
) << "]: "
47 UpdateEntries(GetTypeString(type
), entries
);
50 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 void ProfileListChanged() override
{}
60 void UpdateNetworkServiceProperty(const std::string
& service_path
,
61 const std::string
& key
,
62 const base::Value
& value
) override
{
63 AddPropertyUpdate(shill::kServiceCompleteListProperty
, service_path
);
66 void UpdateDeviceProperty(const std::string
& device_path
,
67 const std::string
& key
,
68 const base::Value
& value
) override
{
69 AddPropertyUpdate(shill::kDevicesProperty
, device_path
);
72 void UpdateIPConfigProperties(
73 ManagedState::ManagedType type
,
74 const std::string
& path
,
75 const std::string
& ip_config_path
,
76 const base::DictionaryValue
& properties
) override
{
77 AddPropertyUpdate(shill::kIPConfigsProperty
, ip_config_path
);
80 void TechnologyListChanged() override
{
81 VLOG(1) << "TechnologyListChanged.";
82 ++technology_list_updates_
;
85 void CheckPortalListChanged(const std::string
& check_portal_list
) override
{}
87 void ManagedStateListChanged(ManagedState::ManagedType type
) override
{
88 VLOG(1) << "ManagedStateListChanged: " << GetTypeString(type
);
89 AddStateListUpdate(GetTypeString(type
));
92 void DefaultNetworkServiceChanged(const std::string
& service_path
) override
{}
94 std::vector
<std::string
>& entries(const std::string
& type
) {
95 return entries_
[type
];
97 std::map
<std::string
, int>& property_updates(const std::string
& type
) {
98 return property_updates_
[type
];
100 std::map
<std::string
, int>& initial_property_updates(
101 const std::string
& type
) {
102 return initial_property_updates_
[type
];
104 int list_updates(const std::string
& type
) { return list_updates_
[type
]; }
105 int technology_list_updates() { return technology_list_updates_
; }
106 void reset_list_updates() {
107 VLOG(1) << "=== RESET LIST UPDATES ===";
108 list_updates_
.clear();
109 technology_list_updates_
= 0;
111 int errors() { return errors_
; }
114 std::string
GetTypeString(ManagedState::ManagedType type
) {
115 if (type
== ManagedState::MANAGED_TYPE_NETWORK
)
116 return shill::kServiceCompleteListProperty
;
117 if (type
== ManagedState::MANAGED_TYPE_DEVICE
)
118 return shill::kDevicesProperty
;
120 return std::string();
123 void UpdateEntries(const std::string
& type
, const base::ListValue
& entries
) {
126 entries_
[type
].clear();
127 for (base::ListValue::const_iterator iter
= entries
.begin();
128 iter
!= entries
.end(); ++iter
) {
130 if ((*iter
)->GetAsString(&path
))
131 entries_
[type
].push_back(path
);
135 void AddPropertyUpdate(const std::string
& type
, const std::string
& path
) {
136 DCHECK(!type
.empty());
137 VLOG(2) << "AddPropertyUpdate: " << type
;
138 property_updates(type
)[path
] += 1;
141 void AddStateListUpdate(const std::string
& type
) {
142 DCHECK(!type
.empty());
143 list_updates_
[type
] += 1;
146 // Map of list-type -> paths
147 std::map
<std::string
, std::vector
<std::string
> > entries_
;
148 // Map of list-type -> map of paths -> update counts
149 std::map
<std::string
, std::map
<std::string
, int> > property_updates_
;
150 std::map
<std::string
, std::map
<std::string
, int> > initial_property_updates_
;
151 // Map of list-type -> list update counts
152 std::map
<std::string
, int > list_updates_
;
153 int technology_list_updates_
;
159 class ShillPropertyHandlerTest
: public testing::Test
{
161 ShillPropertyHandlerTest()
162 : manager_test_(NULL
),
165 profile_test_(NULL
) {
167 ~ShillPropertyHandlerTest() override
{}
169 void SetUp() override
{
170 // Initialize DBusThreadManager with a stub implementation.
171 DBusThreadManager::Initialize();
172 // Get the test interface for manager / device / service and clear the
173 // default stub properties.
175 DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface();
176 ASSERT_TRUE(manager_test_
);
178 DBusThreadManager::Get()->GetShillDeviceClient()->GetTestInterface();
179 ASSERT_TRUE(device_test_
);
181 DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
182 ASSERT_TRUE(service_test_
);
184 DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface();
185 ASSERT_TRUE(profile_test_
);
186 SetupShillPropertyHandler();
187 message_loop_
.RunUntilIdle();
190 void TearDown() override
{
191 shill_property_handler_
.reset();
193 DBusThreadManager::Shutdown();
196 void AddDevice(const std::string
& type
, const std::string
& id
) {
197 ASSERT_TRUE(IsValidType(type
));
198 device_test_
->AddDevice(id
, type
, id
);
201 void RemoveDevice(const std::string
& id
) {
202 device_test_
->RemoveDevice(id
);
205 void AddService(const std::string
& type
,
206 const std::string
& id
,
207 const std::string
& state
) {
208 VLOG(2) << "AddService: " << type
<< ": " << id
<< ": " << state
;
209 ASSERT_TRUE(IsValidType(type
));
210 service_test_
->AddService(id
/* service_path */,
218 void AddServiceWithIPConfig(const std::string
& type
,
219 const std::string
& id
,
220 const std::string
& state
,
221 const std::string
& ipconfig_path
) {
222 ASSERT_TRUE(IsValidType(type
));
223 service_test_
->AddServiceWithIPConfig(id
, /* service_path */
232 void AddServiceToProfile(const std::string
& type
,
233 const std::string
& id
,
235 service_test_
->AddService(id
/* service_path */,
241 std::vector
<std::string
> profiles
;
242 profile_test_
->GetProfilePaths(&profiles
);
243 ASSERT_TRUE(profiles
.size() > 0);
244 base::DictionaryValue properties
; // Empty entry
245 profile_test_
->AddService(profiles
[0], id
);
248 void RemoveService(const std::string
& id
) {
249 service_test_
->RemoveService(id
);
252 // Call this after any initial Shill client setup
253 void SetupShillPropertyHandler() {
254 SetupDefaultShillState();
255 listener_
.reset(new TestListener
);
256 shill_property_handler_
.reset(
257 new internal::ShillPropertyHandler(listener_
.get()));
258 shill_property_handler_
->Init();
261 bool IsValidType(const std::string
& type
) {
262 return (type
== shill::kTypeEthernet
||
263 type
== shill::kTypeEthernetEap
||
264 type
== shill::kTypeWifi
||
265 type
== shill::kTypeWimax
||
266 type
== shill::kTypeBluetooth
||
267 type
== shill::kTypeCellular
||
268 type
== shill::kTypeVPN
);
272 void SetupDefaultShillState() {
273 message_loop_
.RunUntilIdle(); // Process any pending updates
274 device_test_
->ClearDevices();
275 AddDevice(shill::kTypeWifi
, "stub_wifi_device1");
276 AddDevice(shill::kTypeCellular
, "stub_cellular_device1");
277 service_test_
->ClearServices();
278 AddService(shill::kTypeEthernet
, "stub_ethernet", shill::kStateOnline
);
279 AddService(shill::kTypeWifi
, "stub_wifi1", shill::kStateOnline
);
280 AddService(shill::kTypeWifi
, "stub_wifi2", shill::kStateIdle
);
281 AddService(shill::kTypeCellular
, "stub_cellular1", shill::kStateIdle
);
284 base::MessageLoopForUI message_loop_
;
285 scoped_ptr
<TestListener
> listener_
;
286 scoped_ptr
<internal::ShillPropertyHandler
> shill_property_handler_
;
287 ShillManagerClient::TestInterface
* manager_test_
;
288 ShillDeviceClient::TestInterface
* device_test_
;
289 ShillServiceClient::TestInterface
* service_test_
;
290 ShillProfileClient::TestInterface
* profile_test_
;
293 DISALLOW_COPY_AND_ASSIGN(ShillPropertyHandlerTest
);
296 TEST_F(ShillPropertyHandlerTest
, ShillPropertyHandlerStub
) {
297 EXPECT_TRUE(shill_property_handler_
->IsTechnologyAvailable(shill::kTypeWifi
));
298 EXPECT_TRUE(shill_property_handler_
->IsTechnologyEnabled(shill::kTypeWifi
));
299 const size_t kNumShillManagerClientStubImplDevices
= 2;
300 EXPECT_EQ(kNumShillManagerClientStubImplDevices
,
301 listener_
->entries(shill::kDevicesProperty
).size());
302 const size_t kNumShillManagerClientStubImplServices
= 4;
303 EXPECT_EQ(kNumShillManagerClientStubImplServices
,
304 listener_
->entries(shill::kServiceCompleteListProperty
).size());
306 EXPECT_EQ(0, listener_
->errors());
309 TEST_F(ShillPropertyHandlerTest
, ShillPropertyHandlerTechnologyChanged
) {
310 const int initial_technology_updates
= 2; // Available and Enabled lists
311 EXPECT_EQ(initial_technology_updates
, listener_
->technology_list_updates());
313 // Remove an enabled technology. Updates both the Available and Enabled lists.
314 listener_
->reset_list_updates();
315 manager_test_
->RemoveTechnology(shill::kTypeWifi
);
316 message_loop_
.RunUntilIdle();
317 EXPECT_EQ(2, listener_
->technology_list_updates());
319 // Add a disabled technology.
320 listener_
->reset_list_updates();
321 manager_test_
->AddTechnology(shill::kTypeWifi
, false);
322 message_loop_
.RunUntilIdle();
323 EXPECT_EQ(1, listener_
->technology_list_updates());
324 EXPECT_TRUE(shill_property_handler_
->IsTechnologyAvailable(
326 EXPECT_FALSE(shill_property_handler_
->IsTechnologyEnabled(shill::kTypeWifi
));
328 // Enable the technology.
329 listener_
->reset_list_updates();
330 DBusThreadManager::Get()->GetShillManagerClient()->EnableTechnology(
332 base::Bind(&base::DoNothing
), base::Bind(&ErrorCallbackFunction
));
333 message_loop_
.RunUntilIdle();
334 EXPECT_EQ(1, listener_
->technology_list_updates());
335 EXPECT_TRUE(shill_property_handler_
->IsTechnologyEnabled(shill::kTypeWifi
));
337 EXPECT_EQ(0, listener_
->errors());
340 TEST_F(ShillPropertyHandlerTest
, ShillPropertyHandlerDevicePropertyChanged
) {
341 const size_t kNumShillManagerClientStubImplDevices
= 2;
342 EXPECT_EQ(kNumShillManagerClientStubImplDevices
,
343 listener_
->entries(shill::kDevicesProperty
).size());
345 listener_
->reset_list_updates();
346 const std::string
kTestDevicePath("test_wifi_device1");
347 AddDevice(shill::kTypeWifi
, kTestDevicePath
);
348 message_loop_
.RunUntilIdle();
349 EXPECT_EQ(1, listener_
->list_updates(shill::kDevicesProperty
));
350 EXPECT_EQ(kNumShillManagerClientStubImplDevices
+ 1,
351 listener_
->entries(shill::kDevicesProperty
).size());
354 listener_
->reset_list_updates();
355 RemoveDevice(kTestDevicePath
);
356 message_loop_
.RunUntilIdle();
357 EXPECT_EQ(1, listener_
->list_updates(shill::kDevicesProperty
));
358 EXPECT_EQ(kNumShillManagerClientStubImplDevices
,
359 listener_
->entries(shill::kDevicesProperty
).size());
361 EXPECT_EQ(0, listener_
->errors());
364 TEST_F(ShillPropertyHandlerTest
, ShillPropertyHandlerServicePropertyChanged
) {
365 const size_t kNumShillManagerClientStubImplServices
= 4;
366 EXPECT_EQ(kNumShillManagerClientStubImplServices
,
367 listener_
->entries(shill::kServiceCompleteListProperty
).size());
370 listener_
->reset_list_updates();
371 const std::string
kTestServicePath("test_wifi_service1");
372 AddService(shill::kTypeWifi
, kTestServicePath
, shill::kStateIdle
);
373 message_loop_
.RunUntilIdle();
374 // Add should trigger a service list update and update entries.
375 EXPECT_EQ(1, listener_
->list_updates(shill::kServiceCompleteListProperty
));
376 EXPECT_EQ(kNumShillManagerClientStubImplServices
+ 1,
377 listener_
->entries(shill::kServiceCompleteListProperty
).size());
378 // Service receives an initial property update.
379 EXPECT_EQ(1, listener_
->initial_property_updates(
380 shill::kServiceCompleteListProperty
)[kTestServicePath
]);
381 // Change a property.
382 base::FundamentalValue
scan_interval(3);
383 DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
384 dbus::ObjectPath(kTestServicePath
),
385 shill::kScanIntervalProperty
,
387 base::Bind(&base::DoNothing
), base::Bind(&ErrorCallbackFunction
));
388 message_loop_
.RunUntilIdle();
389 // Property change triggers an update (but not a service list update).
390 EXPECT_EQ(1, listener_
->property_updates(
391 shill::kServiceCompleteListProperty
)[kTestServicePath
]);
393 // Change the visibility of a service. This will trigger a service list
395 listener_
->reset_list_updates();
396 DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
397 dbus::ObjectPath(kTestServicePath
),
398 shill::kVisibleProperty
,
399 base::FundamentalValue(false),
400 base::Bind(&base::DoNothing
), base::Bind(&ErrorCallbackFunction
));
401 message_loop_
.RunUntilIdle();
402 EXPECT_EQ(1, listener_
->list_updates(shill::kServiceCompleteListProperty
));
404 // Remove a service. This will update the entries and signal a service list
406 listener_
->reset_list_updates();
407 RemoveService(kTestServicePath
);
408 message_loop_
.RunUntilIdle();
409 EXPECT_EQ(1, listener_
->list_updates(shill::kServiceCompleteListProperty
));
410 EXPECT_EQ(kNumShillManagerClientStubImplServices
,
411 listener_
->entries(shill::kServiceCompleteListProperty
).size());
413 EXPECT_EQ(0, listener_
->errors());
416 TEST_F(ShillPropertyHandlerTest
, ShillPropertyHandlerIPConfigPropertyChanged
) {
417 // Set the properties for an IP Config object.
418 const std::string
kTestIPConfigPath("test_ip_config_path");
420 base::StringValue
ip_address("192.168.1.1");
421 DBusThreadManager::Get()->GetShillIPConfigClient()->SetProperty(
422 dbus::ObjectPath(kTestIPConfigPath
),
423 shill::kAddressProperty
, ip_address
,
424 base::Bind(&DoNothingWithCallStatus
));
425 base::ListValue dns_servers
;
426 dns_servers
.Append(new base::StringValue("192.168.1.100"));
427 dns_servers
.Append(new base::StringValue("192.168.1.101"));
428 DBusThreadManager::Get()->GetShillIPConfigClient()->SetProperty(
429 dbus::ObjectPath(kTestIPConfigPath
),
430 shill::kNameServersProperty
, dns_servers
,
431 base::Bind(&DoNothingWithCallStatus
));
432 base::FundamentalValue
prefixlen(8);
433 DBusThreadManager::Get()->GetShillIPConfigClient()->SetProperty(
434 dbus::ObjectPath(kTestIPConfigPath
),
435 shill::kPrefixlenProperty
, prefixlen
,
436 base::Bind(&DoNothingWithCallStatus
));
437 base::StringValue
gateway("192.0.0.1");
438 DBusThreadManager::Get()->GetShillIPConfigClient()->SetProperty(
439 dbus::ObjectPath(kTestIPConfigPath
),
440 shill::kGatewayProperty
, gateway
,
441 base::Bind(&DoNothingWithCallStatus
));
442 message_loop_
.RunUntilIdle();
444 // Add a service with an empty ipconfig and then update
445 // its ipconfig property.
446 const std::string
kTestServicePath1("test_wifi_service1");
447 AddService(shill::kTypeWifi
, kTestServicePath1
, shill::kStateIdle
);
448 message_loop_
.RunUntilIdle();
449 // This is the initial property update.
450 EXPECT_EQ(1, listener_
->initial_property_updates(
451 shill::kServiceCompleteListProperty
)[kTestServicePath1
]);
452 DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
453 dbus::ObjectPath(kTestServicePath1
),
454 shill::kIPConfigProperty
,
455 base::StringValue(kTestIPConfigPath
),
456 base::Bind(&base::DoNothing
), base::Bind(&ErrorCallbackFunction
));
457 message_loop_
.RunUntilIdle();
458 // IPConfig property change on the service should trigger an IPConfigs update.
459 EXPECT_EQ(1, listener_
->property_updates(
460 shill::kIPConfigsProperty
)[kTestIPConfigPath
]);
462 // Now, Add a new service with the IPConfig already set.
463 const std::string
kTestServicePath2("test_wifi_service2");
464 AddServiceWithIPConfig(shill::kTypeWifi
, kTestServicePath2
,
465 shill::kStateIdle
, kTestIPConfigPath
);
466 message_loop_
.RunUntilIdle();
467 // A service with the IPConfig property already set should trigger an
468 // additional IPConfigs update.
469 EXPECT_EQ(2, listener_
->property_updates(
470 shill::kIPConfigsProperty
)[kTestIPConfigPath
]);
473 TEST_F(ShillPropertyHandlerTest
, ShillPropertyHandlerServiceList
) {
474 // Add an entry to the profile only.
475 const std::string
kTestServicePath1("stub_wifi_profile_only1");
476 AddServiceToProfile(shill::kTypeWifi
, kTestServicePath1
, false /* visible */);
477 message_loop_
.RunUntilIdle();
479 // Update the Manager properties. This should trigger a single list update,
480 // an initial property update, and a regular property update.
481 listener_
->reset_list_updates();
482 shill_property_handler_
->UpdateManagerProperties();
483 message_loop_
.RunUntilIdle();
484 EXPECT_EQ(1, listener_
->list_updates(shill::kServiceCompleteListProperty
));
485 EXPECT_EQ(1, listener_
->initial_property_updates(
486 shill::kServiceCompleteListProperty
)[kTestServicePath1
]);
487 EXPECT_EQ(1, listener_
->property_updates(
488 shill::kServiceCompleteListProperty
)[kTestServicePath1
]);
490 // Add a new entry to the services and the profile; should also trigger a
491 // service list update, and a property update.
492 listener_
->reset_list_updates();
493 const std::string
kTestServicePath2("stub_wifi_profile_only2");
494 AddServiceToProfile(shill::kTypeWifi
, kTestServicePath2
, true);
495 shill_property_handler_
->UpdateManagerProperties();
496 message_loop_
.RunUntilIdle();
497 EXPECT_EQ(1, listener_
->list_updates(shill::kServiceCompleteListProperty
));
498 EXPECT_EQ(1, listener_
->initial_property_updates(
499 shill::kServiceCompleteListProperty
)[kTestServicePath2
]);
500 EXPECT_EQ(1, listener_
->property_updates(
501 shill::kServiceCompleteListProperty
)[kTestServicePath2
]);
504 } // namespace chromeos