cd02c5e13c16ac96a2753900cbfeaf948e507145
[platform/framework/web/crosswalk.git] / src / dbus / object_manager_unittest.cc
1 // Copyright (c) 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 "dbus/object_manager.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/basictypes.h"
11 #include "base/bind.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/run_loop.h"
14 #include "base/threading/thread.h"
15 #include "base/threading/thread_restrictions.h"
16 #include "dbus/bus.h"
17 #include "dbus/object_path.h"
18 #include "dbus/object_proxy.h"
19 #include "dbus/property.h"
20 #include "dbus/test_service.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22
23 namespace dbus {
24
25 // The object manager test exercises the asynchronous APIs in ObjectManager,
26 // and by extension PropertySet and Property<>.
27 class ObjectManagerTest
28     : public testing::Test,
29       public ObjectManager::Interface {
30  public:
31   ObjectManagerTest() : timeout_expired_(false) {
32   }
33
34   struct Properties : public PropertySet {
35     Property<std::string> name;
36     Property<int16> version;
37     Property<std::vector<std::string> > methods;
38     Property<std::vector<ObjectPath> > objects;
39
40     Properties(ObjectProxy* object_proxy,
41                const std::string& interface_name,
42                PropertyChangedCallback property_changed_callback)
43         : PropertySet(object_proxy, interface_name, property_changed_callback) {
44       RegisterProperty("Name", &name);
45       RegisterProperty("Version", &version);
46       RegisterProperty("Methods", &methods);
47       RegisterProperty("Objects", &objects);
48     }
49   };
50
51   virtual PropertySet* CreateProperties(
52       ObjectProxy* object_proxy,
53       const ObjectPath& object_path,
54       const std::string& interface_name) override {
55     Properties* properties = new Properties(
56         object_proxy, interface_name,
57         base::Bind(&ObjectManagerTest::OnPropertyChanged,
58                    base::Unretained(this), object_path));
59     return static_cast<PropertySet*>(properties);
60   }
61
62   virtual void SetUp() {
63     // Make the main thread not to allow IO.
64     base::ThreadRestrictions::SetIOAllowed(false);
65
66     // Start the D-Bus thread.
67     dbus_thread_.reset(new base::Thread("D-Bus Thread"));
68     base::Thread::Options thread_options;
69     thread_options.message_loop_type = base::MessageLoop::TYPE_IO;
70     ASSERT_TRUE(dbus_thread_->StartWithOptions(thread_options));
71
72     // Start the test service, using the D-Bus thread.
73     TestService::Options options;
74     options.dbus_task_runner = dbus_thread_->message_loop_proxy();
75     test_service_.reset(new TestService(options));
76     ASSERT_TRUE(test_service_->StartService());
77     ASSERT_TRUE(test_service_->WaitUntilServiceIsStarted());
78     ASSERT_TRUE(test_service_->HasDBusThread());
79
80     // Create the client, using the D-Bus thread.
81     Bus::Options bus_options;
82     bus_options.bus_type = Bus::SESSION;
83     bus_options.connection_type = Bus::PRIVATE;
84     bus_options.dbus_task_runner = dbus_thread_->message_loop_proxy();
85     bus_ = new Bus(bus_options);
86     ASSERT_TRUE(bus_->HasDBusThread());
87
88     object_manager_ = bus_->GetObjectManager(
89         "org.chromium.TestService",
90         ObjectPath("/org/chromium/TestService"));
91     object_manager_->RegisterInterface("org.chromium.TestInterface", this);
92
93     WaitForObject();
94   }
95
96   virtual void TearDown() {
97     bus_->ShutdownOnDBusThreadAndBlock();
98
99     // Shut down the service.
100     test_service_->ShutdownAndBlock();
101
102     // Reset to the default.
103     base::ThreadRestrictions::SetIOAllowed(true);
104
105     // Stopping a thread is considered an IO operation, so do this after
106     // allowing IO.
107     test_service_->Stop();
108
109     base::RunLoop().RunUntilIdle();
110   }
111
112   void MethodCallback(Response* response) {
113     method_callback_called_ = true;
114     run_loop_->Quit();
115   }
116
117   // Called from the PropertiesChangedAsObjectsReceived test case. The test will
118   // not run the message loop if it receives the expected PropertiesChanged
119   // signal before the timeout. This method immediately fails the test.
120   void PropertiesChangedTestTimeout() {
121     timeout_expired_ = true;
122     run_loop_->Quit();
123
124     FAIL() << "Never received PropertiesChanged";
125   }
126
127  protected:
128   // Called when an object is added.
129   virtual void ObjectAdded(const ObjectPath& object_path,
130                            const std::string& interface_name) override {
131     added_objects_.push_back(std::make_pair(object_path, interface_name));
132     run_loop_->Quit();
133   }
134
135   // Called when an object is removed.
136   virtual void ObjectRemoved(const ObjectPath& object_path,
137                              const std::string& interface_name) override {
138     removed_objects_.push_back(std::make_pair(object_path, interface_name));
139     run_loop_->Quit();
140   }
141
142   // Called when a property value is updated.
143   void OnPropertyChanged(const ObjectPath& object_path,
144                          const std::string& name) {
145     // Store the value of the "Name" property if that's the one that
146     // changed.
147     Properties* properties = static_cast<Properties*>(
148         object_manager_->GetProperties(
149             object_path,
150             "org.chromium.TestInterface"));
151     if (name == properties->name.name())
152       last_name_value_ = properties->name.value();
153
154     // Store the updated property.
155     updated_properties_.push_back(name);
156     run_loop_->Quit();
157   }
158
159   static const size_t kExpectedObjects = 1;
160   static const size_t kExpectedProperties = 4;
161
162   void WaitForObject() {
163     while (added_objects_.size() < kExpectedObjects ||
164            updated_properties_.size() < kExpectedProperties) {
165       run_loop_.reset(new base::RunLoop);
166       run_loop_->Run();
167     }
168     for (size_t i = 0; i < kExpectedObjects; ++i)
169       added_objects_.erase(added_objects_.begin());
170     for (size_t i = 0; i < kExpectedProperties; ++i)
171       updated_properties_.erase(updated_properties_.begin());
172   }
173
174   void WaitForRemoveObject() {
175     while (removed_objects_.size() < kExpectedObjects) {
176       run_loop_.reset(new base::RunLoop);
177       run_loop_->Run();
178     }
179     for (size_t i = 0; i < kExpectedObjects; ++i)
180       removed_objects_.erase(removed_objects_.begin());
181   }
182
183   void WaitForMethodCallback() {
184     run_loop_.reset(new base::RunLoop);
185     run_loop_->Run();
186     method_callback_called_ = false;
187   }
188
189   void PerformAction(const std::string& action, const ObjectPath& object_path) {
190     ObjectProxy* object_proxy = bus_->GetObjectProxy(
191         "org.chromium.TestService",
192         ObjectPath("/org/chromium/TestObject"));
193
194     MethodCall method_call("org.chromium.TestInterface", "PerformAction");
195     MessageWriter writer(&method_call);
196     writer.AppendString(action);
197     writer.AppendObjectPath(object_path);
198
199     object_proxy->CallMethod(&method_call,
200                              ObjectProxy::TIMEOUT_USE_DEFAULT,
201                              base::Bind(&ObjectManagerTest::MethodCallback,
202                                         base::Unretained(this)));
203     WaitForMethodCallback();
204   }
205
206   base::MessageLoop message_loop_;
207   scoped_ptr<base::RunLoop> run_loop_;
208   scoped_ptr<base::Thread> dbus_thread_;
209   scoped_refptr<Bus> bus_;
210   ObjectManager* object_manager_;
211   scoped_ptr<TestService> test_service_;
212
213   std::string last_name_value_;
214   bool timeout_expired_;
215
216   std::vector<std::pair<ObjectPath, std::string> > added_objects_;
217   std::vector<std::pair<ObjectPath, std::string> > removed_objects_;
218   std::vector<std::string> updated_properties_;
219
220   bool method_callback_called_;
221 };
222
223
224 TEST_F(ObjectManagerTest, InitialObject) {
225   ObjectProxy* object_proxy = object_manager_->GetObjectProxy(
226       ObjectPath("/org/chromium/TestObject"));
227   EXPECT_TRUE(object_proxy != NULL);
228
229   Properties* properties = static_cast<Properties*>(
230       object_manager_->GetProperties(ObjectPath("/org/chromium/TestObject"),
231                                      "org.chromium.TestInterface"));
232   EXPECT_TRUE(properties != NULL);
233
234   EXPECT_EQ("TestService", properties->name.value());
235   EXPECT_EQ(10, properties->version.value());
236
237   std::vector<std::string> methods = properties->methods.value();
238   ASSERT_EQ(4U, methods.size());
239   EXPECT_EQ("Echo", methods[0]);
240   EXPECT_EQ("SlowEcho", methods[1]);
241   EXPECT_EQ("AsyncEcho", methods[2]);
242   EXPECT_EQ("BrokenMethod", methods[3]);
243
244   std::vector<ObjectPath> objects = properties->objects.value();
245   ASSERT_EQ(1U, objects.size());
246   EXPECT_EQ(ObjectPath("/TestObjectPath"), objects[0]);
247 }
248
249 TEST_F(ObjectManagerTest, UnknownObjectProxy) {
250   ObjectProxy* object_proxy = object_manager_->GetObjectProxy(
251       ObjectPath("/org/chromium/UnknownObject"));
252   EXPECT_TRUE(object_proxy == NULL);
253 }
254
255 TEST_F(ObjectManagerTest, UnknownObjectProperties) {
256   Properties* properties = static_cast<Properties*>(
257       object_manager_->GetProperties(ObjectPath("/org/chromium/UnknownObject"),
258                                      "org.chromium.TestInterface"));
259   EXPECT_TRUE(properties == NULL);
260 }
261
262 TEST_F(ObjectManagerTest, UnknownInterfaceProperties) {
263   Properties* properties = static_cast<Properties*>(
264       object_manager_->GetProperties(ObjectPath("/org/chromium/TestObject"),
265                                      "org.chromium.UnknownService"));
266   EXPECT_TRUE(properties == NULL);
267 }
268
269 TEST_F(ObjectManagerTest, GetObjects) {
270   std::vector<ObjectPath> object_paths = object_manager_->GetObjects();
271   ASSERT_EQ(1U, object_paths.size());
272   EXPECT_EQ(ObjectPath("/org/chromium/TestObject"), object_paths[0]);
273 }
274
275 TEST_F(ObjectManagerTest, GetObjectsWithInterface) {
276   std::vector<ObjectPath> object_paths =
277       object_manager_->GetObjectsWithInterface("org.chromium.TestInterface");
278   ASSERT_EQ(1U, object_paths.size());
279   EXPECT_EQ(ObjectPath("/org/chromium/TestObject"), object_paths[0]);
280 }
281
282 TEST_F(ObjectManagerTest, GetObjectsWithUnknownInterface) {
283   std::vector<ObjectPath> object_paths =
284       object_manager_->GetObjectsWithInterface("org.chromium.UnknownService");
285   EXPECT_EQ(0U, object_paths.size());
286 }
287
288 TEST_F(ObjectManagerTest, SameObject) {
289   ObjectManager* object_manager = bus_->GetObjectManager(
290       "org.chromium.TestService",
291       ObjectPath("/org/chromium/TestService"));
292   EXPECT_EQ(object_manager_, object_manager);
293 }
294
295 TEST_F(ObjectManagerTest, DifferentObjectForService) {
296   ObjectManager* object_manager = bus_->GetObjectManager(
297       "org.chromium.DifferentService",
298       ObjectPath("/org/chromium/TestService"));
299   EXPECT_NE(object_manager_, object_manager);
300 }
301
302 TEST_F(ObjectManagerTest, DifferentObjectForPath) {
303   ObjectManager* object_manager = bus_->GetObjectManager(
304       "org.chromium.TestService",
305       ObjectPath("/org/chromium/DifferentService"));
306   EXPECT_NE(object_manager_, object_manager);
307 }
308
309 TEST_F(ObjectManagerTest, SecondObject) {
310   PerformAction("AddObject", ObjectPath("/org/chromium/SecondObject"));
311   WaitForObject();
312
313   ObjectProxy* object_proxy = object_manager_->GetObjectProxy(
314       ObjectPath("/org/chromium/SecondObject"));
315   EXPECT_TRUE(object_proxy != NULL);
316
317   Properties* properties = static_cast<Properties*>(
318       object_manager_->GetProperties(ObjectPath("/org/chromium/SecondObject"),
319                                      "org.chromium.TestInterface"));
320   EXPECT_TRUE(properties != NULL);
321
322   std::vector<ObjectPath> object_paths = object_manager_->GetObjects();
323   ASSERT_EQ(2U, object_paths.size());
324
325   std::sort(object_paths.begin(), object_paths.end());
326   EXPECT_EQ(ObjectPath("/org/chromium/SecondObject"), object_paths[0]);
327   EXPECT_EQ(ObjectPath("/org/chromium/TestObject"), object_paths[1]);
328
329   object_paths =
330       object_manager_->GetObjectsWithInterface("org.chromium.TestInterface");
331   ASSERT_EQ(2U, object_paths.size());
332
333   std::sort(object_paths.begin(), object_paths.end());
334   EXPECT_EQ(ObjectPath("/org/chromium/SecondObject"), object_paths[0]);
335   EXPECT_EQ(ObjectPath("/org/chromium/TestObject"), object_paths[1]);
336 }
337
338 TEST_F(ObjectManagerTest, RemoveSecondObject) {
339   PerformAction("AddObject", ObjectPath("/org/chromium/SecondObject"));
340   WaitForObject();
341
342   std::vector<ObjectPath> object_paths = object_manager_->GetObjects();
343   ASSERT_EQ(2U, object_paths.size());
344
345   PerformAction("RemoveObject", ObjectPath("/org/chromium/SecondObject"));
346   WaitForRemoveObject();
347
348   ObjectProxy* object_proxy = object_manager_->GetObjectProxy(
349       ObjectPath("/org/chromium/SecondObject"));
350   EXPECT_TRUE(object_proxy == NULL);
351
352   Properties* properties = static_cast<Properties*>(
353       object_manager_->GetProperties(ObjectPath("/org/chromium/SecondObject"),
354                                      "org.chromium.TestInterface"));
355   EXPECT_TRUE(properties == NULL);
356
357   object_paths = object_manager_->GetObjects();
358   ASSERT_EQ(1U, object_paths.size());
359   EXPECT_EQ(ObjectPath("/org/chromium/TestObject"), object_paths[0]);
360
361   object_paths =
362       object_manager_->GetObjectsWithInterface("org.chromium.TestInterface");
363   ASSERT_EQ(1U, object_paths.size());
364   EXPECT_EQ(ObjectPath("/org/chromium/TestObject"), object_paths[0]);
365 }
366
367 TEST_F(ObjectManagerTest, OwnershipLost) {
368   PerformAction("ReleaseOwnership", ObjectPath("/org/chromium/TestService"));
369   WaitForRemoveObject();
370
371   std::vector<ObjectPath> object_paths = object_manager_->GetObjects();
372   ASSERT_EQ(0U, object_paths.size());
373 }
374
375 TEST_F(ObjectManagerTest, OwnershipLostAndRegained) {
376   PerformAction("Ownership", ObjectPath("/org/chromium/TestService"));
377   WaitForRemoveObject();
378   WaitForObject();
379
380   std::vector<ObjectPath> object_paths = object_manager_->GetObjects();
381   ASSERT_EQ(1U, object_paths.size());
382 }
383
384 TEST_F(ObjectManagerTest, PropertiesChangedAsObjectsReceived) {
385   // Remove the existing object manager.
386   object_manager_->UnregisterInterface("org.chromium.TestInterface");
387   run_loop_.reset(new base::RunLoop);
388   EXPECT_TRUE(bus_->RemoveObjectManager(
389       "org.chromium.TestService",
390       ObjectPath("/org/chromium/TestService"),
391       run_loop_->QuitClosure()));
392   run_loop_->Run();
393
394   PerformAction("SetSendImmediatePropertiesChanged",
395                 ObjectPath("/org/chromium/TestService"));
396
397   object_manager_ = bus_->GetObjectManager(
398       "org.chromium.TestService",
399       ObjectPath("/org/chromium/TestService"));
400   object_manager_->RegisterInterface("org.chromium.TestInterface", this);
401
402   // The newly created object manager should call GetManagedObjects immediately
403   // after setting up the match rule for PropertiesChanged. We should process
404   // the PropertiesChanged event right after that. If we don't receive it within
405   // 2 seconds, then fail the test.
406   message_loop_.PostDelayedTask(
407       FROM_HERE,
408       base::Bind(&ObjectManagerTest::PropertiesChangedTestTimeout,
409                  base::Unretained(this)),
410       base::TimeDelta::FromSeconds(2));
411
412   while (last_name_value_ != "ChangedTestServiceName" && !timeout_expired_) {
413     run_loop_.reset(new base::RunLoop);
414     run_loop_->Run();
415   }
416 }
417
418 }  // namespace dbus