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.
5 #include "dbus/object_manager.h"
10 #include "base/basictypes.h"
11 #include "base/bind.h"
12 #include "base/message_loop.h"
13 #include "base/threading/thread.h"
14 #include "base/threading/thread_restrictions.h"
16 #include "dbus/object_path.h"
17 #include "dbus/object_proxy.h"
18 #include "dbus/property.h"
19 #include "dbus/test_service.h"
20 #include "testing/gtest/include/gtest/gtest.h"
22 // The object manager test exercises the asynchronous APIs in ObjectManager,
23 // and by extension PropertySet and Property<>.
24 class ObjectManagerTest
25 : public testing::Test
,
26 public dbus::ObjectManager::Interface
{
31 struct Properties
: public dbus::PropertySet
{
32 dbus::Property
<std::string
> name
;
33 dbus::Property
<int16
> version
;
34 dbus::Property
<std::vector
<std::string
> > methods
;
35 dbus::Property
<std::vector
<dbus::ObjectPath
> > objects
;
37 Properties(dbus::ObjectProxy
* object_proxy
,
38 const std::string
& interface_name
,
39 PropertyChangedCallback property_changed_callback
)
40 : dbus::PropertySet(object_proxy
, interface_name
,
41 property_changed_callback
) {
42 RegisterProperty("Name", &name
);
43 RegisterProperty("Version", &version
);
44 RegisterProperty("Methods", &methods
);
45 RegisterProperty("Objects", &objects
);
49 virtual dbus::PropertySet
* CreateProperties(
50 dbus::ObjectProxy
* object_proxy
,
51 const dbus::ObjectPath
& object_path
,
52 const std::string
& interface_name
) OVERRIDE
{
53 Properties
* properties
= new Properties(
54 object_proxy
, interface_name
,
55 base::Bind(&ObjectManagerTest::OnPropertyChanged
,
56 base::Unretained(this), object_path
));
57 return static_cast<dbus::PropertySet
*>(properties
);
60 virtual void SetUp() {
61 // Make the main thread not to allow IO.
62 base::ThreadRestrictions::SetIOAllowed(false);
64 // Start the D-Bus thread.
65 dbus_thread_
.reset(new base::Thread("D-Bus Thread"));
66 base::Thread::Options thread_options
;
67 thread_options
.message_loop_type
= base::MessageLoop::TYPE_IO
;
68 ASSERT_TRUE(dbus_thread_
->StartWithOptions(thread_options
));
70 // Start the test service, using the D-Bus thread.
71 dbus::TestService::Options options
;
72 options
.dbus_task_runner
= dbus_thread_
->message_loop_proxy();
73 test_service_
.reset(new dbus::TestService(options
));
74 ASSERT_TRUE(test_service_
->StartService());
75 ASSERT_TRUE(test_service_
->WaitUntilServiceIsStarted());
76 ASSERT_TRUE(test_service_
->HasDBusThread());
78 // Create the client, using the D-Bus thread.
79 dbus::Bus::Options bus_options
;
80 bus_options
.bus_type
= dbus::Bus::SESSION
;
81 bus_options
.connection_type
= dbus::Bus::PRIVATE
;
82 bus_options
.dbus_task_runner
= dbus_thread_
->message_loop_proxy();
83 bus_
= new dbus::Bus(bus_options
);
84 ASSERT_TRUE(bus_
->HasDBusThread());
86 object_manager_
= bus_
->GetObjectManager(
87 "org.chromium.TestService",
88 dbus::ObjectPath("/org/chromium/TestService"));
89 object_manager_
->RegisterInterface("org.chromium.TestInterface", this);
91 object_manager_
->GetManagedObjects();
95 virtual void TearDown() {
96 bus_
->ShutdownOnDBusThreadAndBlock();
98 // Shut down the service.
99 test_service_
->ShutdownAndBlock();
101 // Reset to the default.
102 base::ThreadRestrictions::SetIOAllowed(true);
104 // Stopping a thread is considered an IO operation, so do this after
106 test_service_
->Stop();
109 void MethodCallback(dbus::Response
* response
) {
110 method_callback_called_
= true;
111 message_loop_
.Quit();
115 // Called when an object is added.
116 virtual void ObjectAdded(const dbus::ObjectPath
& object_path
,
117 const std::string
& interface_name
) OVERRIDE
{
118 added_objects_
.push_back(std::make_pair(object_path
, interface_name
));
119 message_loop_
.Quit();
122 // Called when an object is removed.
123 virtual void ObjectRemoved(const dbus::ObjectPath
& object_path
,
124 const std::string
& interface_name
) OVERRIDE
{
125 removed_objects_
.push_back(std::make_pair(object_path
, interface_name
));
126 message_loop_
.Quit();
129 // Called when a property value is updated.
130 void OnPropertyChanged(const dbus::ObjectPath
& object_path
,
131 const std::string
& name
) {
132 updated_properties_
.push_back(name
);
133 message_loop_
.Quit();
136 static const size_t kExpectedObjects
= 1;
137 static const size_t kExpectedProperties
= 4;
139 void WaitForObject() {
140 while (added_objects_
.size() < kExpectedObjects
||
141 updated_properties_
.size() < kExpectedProperties
)
143 for (size_t i
= 0; i
< kExpectedObjects
; ++i
)
144 added_objects_
.erase(added_objects_
.begin());
145 for (size_t i
= 0; i
< kExpectedProperties
; ++i
)
146 updated_properties_
.erase(updated_properties_
.begin());
149 void WaitForRemoveObject() {
150 while (removed_objects_
.size() < kExpectedObjects
)
152 for (size_t i
= 0; i
< kExpectedObjects
; ++i
)
153 removed_objects_
.erase(removed_objects_
.begin());
156 void WaitForMethodCallback() {
158 method_callback_called_
= false;
161 void PerformAction(const std::string
& action
,
162 const dbus::ObjectPath
& object_path
) {
163 dbus::ObjectProxy
* object_proxy
= bus_
->GetObjectProxy(
164 "org.chromium.TestService",
165 dbus::ObjectPath("/org/chromium/TestObject"));
167 dbus::MethodCall
method_call("org.chromium.TestInterface", "PerformAction");
168 dbus::MessageWriter
writer(&method_call
);
169 writer
.AppendString(action
);
170 writer
.AppendObjectPath(object_path
);
172 object_proxy
->CallMethod(&method_call
,
173 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
174 base::Bind(&ObjectManagerTest::MethodCallback
,
175 base::Unretained(this)));
176 WaitForMethodCallback();
179 base::MessageLoop message_loop_
;
180 scoped_ptr
<base::Thread
> dbus_thread_
;
181 scoped_refptr
<dbus::Bus
> bus_
;
182 dbus::ObjectManager
* object_manager_
;
183 scoped_ptr
<dbus::TestService
> test_service_
;
185 std::vector
<std::pair
<dbus::ObjectPath
, std::string
> > added_objects_
;
186 std::vector
<std::pair
<dbus::ObjectPath
, std::string
> > removed_objects_
;
187 std::vector
<std::string
> updated_properties_
;
189 bool method_callback_called_
;
193 TEST_F(ObjectManagerTest
, InitialObject
) {
194 dbus::ObjectProxy
* object_proxy
= object_manager_
->GetObjectProxy(
195 dbus::ObjectPath("/org/chromium/TestObject"));
196 EXPECT_TRUE(object_proxy
!= NULL
);
198 Properties
* properties
= static_cast<Properties
*>(
199 object_manager_
->GetProperties(
200 dbus::ObjectPath("/org/chromium/TestObject"),
201 "org.chromium.TestInterface"));
202 EXPECT_TRUE(properties
!= NULL
);
204 EXPECT_EQ("TestService", properties
->name
.value());
205 EXPECT_EQ(10, properties
->version
.value());
207 std::vector
<std::string
> methods
= properties
->methods
.value();
208 ASSERT_EQ(4U, methods
.size());
209 EXPECT_EQ("Echo", methods
[0]);
210 EXPECT_EQ("SlowEcho", methods
[1]);
211 EXPECT_EQ("AsyncEcho", methods
[2]);
212 EXPECT_EQ("BrokenMethod", methods
[3]);
214 std::vector
<dbus::ObjectPath
> objects
= properties
->objects
.value();
215 ASSERT_EQ(1U, objects
.size());
216 EXPECT_EQ(dbus::ObjectPath("/TestObjectPath"), objects
[0]);
219 TEST_F(ObjectManagerTest
, UnknownObjectProxy
) {
220 dbus::ObjectProxy
* object_proxy
= object_manager_
->GetObjectProxy(
221 dbus::ObjectPath("/org/chromium/UnknownObject"));
222 EXPECT_TRUE(object_proxy
== NULL
);
225 TEST_F(ObjectManagerTest
, UnknownObjectProperties
) {
226 Properties
* properties
= static_cast<Properties
*>(
227 object_manager_
->GetProperties(
228 dbus::ObjectPath("/org/chromium/UnknownObject"),
229 "org.chromium.TestInterface"));
230 EXPECT_TRUE(properties
== NULL
);
233 TEST_F(ObjectManagerTest
, UnknownInterfaceProperties
) {
234 Properties
* properties
= static_cast<Properties
*>(
235 object_manager_
->GetProperties(
236 dbus::ObjectPath("/org/chromium/TestObject"),
237 "org.chromium.UnknownService"));
238 EXPECT_TRUE(properties
== NULL
);
241 TEST_F(ObjectManagerTest
, GetObjects
) {
242 std::vector
<dbus::ObjectPath
> object_paths
= object_manager_
->GetObjects();
243 ASSERT_EQ(1U, object_paths
.size());
244 EXPECT_EQ(dbus::ObjectPath("/org/chromium/TestObject"), object_paths
[0]);
247 TEST_F(ObjectManagerTest
, GetObjectsWithInterface
) {
248 std::vector
<dbus::ObjectPath
> object_paths
=
249 object_manager_
->GetObjectsWithInterface("org.chromium.TestInterface");
250 ASSERT_EQ(1U, object_paths
.size());
251 EXPECT_EQ(dbus::ObjectPath("/org/chromium/TestObject"), object_paths
[0]);
254 TEST_F(ObjectManagerTest
, GetObjectsWithUnknownInterface
) {
255 std::vector
<dbus::ObjectPath
> object_paths
=
256 object_manager_
->GetObjectsWithInterface("org.chromium.UnknownService");
257 EXPECT_EQ(0U, object_paths
.size());
260 TEST_F(ObjectManagerTest
, SameObject
) {
261 dbus::ObjectManager
* object_manager
= bus_
->GetObjectManager(
262 "org.chromium.TestService",
263 dbus::ObjectPath("/org/chromium/TestService"));
264 EXPECT_EQ(object_manager_
, object_manager
);
267 TEST_F(ObjectManagerTest
, DifferentObjectForService
) {
268 dbus::ObjectManager
* object_manager
= bus_
->GetObjectManager(
269 "org.chromium.DifferentService",
270 dbus::ObjectPath("/org/chromium/TestService"));
271 EXPECT_NE(object_manager_
, object_manager
);
274 TEST_F(ObjectManagerTest
, DifferentObjectForPath
) {
275 dbus::ObjectManager
* object_manager
= bus_
->GetObjectManager(
276 "org.chromium.TestService",
277 dbus::ObjectPath("/org/chromium/DifferentService"));
278 EXPECT_NE(object_manager_
, object_manager
);
281 TEST_F(ObjectManagerTest
, SecondObject
) {
282 PerformAction("AddObject", dbus::ObjectPath("/org/chromium/SecondObject"));
285 dbus::ObjectProxy
* object_proxy
= object_manager_
->GetObjectProxy(
286 dbus::ObjectPath("/org/chromium/SecondObject"));
287 EXPECT_TRUE(object_proxy
!= NULL
);
289 Properties
* properties
= static_cast<Properties
*>(
290 object_manager_
->GetProperties(
291 dbus::ObjectPath("/org/chromium/SecondObject"),
292 "org.chromium.TestInterface"));
293 EXPECT_TRUE(properties
!= NULL
);
295 std::vector
<dbus::ObjectPath
> object_paths
= object_manager_
->GetObjects();
296 ASSERT_EQ(2U, object_paths
.size());
298 std::sort(object_paths
.begin(), object_paths
.end());
299 EXPECT_EQ(dbus::ObjectPath("/org/chromium/SecondObject"), object_paths
[0]);
300 EXPECT_EQ(dbus::ObjectPath("/org/chromium/TestObject"), object_paths
[1]);
303 object_manager_
->GetObjectsWithInterface("org.chromium.TestInterface");
304 ASSERT_EQ(2U, object_paths
.size());
306 std::sort(object_paths
.begin(), object_paths
.end());
307 EXPECT_EQ(dbus::ObjectPath("/org/chromium/SecondObject"), object_paths
[0]);
308 EXPECT_EQ(dbus::ObjectPath("/org/chromium/TestObject"), object_paths
[1]);
311 TEST_F(ObjectManagerTest
, RemoveSecondObject
) {
312 PerformAction("AddObject", dbus::ObjectPath("/org/chromium/SecondObject"));
315 std::vector
<dbus::ObjectPath
> object_paths
= object_manager_
->GetObjects();
316 ASSERT_EQ(2U, object_paths
.size());
318 PerformAction("RemoveObject", dbus::ObjectPath("/org/chromium/SecondObject"));
319 WaitForRemoveObject();
321 dbus::ObjectProxy
* object_proxy
= object_manager_
->GetObjectProxy(
322 dbus::ObjectPath("/org/chromium/SecondObject"));
323 EXPECT_TRUE(object_proxy
== NULL
);
325 Properties
* properties
= static_cast<Properties
*>(
326 object_manager_
->GetProperties(
327 dbus::ObjectPath("/org/chromium/SecondObject"),
328 "org.chromium.TestInterface"));
329 EXPECT_TRUE(properties
== NULL
);
331 object_paths
= object_manager_
->GetObjects();
332 ASSERT_EQ(1U, object_paths
.size());
333 EXPECT_EQ(dbus::ObjectPath("/org/chromium/TestObject"), object_paths
[0]);
336 object_manager_
->GetObjectsWithInterface("org.chromium.TestInterface");
337 ASSERT_EQ(1U, object_paths
.size());
338 EXPECT_EQ(dbus::ObjectPath("/org/chromium/TestObject"), object_paths
[0]);