• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
ObjectManagerTest()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 
Propertiesdbus::ObjectManagerTest::Properties40     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 
CreateProperties(ObjectProxy * object_proxy,const ObjectPath & object_path,const std::string & interface_name)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 
SetUp()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 
TearDown()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 
MethodCallback(Response * response)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.
PropertiesChangedTestTimeout()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.
ObjectAdded(const ObjectPath & object_path,const std::string & interface_name)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.
ObjectRemoved(const ObjectPath & object_path,const std::string & interface_name)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.
OnPropertyChanged(const ObjectPath & object_path,const std::string & name)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 
WaitForObject()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 
WaitForRemoveObject()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 
WaitForMethodCallback()183   void WaitForMethodCallback() {
184     run_loop_.reset(new base::RunLoop);
185     run_loop_->Run();
186     method_callback_called_ = false;
187   }
188 
PerformAction(const std::string & action,const ObjectPath & object_path)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 
TEST_F(ObjectManagerTest,InitialObject)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 
TEST_F(ObjectManagerTest,UnknownObjectProxy)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 
TEST_F(ObjectManagerTest,UnknownObjectProperties)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 
TEST_F(ObjectManagerTest,UnknownInterfaceProperties)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 
TEST_F(ObjectManagerTest,GetObjects)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 
TEST_F(ObjectManagerTest,GetObjectsWithInterface)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 
TEST_F(ObjectManagerTest,GetObjectsWithUnknownInterface)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 
TEST_F(ObjectManagerTest,SameObject)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 
TEST_F(ObjectManagerTest,DifferentObjectForService)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 
TEST_F(ObjectManagerTest,DifferentObjectForPath)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 
TEST_F(ObjectManagerTest,SecondObject)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 
TEST_F(ObjectManagerTest,RemoveSecondObject)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 
TEST_F(ObjectManagerTest,OwnershipLost)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 
TEST_F(ObjectManagerTest,OwnershipLostAndRegained)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 
TEST_F(ObjectManagerTest,PropertiesChangedAsObjectsReceived)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
419