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