Add default implementations for AppWindowRegistry::Observer notifications.
[chromium-blink-merge.git] / chromeos / dbus / fake_shill_service_client.cc
blob30673f3f14ca7df882944c61dbe7e5cc6b7d91a8
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.
5 #include "chromeos/dbus/fake_shill_service_client.h"
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_property_changed_observer.h"
17 #include "chromeos/network/shill_property_util.h"
18 #include "dbus/bus.h"
19 #include "dbus/message.h"
20 #include "dbus/object_path.h"
21 #include "third_party/cros_system_api/dbus/service_constants.h"
23 namespace chromeos {
25 namespace {
27 void PassStubListValue(const ShillServiceClient::ListValueCallback& callback,
28 base::ListValue* value) {
29 callback.Run(*value);
32 void PassStubServiceProperties(
33 const ShillServiceClient::DictionaryValueCallback& callback,
34 DBusMethodCallStatus call_status,
35 const base::DictionaryValue* properties) {
36 callback.Run(call_status, *properties);
39 void CallSortManagerServices() {
40 DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()->
41 SortManagerServices();
44 int GetInteractiveDelay() {
45 return DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()->
46 GetInteractiveDelay();
49 } // namespace
51 FakeShillServiceClient::FakeShillServiceClient() : weak_ptr_factory_(this) {
54 FakeShillServiceClient::~FakeShillServiceClient() {
55 STLDeleteContainerPairSecondPointers(
56 observer_list_.begin(), observer_list_.end());
60 // ShillServiceClient overrides.
62 void FakeShillServiceClient::Init(dbus::Bus* bus) {
65 void FakeShillServiceClient::AddPropertyChangedObserver(
66 const dbus::ObjectPath& service_path,
67 ShillPropertyChangedObserver* observer) {
68 GetObserverList(service_path).AddObserver(observer);
71 void FakeShillServiceClient::RemovePropertyChangedObserver(
72 const dbus::ObjectPath& service_path,
73 ShillPropertyChangedObserver* observer) {
74 GetObserverList(service_path).RemoveObserver(observer);
77 void FakeShillServiceClient::GetProperties(
78 const dbus::ObjectPath& service_path,
79 const DictionaryValueCallback& callback) {
80 base::DictionaryValue* nested_dict = NULL;
81 scoped_ptr<base::DictionaryValue> result_properties;
82 DBusMethodCallStatus call_status;
83 stub_services_.GetDictionaryWithoutPathExpansion(service_path.value(),
84 &nested_dict);
85 if (nested_dict) {
86 result_properties.reset(nested_dict->DeepCopy());
87 // Remove credentials that Shill wouldn't send.
88 result_properties->RemoveWithoutPathExpansion(shill::kPassphraseProperty,
89 NULL);
90 call_status = DBUS_METHOD_CALL_SUCCESS;
91 } else {
92 LOG(ERROR) << "Properties not found for: " << service_path.value();
93 result_properties.reset(new base::DictionaryValue);
94 call_status = DBUS_METHOD_CALL_FAILURE;
97 base::MessageLoop::current()->PostTask(
98 FROM_HERE,
99 base::Bind(&PassStubServiceProperties,
100 callback,
101 call_status,
102 base::Owned(result_properties.release())));
105 void FakeShillServiceClient::SetProperty(const dbus::ObjectPath& service_path,
106 const std::string& name,
107 const base::Value& value,
108 const base::Closure& callback,
109 const ErrorCallback& error_callback) {
110 if (!SetServiceProperty(service_path.value(), name, value)) {
111 LOG(ERROR) << "Service not found: " << service_path.value();
112 error_callback.Run("Error.InvalidService", "Invalid Service");
113 return;
115 base::MessageLoop::current()->PostTask(FROM_HERE, callback);
118 void FakeShillServiceClient::SetProperties(
119 const dbus::ObjectPath& service_path,
120 const base::DictionaryValue& properties,
121 const base::Closure& callback,
122 const ErrorCallback& error_callback) {
123 for (base::DictionaryValue::Iterator iter(properties);
124 !iter.IsAtEnd(); iter.Advance()) {
125 if (!SetServiceProperty(service_path.value(), iter.key(), iter.value())) {
126 LOG(ERROR) << "Service not found: " << service_path.value();
127 error_callback.Run("Error.InvalidService", "Invalid Service");
128 return;
131 base::MessageLoop::current()->PostTask(FROM_HERE, callback);
134 void FakeShillServiceClient::ClearProperty(
135 const dbus::ObjectPath& service_path,
136 const std::string& name,
137 const base::Closure& callback,
138 const ErrorCallback& error_callback) {
139 base::DictionaryValue* dict = NULL;
140 if (!stub_services_.GetDictionaryWithoutPathExpansion(
141 service_path.value(), &dict)) {
142 error_callback.Run("Error.InvalidService", "Invalid Service");
143 return;
145 dict->RemoveWithoutPathExpansion(name, NULL);
146 // Note: Shill does not send notifications when properties are cleared.
147 base::MessageLoop::current()->PostTask(FROM_HERE, callback);
150 void FakeShillServiceClient::ClearProperties(
151 const dbus::ObjectPath& service_path,
152 const std::vector<std::string>& names,
153 const ListValueCallback& callback,
154 const ErrorCallback& error_callback) {
155 base::DictionaryValue* dict = NULL;
156 if (!stub_services_.GetDictionaryWithoutPathExpansion(
157 service_path.value(), &dict)) {
158 error_callback.Run("Error.InvalidService", "Invalid Service");
159 return;
161 scoped_ptr<base::ListValue> results(new base::ListValue);
162 for (std::vector<std::string>::const_iterator iter = names.begin();
163 iter != names.end(); ++iter) {
164 dict->RemoveWithoutPathExpansion(*iter, NULL);
165 // Note: Shill does not send notifications when properties are cleared.
166 results->AppendBoolean(true);
168 base::MessageLoop::current()->PostTask(
169 FROM_HERE,
170 base::Bind(&PassStubListValue,
171 callback, base::Owned(results.release())));
174 void FakeShillServiceClient::Connect(const dbus::ObjectPath& service_path,
175 const base::Closure& callback,
176 const ErrorCallback& error_callback) {
177 VLOG(1) << "FakeShillServiceClient::Connect: " << service_path.value();
178 base::DictionaryValue* service_properties = NULL;
179 if (!stub_services_.GetDictionary(
180 service_path.value(), &service_properties)) {
181 LOG(ERROR) << "Service not found: " << service_path.value();
182 error_callback.Run("Error.InvalidService", "Invalid Service");
183 return;
186 // Set any other services of the same Type to 'offline' first, before setting
187 // State to Association which will trigger sorting Manager.Services and
188 // sending an update.
189 SetOtherServicesOffline(service_path.value());
191 // Set Associating.
192 base::StringValue associating_value(shill::kStateAssociation);
193 SetServiceProperty(service_path.value(),
194 shill::kStateProperty,
195 associating_value);
197 // Stay Associating until the state is changed again after a delay.
198 base::MessageLoop::current()->PostDelayedTask(
199 FROM_HERE,
200 base::Bind(&FakeShillServiceClient::ContinueConnect,
201 weak_ptr_factory_.GetWeakPtr(),
202 service_path.value()),
203 base::TimeDelta::FromSeconds(GetInteractiveDelay()));
205 callback.Run();
208 void FakeShillServiceClient::Disconnect(const dbus::ObjectPath& service_path,
209 const base::Closure& callback,
210 const ErrorCallback& error_callback) {
211 base::Value* service;
212 if (!stub_services_.Get(service_path.value(), &service)) {
213 error_callback.Run("Error.InvalidService", "Invalid Service");
214 return;
216 // Set Idle after a delay
217 base::StringValue idle_value(shill::kStateIdle);
218 base::MessageLoop::current()->PostDelayedTask(
219 FROM_HERE,
220 base::Bind(&FakeShillServiceClient::SetProperty,
221 weak_ptr_factory_.GetWeakPtr(),
222 service_path,
223 shill::kStateProperty,
224 idle_value,
225 base::Bind(&base::DoNothing),
226 error_callback),
227 base::TimeDelta::FromSeconds(GetInteractiveDelay()));
228 callback.Run();
231 void FakeShillServiceClient::Remove(const dbus::ObjectPath& service_path,
232 const base::Closure& callback,
233 const ErrorCallback& error_callback) {
234 base::MessageLoop::current()->PostTask(FROM_HERE, callback);
237 void FakeShillServiceClient::ActivateCellularModem(
238 const dbus::ObjectPath& service_path,
239 const std::string& carrier,
240 const base::Closure& callback,
241 const ErrorCallback& error_callback) {
242 base::DictionaryValue* service_properties =
243 GetModifiableServiceProperties(service_path.value(), false);
244 if (!service_properties) {
245 LOG(ERROR) << "Service not found: " << service_path.value();
246 error_callback.Run("Error.InvalidService", "Invalid Service");
248 SetServiceProperty(service_path.value(),
249 shill::kActivationStateProperty,
250 base::StringValue(shill::kActivationStateActivating));
251 // Set Activated after a delay
252 base::MessageLoop::current()->PostDelayedTask(
253 FROM_HERE,
254 base::Bind(&FakeShillServiceClient::SetCellularActivated,
255 weak_ptr_factory_.GetWeakPtr(),
256 service_path,
257 error_callback),
258 base::TimeDelta::FromSeconds(GetInteractiveDelay()));
260 base::MessageLoop::current()->PostTask(FROM_HERE, callback);
263 void FakeShillServiceClient::CompleteCellularActivation(
264 const dbus::ObjectPath& service_path,
265 const base::Closure& callback,
266 const ErrorCallback& error_callback) {
267 base::MessageLoop::current()->PostTask(FROM_HERE, callback);
270 void FakeShillServiceClient::GetLoadableProfileEntries(
271 const dbus::ObjectPath& service_path,
272 const DictionaryValueCallback& callback) {
273 // Provide a dictionary with a single { profile_path, service_path } entry
274 // if the Profile property is set, or an empty dictionary.
275 scoped_ptr<base::DictionaryValue> result_properties(
276 new base::DictionaryValue);
277 base::DictionaryValue* service_properties =
278 GetModifiableServiceProperties(service_path.value(), false);
279 if (service_properties) {
280 std::string profile_path;
281 if (service_properties->GetStringWithoutPathExpansion(
282 shill::kProfileProperty, &profile_path)) {
283 result_properties->SetStringWithoutPathExpansion(
284 profile_path, service_path.value());
286 } else {
287 LOG(WARNING) << "Service not in profile: " << service_path.value();
290 DBusMethodCallStatus call_status = DBUS_METHOD_CALL_SUCCESS;
291 base::MessageLoop::current()->PostTask(
292 FROM_HERE,
293 base::Bind(&PassStubServiceProperties,
294 callback,
295 call_status,
296 base::Owned(result_properties.release())));
299 ShillServiceClient::TestInterface* FakeShillServiceClient::GetTestInterface() {
300 return this;
303 // ShillServiceClient::TestInterface overrides.
305 void FakeShillServiceClient::AddService(const std::string& service_path,
306 const std::string& name,
307 const std::string& type,
308 const std::string& state,
309 bool add_to_visible_list,
310 bool add_to_watch_list) {
311 AddServiceWithIPConfig(service_path, name, type, state, "",
312 add_to_visible_list, add_to_watch_list);
315 void FakeShillServiceClient::AddServiceWithIPConfig(
316 const std::string& service_path,
317 const std::string& name,
318 const std::string& type,
319 const std::string& state,
320 const std::string& ipconfig_path,
321 bool add_to_visible_list,
322 bool add_to_watch_list) {
323 DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()->
324 AddManagerService(service_path, add_to_visible_list, add_to_watch_list);
325 std::string device_path =
326 DBusThreadManager::Get()->GetShillDeviceClient()->GetTestInterface()->
327 GetDevicePathForType(type);
329 base::DictionaryValue* properties =
330 GetModifiableServiceProperties(service_path, true);
331 connect_behavior_.erase(service_path);
332 shill_property_util::SetSSID(name, properties);
333 properties->SetWithoutPathExpansion(
334 shill::kNameProperty,
335 base::Value::CreateStringValue(name));
336 properties->SetWithoutPathExpansion(
337 shill::kDeviceProperty,
338 base::Value::CreateStringValue(device_path));
339 properties->SetWithoutPathExpansion(
340 shill::kTypeProperty,
341 base::Value::CreateStringValue(type));
342 properties->SetWithoutPathExpansion(
343 shill::kStateProperty,
344 base::Value::CreateStringValue(state));
345 if (!ipconfig_path.empty()) {
346 properties->SetWithoutPathExpansion(
347 shill::kIPConfigProperty,
348 base::Value::CreateStringValue(ipconfig_path));
351 DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()->
352 SortManagerServices();
355 void FakeShillServiceClient::RemoveService(const std::string& service_path) {
356 DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()->
357 RemoveManagerService(service_path);
359 stub_services_.RemoveWithoutPathExpansion(service_path, NULL);
360 connect_behavior_.erase(service_path);
363 bool FakeShillServiceClient::SetServiceProperty(const std::string& service_path,
364 const std::string& property,
365 const base::Value& value) {
366 base::DictionaryValue* dict = NULL;
367 if (!stub_services_.GetDictionaryWithoutPathExpansion(service_path, &dict))
368 return false;
370 VLOG(1) << "Service.SetProperty: " << property << " = " << value
371 << " For: " << service_path;
373 base::DictionaryValue new_properties;
374 std::string changed_property;
375 bool case_sensitive = true;
376 if (StartsWithASCII(property, "Provider.", case_sensitive) ||
377 StartsWithASCII(property, "OpenVPN.", case_sensitive) ||
378 StartsWithASCII(property, "L2TPIPsec.", case_sensitive)) {
379 // These properties are only nested within the Provider dictionary if read
380 // from Shill.
381 base::DictionaryValue* provider = new base::DictionaryValue;
382 provider->SetWithoutPathExpansion(property, value.DeepCopy());
383 new_properties.SetWithoutPathExpansion(shill::kProviderProperty, provider);
384 changed_property = shill::kProviderProperty;
385 } else {
386 new_properties.SetWithoutPathExpansion(property, value.DeepCopy());
387 changed_property = property;
390 dict->MergeDictionary(&new_properties);
392 // Notify the Manager if the state changed (affects DefaultService).
393 if (property == shill::kStateProperty) {
394 std::string state;
395 value.GetAsString(&state);
396 DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()->
397 ServiceStateChanged(service_path, state);
400 // If the State changes, the sort order of Services may change and the
401 // DefaultService property may change.
402 if (property == shill::kStateProperty) {
403 base::MessageLoop::current()->PostTask(
404 FROM_HERE, base::Bind(&CallSortManagerServices));
407 // Notifiy Chrome of the property change.
408 base::MessageLoop::current()->PostTask(
409 FROM_HERE,
410 base::Bind(&FakeShillServiceClient::NotifyObserversPropertyChanged,
411 weak_ptr_factory_.GetWeakPtr(),
412 dbus::ObjectPath(service_path), changed_property));
413 return true;
416 const base::DictionaryValue* FakeShillServiceClient::GetServiceProperties(
417 const std::string& service_path) const {
418 const base::DictionaryValue* properties = NULL;
419 stub_services_.GetDictionaryWithoutPathExpansion(service_path, &properties);
420 return properties;
423 void FakeShillServiceClient::ClearServices() {
424 DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()->
425 ClearManagerServices();
427 stub_services_.Clear();
428 connect_behavior_.clear();
431 void FakeShillServiceClient::SetConnectBehavior(const std::string& service_path,
432 const base::Closure& behavior) {
433 connect_behavior_[service_path] = behavior;
436 void FakeShillServiceClient::NotifyObserversPropertyChanged(
437 const dbus::ObjectPath& service_path,
438 const std::string& property) {
439 base::DictionaryValue* dict = NULL;
440 std::string path = service_path.value();
441 if (!stub_services_.GetDictionaryWithoutPathExpansion(path, &dict)) {
442 LOG(ERROR) << "Notify for unknown service: " << path;
443 return;
445 base::Value* value = NULL;
446 if (!dict->GetWithoutPathExpansion(property, &value)) {
447 LOG(ERROR) << "Notify for unknown property: "
448 << path << " : " << property;
449 return;
451 FOR_EACH_OBSERVER(ShillPropertyChangedObserver,
452 GetObserverList(service_path),
453 OnPropertyChanged(property, *value));
456 base::DictionaryValue* FakeShillServiceClient::GetModifiableServiceProperties(
457 const std::string& service_path, bool create_if_missing) {
458 base::DictionaryValue* properties = NULL;
459 if (!stub_services_.GetDictionaryWithoutPathExpansion(service_path,
460 &properties) &&
461 create_if_missing) {
462 properties = new base::DictionaryValue;
463 stub_services_.Set(service_path, properties);
465 return properties;
468 FakeShillServiceClient::PropertyObserverList&
469 FakeShillServiceClient::GetObserverList(const dbus::ObjectPath& device_path) {
470 std::map<dbus::ObjectPath, PropertyObserverList*>::iterator iter =
471 observer_list_.find(device_path);
472 if (iter != observer_list_.end())
473 return *(iter->second);
474 PropertyObserverList* observer_list = new PropertyObserverList();
475 observer_list_[device_path] = observer_list;
476 return *observer_list;
479 void FakeShillServiceClient::SetOtherServicesOffline(
480 const std::string& service_path) {
481 const base::DictionaryValue* service_properties = GetServiceProperties(
482 service_path);
483 if (!service_properties) {
484 LOG(ERROR) << "Missing service: " << service_path;
485 return;
487 std::string service_type;
488 service_properties->GetString(shill::kTypeProperty, &service_type);
489 // Set all other services of the same type to offline (Idle).
490 for (base::DictionaryValue::Iterator iter(stub_services_);
491 !iter.IsAtEnd(); iter.Advance()) {
492 std::string path = iter.key();
493 if (path == service_path)
494 continue;
495 base::DictionaryValue* properties;
496 if (!stub_services_.GetDictionaryWithoutPathExpansion(path, &properties))
497 NOTREACHED();
499 std::string type;
500 properties->GetString(shill::kTypeProperty, &type);
501 if (type != service_type)
502 continue;
503 properties->SetWithoutPathExpansion(
504 shill::kStateProperty,
505 base::Value::CreateStringValue(shill::kStateIdle));
509 void FakeShillServiceClient::SetCellularActivated(
510 const dbus::ObjectPath& service_path,
511 const ErrorCallback& error_callback) {
512 SetProperty(service_path,
513 shill::kActivationStateProperty,
514 base::StringValue(shill::kActivationStateActivated),
515 base::Bind(&base::DoNothing),
516 error_callback);
517 SetProperty(service_path,
518 shill::kConnectableProperty,
519 base::FundamentalValue(true),
520 base::Bind(&base::DoNothing),
521 error_callback);
524 void FakeShillServiceClient::ContinueConnect(
525 const std::string& service_path) {
526 VLOG(1) << "FakeShillServiceClient::ContinueConnect: " << service_path;
527 base::DictionaryValue* service_properties = NULL;
528 if (!stub_services_.GetDictionary(service_path, &service_properties)) {
529 LOG(ERROR) << "Service not found: " << service_path;
530 return;
533 if (ContainsKey(connect_behavior_, service_path)) {
534 const base::Closure& custom_connect_behavior =
535 connect_behavior_[service_path];
536 custom_connect_behavior.Run();
537 return;
540 // No custom connect behavior set, continue with the default connect behavior.
541 std::string passphrase;
542 service_properties->GetStringWithoutPathExpansion(
543 shill::kPassphraseProperty, &passphrase);
544 if (passphrase == "failure") {
545 // Simulate a password failure.
546 SetServiceProperty(service_path,
547 shill::kStateProperty,
548 base::StringValue(shill::kStateFailure));
549 base::MessageLoop::current()->PostTask(
550 FROM_HERE,
551 base::Bind(
552 base::IgnoreResult(&FakeShillServiceClient::SetServiceProperty),
553 weak_ptr_factory_.GetWeakPtr(),
554 service_path,
555 shill::kErrorProperty,
556 base::StringValue(shill::kErrorBadPassphrase)));
557 } else {
558 // Set Online.
559 SetServiceProperty(service_path,
560 shill::kStateProperty,
561 base::StringValue(shill::kStateOnline));
565 } // namespace chromeos