1 // Copyright 2013 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/dbus/fake_shill_service_client.h"
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/stl_util.h"
11 #include "base/strings/string_util.h"
12 #include "base/values.h"
13 #include "chromeos/dbus/dbus_thread_manager.h"
14 #include "chromeos/dbus/shill_device_client.h"
15 #include "chromeos/dbus/shill_manager_client.h"
16 #include "chromeos/dbus/shill_profile_client.h"
17 #include "chromeos/dbus/shill_property_changed_observer.h"
18 #include "chromeos/network/shill_property_util.h"
19 #include "dbus/bus.h"
20 #include "dbus/message.h"
21 #include "dbus/object_path.h"
22 #include "third_party/cros_system_api/dbus/service_constants.h"
23
24 namespace chromeos {
25
26 namespace {
27
PassStubListValue(const ShillServiceClient::ListValueCallback & callback,base::ListValue * value)28 void PassStubListValue(const ShillServiceClient::ListValueCallback& callback,
29 base::ListValue* value) {
30 callback.Run(*value);
31 }
32
PassStubServiceProperties(const ShillServiceClient::DictionaryValueCallback & callback,DBusMethodCallStatus call_status,const base::DictionaryValue * properties)33 void PassStubServiceProperties(
34 const ShillServiceClient::DictionaryValueCallback& callback,
35 DBusMethodCallStatus call_status,
36 const base::DictionaryValue* properties) {
37 callback.Run(call_status, *properties);
38 }
39
CallSortManagerServices()40 void CallSortManagerServices() {
41 DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()->
42 SortManagerServices(true);
43 }
44
GetInteractiveDelay()45 int GetInteractiveDelay() {
46 return DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()->
47 GetInteractiveDelay();
48 }
49
50 } // namespace
51
FakeShillServiceClient()52 FakeShillServiceClient::FakeShillServiceClient() : weak_ptr_factory_(this) {
53 }
54
~FakeShillServiceClient()55 FakeShillServiceClient::~FakeShillServiceClient() {
56 STLDeleteContainerPairSecondPointers(
57 observer_list_.begin(), observer_list_.end());
58 }
59
60
61 // ShillServiceClient overrides.
62
Init(dbus::Bus * bus)63 void FakeShillServiceClient::Init(dbus::Bus* bus) {
64 }
65
AddPropertyChangedObserver(const dbus::ObjectPath & service_path,ShillPropertyChangedObserver * observer)66 void FakeShillServiceClient::AddPropertyChangedObserver(
67 const dbus::ObjectPath& service_path,
68 ShillPropertyChangedObserver* observer) {
69 GetObserverList(service_path).AddObserver(observer);
70 }
71
RemovePropertyChangedObserver(const dbus::ObjectPath & service_path,ShillPropertyChangedObserver * observer)72 void FakeShillServiceClient::RemovePropertyChangedObserver(
73 const dbus::ObjectPath& service_path,
74 ShillPropertyChangedObserver* observer) {
75 GetObserverList(service_path).RemoveObserver(observer);
76 }
77
GetProperties(const dbus::ObjectPath & service_path,const DictionaryValueCallback & callback)78 void FakeShillServiceClient::GetProperties(
79 const dbus::ObjectPath& service_path,
80 const DictionaryValueCallback& callback) {
81 base::DictionaryValue* nested_dict = NULL;
82 scoped_ptr<base::DictionaryValue> result_properties;
83 DBusMethodCallStatus call_status;
84 stub_services_.GetDictionaryWithoutPathExpansion(service_path.value(),
85 &nested_dict);
86 if (nested_dict) {
87 result_properties.reset(nested_dict->DeepCopy());
88 // Remove credentials that Shill wouldn't send.
89 result_properties->RemoveWithoutPathExpansion(shill::kPassphraseProperty,
90 NULL);
91 call_status = DBUS_METHOD_CALL_SUCCESS;
92 } else {
93 // This may happen if we remove services from the list.
94 VLOG(2) << "Properties not found for: " << service_path.value();
95 result_properties.reset(new base::DictionaryValue);
96 call_status = DBUS_METHOD_CALL_FAILURE;
97 }
98
99 base::MessageLoop::current()->PostTask(
100 FROM_HERE,
101 base::Bind(&PassStubServiceProperties,
102 callback,
103 call_status,
104 base::Owned(result_properties.release())));
105 }
106
SetProperty(const dbus::ObjectPath & service_path,const std::string & name,const base::Value & value,const base::Closure & callback,const ErrorCallback & error_callback)107 void FakeShillServiceClient::SetProperty(const dbus::ObjectPath& service_path,
108 const std::string& name,
109 const base::Value& value,
110 const base::Closure& callback,
111 const ErrorCallback& error_callback) {
112 if (!SetServiceProperty(service_path.value(), name, value)) {
113 LOG(ERROR) << "Service not found: " << service_path.value();
114 error_callback.Run("Error.InvalidService", "Invalid Service");
115 return;
116 }
117 base::MessageLoop::current()->PostTask(FROM_HERE, callback);
118 }
119
SetProperties(const dbus::ObjectPath & service_path,const base::DictionaryValue & properties,const base::Closure & callback,const ErrorCallback & error_callback)120 void FakeShillServiceClient::SetProperties(
121 const dbus::ObjectPath& service_path,
122 const base::DictionaryValue& properties,
123 const base::Closure& callback,
124 const ErrorCallback& error_callback) {
125 for (base::DictionaryValue::Iterator iter(properties);
126 !iter.IsAtEnd(); iter.Advance()) {
127 if (!SetServiceProperty(service_path.value(), iter.key(), iter.value())) {
128 LOG(ERROR) << "Service not found: " << service_path.value();
129 error_callback.Run("Error.InvalidService", "Invalid Service");
130 return;
131 }
132 }
133 base::MessageLoop::current()->PostTask(FROM_HERE, callback);
134 }
135
ClearProperty(const dbus::ObjectPath & service_path,const std::string & name,const base::Closure & callback,const ErrorCallback & error_callback)136 void FakeShillServiceClient::ClearProperty(
137 const dbus::ObjectPath& service_path,
138 const std::string& name,
139 const base::Closure& callback,
140 const ErrorCallback& error_callback) {
141 base::DictionaryValue* dict = NULL;
142 if (!stub_services_.GetDictionaryWithoutPathExpansion(
143 service_path.value(), &dict)) {
144 error_callback.Run("Error.InvalidService", "Invalid Service");
145 return;
146 }
147 dict->RemoveWithoutPathExpansion(name, NULL);
148 // Note: Shill does not send notifications when properties are cleared.
149 base::MessageLoop::current()->PostTask(FROM_HERE, callback);
150 }
151
ClearProperties(const dbus::ObjectPath & service_path,const std::vector<std::string> & names,const ListValueCallback & callback,const ErrorCallback & error_callback)152 void FakeShillServiceClient::ClearProperties(
153 const dbus::ObjectPath& service_path,
154 const std::vector<std::string>& names,
155 const ListValueCallback& callback,
156 const ErrorCallback& error_callback) {
157 base::DictionaryValue* dict = NULL;
158 if (!stub_services_.GetDictionaryWithoutPathExpansion(
159 service_path.value(), &dict)) {
160 error_callback.Run("Error.InvalidService", "Invalid Service");
161 return;
162 }
163 scoped_ptr<base::ListValue> results(new base::ListValue);
164 for (std::vector<std::string>::const_iterator iter = names.begin();
165 iter != names.end(); ++iter) {
166 dict->RemoveWithoutPathExpansion(*iter, NULL);
167 // Note: Shill does not send notifications when properties are cleared.
168 results->AppendBoolean(true);
169 }
170 base::MessageLoop::current()->PostTask(
171 FROM_HERE,
172 base::Bind(&PassStubListValue,
173 callback, base::Owned(results.release())));
174 }
175
Connect(const dbus::ObjectPath & service_path,const base::Closure & callback,const ErrorCallback & error_callback)176 void FakeShillServiceClient::Connect(const dbus::ObjectPath& service_path,
177 const base::Closure& callback,
178 const ErrorCallback& error_callback) {
179 VLOG(1) << "FakeShillServiceClient::Connect: " << service_path.value();
180 base::DictionaryValue* service_properties = NULL;
181 if (!stub_services_.GetDictionary(
182 service_path.value(), &service_properties)) {
183 LOG(ERROR) << "Service not found: " << service_path.value();
184 error_callback.Run("Error.InvalidService", "Invalid Service");
185 return;
186 }
187
188 // Set any other services of the same Type to 'offline' first, before setting
189 // State to Association which will trigger sorting Manager.Services and
190 // sending an update.
191 SetOtherServicesOffline(service_path.value());
192
193 // Set Associating.
194 base::StringValue associating_value(shill::kStateAssociation);
195 SetServiceProperty(service_path.value(),
196 shill::kStateProperty,
197 associating_value);
198
199 // Stay Associating until the state is changed again after a delay.
200 base::MessageLoop::current()->PostDelayedTask(
201 FROM_HERE,
202 base::Bind(&FakeShillServiceClient::ContinueConnect,
203 weak_ptr_factory_.GetWeakPtr(),
204 service_path.value()),
205 base::TimeDelta::FromSeconds(GetInteractiveDelay()));
206
207 callback.Run();
208 }
209
Disconnect(const dbus::ObjectPath & service_path,const base::Closure & callback,const ErrorCallback & error_callback)210 void FakeShillServiceClient::Disconnect(const dbus::ObjectPath& service_path,
211 const base::Closure& callback,
212 const ErrorCallback& error_callback) {
213 base::Value* service;
214 if (!stub_services_.Get(service_path.value(), &service)) {
215 error_callback.Run("Error.InvalidService", "Invalid Service");
216 return;
217 }
218 // Set Idle after a delay
219 base::StringValue idle_value(shill::kStateIdle);
220 base::MessageLoop::current()->PostDelayedTask(
221 FROM_HERE,
222 base::Bind(&FakeShillServiceClient::SetProperty,
223 weak_ptr_factory_.GetWeakPtr(),
224 service_path,
225 shill::kStateProperty,
226 idle_value,
227 base::Bind(&base::DoNothing),
228 error_callback),
229 base::TimeDelta::FromSeconds(GetInteractiveDelay()));
230 callback.Run();
231 }
232
Remove(const dbus::ObjectPath & service_path,const base::Closure & callback,const ErrorCallback & error_callback)233 void FakeShillServiceClient::Remove(const dbus::ObjectPath& service_path,
234 const base::Closure& callback,
235 const ErrorCallback& error_callback) {
236 base::MessageLoop::current()->PostTask(FROM_HERE, callback);
237 }
238
ActivateCellularModem(const dbus::ObjectPath & service_path,const std::string & carrier,const base::Closure & callback,const ErrorCallback & error_callback)239 void FakeShillServiceClient::ActivateCellularModem(
240 const dbus::ObjectPath& service_path,
241 const std::string& carrier,
242 const base::Closure& callback,
243 const ErrorCallback& error_callback) {
244 base::DictionaryValue* service_properties =
245 GetModifiableServiceProperties(service_path.value(), false);
246 if (!service_properties) {
247 LOG(ERROR) << "Service not found: " << service_path.value();
248 error_callback.Run("Error.InvalidService", "Invalid Service");
249 }
250 SetServiceProperty(service_path.value(),
251 shill::kActivationStateProperty,
252 base::StringValue(shill::kActivationStateActivating));
253 // Set Activated after a delay
254 base::MessageLoop::current()->PostDelayedTask(
255 FROM_HERE,
256 base::Bind(&FakeShillServiceClient::SetCellularActivated,
257 weak_ptr_factory_.GetWeakPtr(),
258 service_path,
259 error_callback),
260 base::TimeDelta::FromSeconds(GetInteractiveDelay()));
261
262 base::MessageLoop::current()->PostTask(FROM_HERE, callback);
263 }
264
CompleteCellularActivation(const dbus::ObjectPath & service_path,const base::Closure & callback,const ErrorCallback & error_callback)265 void FakeShillServiceClient::CompleteCellularActivation(
266 const dbus::ObjectPath& service_path,
267 const base::Closure& callback,
268 const ErrorCallback& error_callback) {
269 base::MessageLoop::current()->PostTask(FROM_HERE, callback);
270 }
271
GetLoadableProfileEntries(const dbus::ObjectPath & service_path,const DictionaryValueCallback & callback)272 void FakeShillServiceClient::GetLoadableProfileEntries(
273 const dbus::ObjectPath& service_path,
274 const DictionaryValueCallback& callback) {
275 // Provide a dictionary with a single { profile_path, service_path } entry
276 // if the Profile property is set, or an empty dictionary.
277 scoped_ptr<base::DictionaryValue> result_properties(
278 new base::DictionaryValue);
279 base::DictionaryValue* service_properties =
280 GetModifiableServiceProperties(service_path.value(), false);
281 if (service_properties) {
282 std::string profile_path;
283 if (service_properties->GetStringWithoutPathExpansion(
284 shill::kProfileProperty, &profile_path)) {
285 result_properties->SetStringWithoutPathExpansion(
286 profile_path, service_path.value());
287 }
288 } else {
289 LOG(WARNING) << "Service not in profile: " << service_path.value();
290 }
291
292 DBusMethodCallStatus call_status = DBUS_METHOD_CALL_SUCCESS;
293 base::MessageLoop::current()->PostTask(
294 FROM_HERE,
295 base::Bind(&PassStubServiceProperties,
296 callback,
297 call_status,
298 base::Owned(result_properties.release())));
299 }
300
GetTestInterface()301 ShillServiceClient::TestInterface* FakeShillServiceClient::GetTestInterface() {
302 return this;
303 }
304
305 // ShillServiceClient::TestInterface overrides.
306
AddService(const std::string & service_path,const std::string & name,const std::string & type,const std::string & state,bool visible)307 void FakeShillServiceClient::AddService(const std::string& service_path,
308 const std::string& name,
309 const std::string& type,
310 const std::string& state,
311 bool visible) {
312 AddServiceWithIPConfig(service_path, "" /* guid */, name,
313 type, state, "" /* ipconfig_path */,
314 visible);
315 }
316
AddServiceWithIPConfig(const std::string & service_path,const std::string & guid,const std::string & name,const std::string & type,const std::string & state,const std::string & ipconfig_path,bool visible)317 void FakeShillServiceClient::AddServiceWithIPConfig(
318 const std::string& service_path,
319 const std::string& guid,
320 const std::string& name,
321 const std::string& type,
322 const std::string& state,
323 const std::string& ipconfig_path,
324 bool visible) {
325 base::DictionaryValue* properties = SetServiceProperties(
326 service_path, guid, name, type, state, visible);
327
328 std::string profile_path;
329 if (properties->GetStringWithoutPathExpansion(shill::kProfileProperty,
330 &profile_path) &&
331 !profile_path.empty()) {
332 DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface()->
333 UpdateService(profile_path, service_path);
334 }
335
336 if (!ipconfig_path.empty()) {
337 properties->SetWithoutPathExpansion(
338 shill::kIPConfigProperty,
339 new base::StringValue(ipconfig_path));
340 }
341
342 DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()->
343 AddManagerService(service_path, true);
344 }
345
346
SetServiceProperties(const std::string & service_path,const std::string & guid,const std::string & name,const std::string & type,const std::string & state,bool visible)347 base::DictionaryValue* FakeShillServiceClient::SetServiceProperties(
348 const std::string& service_path,
349 const std::string& guid,
350 const std::string& name,
351 const std::string& type,
352 const std::string& state,
353 bool visible) {
354 base::DictionaryValue* properties =
355 GetModifiableServiceProperties(service_path, true);
356 connect_behavior_.erase(service_path);
357
358 std::string profile_path;
359 base::DictionaryValue profile_properties;
360 if (DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface()->
361 GetService(service_path, &profile_path, &profile_properties)) {
362 properties->SetWithoutPathExpansion(
363 shill::kProfileProperty,
364 new base::StringValue(profile_path));
365 }
366
367 // If |guid| is provided, set Service.GUID to that. Otherwise if a GUID is
368 // stored in a profile entry, use that. Otherwise leave it blank. Shill does
369 // not enforce a valid guid, we do that at the NetworkStateHandler layer.
370 std::string guid_to_set = guid;
371 if (guid_to_set.empty()) {
372 profile_properties.GetStringWithoutPathExpansion(
373 shill::kGuidProperty, &guid_to_set);
374 }
375 if (!guid_to_set.empty()) {
376 properties->SetWithoutPathExpansion(shill::kGuidProperty,
377 new base::StringValue(guid_to_set));
378 }
379 shill_property_util::SetSSID(name, properties);
380 properties->SetWithoutPathExpansion(
381 shill::kNameProperty,
382 new base::StringValue(name));
383 std::string device_path =
384 DBusThreadManager::Get()->GetShillDeviceClient()->GetTestInterface()->
385 GetDevicePathForType(type);
386 properties->SetWithoutPathExpansion(
387 shill::kDeviceProperty,
388 new base::StringValue(device_path));
389 properties->SetWithoutPathExpansion(
390 shill::kTypeProperty,
391 new base::StringValue(type));
392 properties->SetWithoutPathExpansion(
393 shill::kStateProperty,
394 new base::StringValue(state));
395 properties->SetWithoutPathExpansion(
396 shill::kVisibleProperty,
397 new base::FundamentalValue(visible));
398 if (type == shill::kTypeWifi) {
399 properties->SetWithoutPathExpansion(
400 shill::kSecurityProperty,
401 new base::StringValue(shill::kSecurityNone));
402 }
403 return properties;
404 }
405
RemoveService(const std::string & service_path)406 void FakeShillServiceClient::RemoveService(const std::string& service_path) {
407 stub_services_.RemoveWithoutPathExpansion(service_path, NULL);
408 connect_behavior_.erase(service_path);
409 DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()->
410 RemoveManagerService(service_path);
411 }
412
SetServiceProperty(const std::string & service_path,const std::string & property,const base::Value & value)413 bool FakeShillServiceClient::SetServiceProperty(const std::string& service_path,
414 const std::string& property,
415 const base::Value& value) {
416 base::DictionaryValue* dict = NULL;
417 if (!stub_services_.GetDictionaryWithoutPathExpansion(service_path, &dict))
418 return false;
419
420 VLOG(1) << "Service.SetProperty: " << property << " = " << value
421 << " For: " << service_path;
422
423 base::DictionaryValue new_properties;
424 std::string changed_property;
425 bool case_sensitive = true;
426 if (StartsWithASCII(property, "Provider.", case_sensitive) ||
427 StartsWithASCII(property, "OpenVPN.", case_sensitive) ||
428 StartsWithASCII(property, "L2TPIPsec.", case_sensitive)) {
429 // These properties are only nested within the Provider dictionary if read
430 // from Shill.
431 base::DictionaryValue* provider = new base::DictionaryValue;
432 provider->SetWithoutPathExpansion(property, value.DeepCopy());
433 new_properties.SetWithoutPathExpansion(shill::kProviderProperty, provider);
434 changed_property = shill::kProviderProperty;
435 } else {
436 new_properties.SetWithoutPathExpansion(property, value.DeepCopy());
437 changed_property = property;
438 }
439
440 dict->MergeDictionary(&new_properties);
441
442 // Add or update the profile entry.
443 if (property == shill::kProfileProperty) {
444 std::string profile_path;
445 if (value.GetAsString(&profile_path)) {
446 DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface()->
447 AddService(profile_path, service_path);
448 } else {
449 LOG(ERROR) << "Profile value is not a String!";
450 }
451 } else {
452 std::string profile_path;
453 if (dict->GetStringWithoutPathExpansion(
454 shill::kProfileProperty, &profile_path) && !profile_path.empty()) {
455 DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface()->
456 UpdateService(profile_path, service_path);
457 }
458 }
459
460 // Notify the Manager if the state changed (affects DefaultService).
461 if (property == shill::kStateProperty) {
462 std::string state;
463 value.GetAsString(&state);
464 DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()->
465 ServiceStateChanged(service_path, state);
466 }
467
468 // If the State or Visibility changes, the sort order of service lists may
469 // change and the DefaultService property may change.
470 if (property == shill::kStateProperty ||
471 property == shill::kVisibleProperty) {
472 base::MessageLoop::current()->PostTask(
473 FROM_HERE, base::Bind(&CallSortManagerServices));
474 }
475
476 // Notifiy Chrome of the property change.
477 base::MessageLoop::current()->PostTask(
478 FROM_HERE,
479 base::Bind(&FakeShillServiceClient::NotifyObserversPropertyChanged,
480 weak_ptr_factory_.GetWeakPtr(),
481 dbus::ObjectPath(service_path), changed_property));
482 return true;
483 }
484
GetServiceProperties(const std::string & service_path) const485 const base::DictionaryValue* FakeShillServiceClient::GetServiceProperties(
486 const std::string& service_path) const {
487 const base::DictionaryValue* properties = NULL;
488 stub_services_.GetDictionaryWithoutPathExpansion(service_path, &properties);
489 return properties;
490 }
491
ClearServices()492 void FakeShillServiceClient::ClearServices() {
493 DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()->
494 ClearManagerServices();
495
496 stub_services_.Clear();
497 connect_behavior_.clear();
498 }
499
SetConnectBehavior(const std::string & service_path,const base::Closure & behavior)500 void FakeShillServiceClient::SetConnectBehavior(const std::string& service_path,
501 const base::Closure& behavior) {
502 connect_behavior_[service_path] = behavior;
503 }
504
NotifyObserversPropertyChanged(const dbus::ObjectPath & service_path,const std::string & property)505 void FakeShillServiceClient::NotifyObserversPropertyChanged(
506 const dbus::ObjectPath& service_path,
507 const std::string& property) {
508 base::DictionaryValue* dict = NULL;
509 std::string path = service_path.value();
510 if (!stub_services_.GetDictionaryWithoutPathExpansion(path, &dict)) {
511 LOG(ERROR) << "Notify for unknown service: " << path;
512 return;
513 }
514 base::Value* value = NULL;
515 if (!dict->GetWithoutPathExpansion(property, &value)) {
516 LOG(ERROR) << "Notify for unknown property: "
517 << path << " : " << property;
518 return;
519 }
520 FOR_EACH_OBSERVER(ShillPropertyChangedObserver,
521 GetObserverList(service_path),
522 OnPropertyChanged(property, *value));
523 }
524
GetModifiableServiceProperties(const std::string & service_path,bool create_if_missing)525 base::DictionaryValue* FakeShillServiceClient::GetModifiableServiceProperties(
526 const std::string& service_path, bool create_if_missing) {
527 base::DictionaryValue* properties = NULL;
528 if (!stub_services_.GetDictionaryWithoutPathExpansion(service_path,
529 &properties) &&
530 create_if_missing) {
531 properties = new base::DictionaryValue;
532 stub_services_.Set(service_path, properties);
533 }
534 return properties;
535 }
536
537 FakeShillServiceClient::PropertyObserverList&
GetObserverList(const dbus::ObjectPath & device_path)538 FakeShillServiceClient::GetObserverList(const dbus::ObjectPath& device_path) {
539 std::map<dbus::ObjectPath, PropertyObserverList*>::iterator iter =
540 observer_list_.find(device_path);
541 if (iter != observer_list_.end())
542 return *(iter->second);
543 PropertyObserverList* observer_list = new PropertyObserverList();
544 observer_list_[device_path] = observer_list;
545 return *observer_list;
546 }
547
SetOtherServicesOffline(const std::string & service_path)548 void FakeShillServiceClient::SetOtherServicesOffline(
549 const std::string& service_path) {
550 const base::DictionaryValue* service_properties = GetServiceProperties(
551 service_path);
552 if (!service_properties) {
553 LOG(ERROR) << "Missing service: " << service_path;
554 return;
555 }
556 std::string service_type;
557 service_properties->GetString(shill::kTypeProperty, &service_type);
558 // Set all other services of the same type to offline (Idle).
559 for (base::DictionaryValue::Iterator iter(stub_services_);
560 !iter.IsAtEnd(); iter.Advance()) {
561 std::string path = iter.key();
562 if (path == service_path)
563 continue;
564 base::DictionaryValue* properties;
565 if (!stub_services_.GetDictionaryWithoutPathExpansion(path, &properties))
566 NOTREACHED();
567
568 std::string type;
569 properties->GetString(shill::kTypeProperty, &type);
570 if (type != service_type)
571 continue;
572 properties->SetWithoutPathExpansion(
573 shill::kStateProperty,
574 new base::StringValue(shill::kStateIdle));
575 }
576 }
577
SetCellularActivated(const dbus::ObjectPath & service_path,const ErrorCallback & error_callback)578 void FakeShillServiceClient::SetCellularActivated(
579 const dbus::ObjectPath& service_path,
580 const ErrorCallback& error_callback) {
581 SetProperty(service_path,
582 shill::kActivationStateProperty,
583 base::StringValue(shill::kActivationStateActivated),
584 base::Bind(&base::DoNothing),
585 error_callback);
586 SetProperty(service_path,
587 shill::kConnectableProperty,
588 base::FundamentalValue(true),
589 base::Bind(&base::DoNothing),
590 error_callback);
591 }
592
ContinueConnect(const std::string & service_path)593 void FakeShillServiceClient::ContinueConnect(
594 const std::string& service_path) {
595 VLOG(1) << "FakeShillServiceClient::ContinueConnect: " << service_path;
596 base::DictionaryValue* service_properties = NULL;
597 if (!stub_services_.GetDictionary(service_path, &service_properties)) {
598 LOG(ERROR) << "Service not found: " << service_path;
599 return;
600 }
601
602 if (ContainsKey(connect_behavior_, service_path)) {
603 const base::Closure& custom_connect_behavior =
604 connect_behavior_[service_path];
605 custom_connect_behavior.Run();
606 return;
607 }
608
609 // No custom connect behavior set, continue with the default connect behavior.
610 std::string passphrase;
611 service_properties->GetStringWithoutPathExpansion(
612 shill::kPassphraseProperty, &passphrase);
613 if (passphrase == "failure") {
614 // Simulate a password failure.
615 SetServiceProperty(service_path,
616 shill::kStateProperty,
617 base::StringValue(shill::kStateFailure));
618 base::MessageLoop::current()->PostTask(
619 FROM_HERE,
620 base::Bind(
621 base::IgnoreResult(&FakeShillServiceClient::SetServiceProperty),
622 weak_ptr_factory_.GetWeakPtr(),
623 service_path,
624 shill::kErrorProperty,
625 base::StringValue(shill::kErrorBadPassphrase)));
626 } else {
627 // Set Online.
628 SetServiceProperty(service_path,
629 shill::kStateProperty,
630 base::StringValue(shill::kStateOnline));
631 }
632 }
633
634 } // namespace chromeos
635