1 // Copyright (c) 2012 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.
8 #include "base/message_loop.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/threading/thread.h"
11 #include "dbus/exported_object.h"
12 #include "dbus/object_path.h"
13 #include "dbus/object_proxy.h"
14 #include "dbus/scoped_dbus_error.h"
16 #include "testing/gtest/include/gtest/gtest.h"
20 // Used to test AddFilterFunction().
21 DBusHandlerResult
DummyHandler(DBusConnection
* connection
,
22 DBusMessage
* raw_message
,
24 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
29 TEST(BusTest
, GetObjectProxy
) {
30 dbus::Bus::Options options
;
31 scoped_refptr
<dbus::Bus
> bus
= new dbus::Bus(options
);
33 dbus::ObjectProxy
* object_proxy1
=
34 bus
->GetObjectProxy("org.chromium.TestService",
35 dbus::ObjectPath("/org/chromium/TestObject"));
36 ASSERT_TRUE(object_proxy1
);
38 // This should return the same object.
39 dbus::ObjectProxy
* object_proxy2
=
40 bus
->GetObjectProxy("org.chromium.TestService",
41 dbus::ObjectPath("/org/chromium/TestObject"));
42 ASSERT_TRUE(object_proxy2
);
43 EXPECT_EQ(object_proxy1
, object_proxy2
);
46 dbus::ObjectProxy
* object_proxy3
=
48 "org.chromium.TestService",
49 dbus::ObjectPath("/org/chromium/DifferentTestObject"));
50 ASSERT_TRUE(object_proxy3
);
51 EXPECT_NE(object_proxy1
, object_proxy3
);
53 bus
->ShutdownAndBlock();
56 TEST(BusTest
, GetObjectProxyIgnoreUnknownService
) {
57 dbus::Bus::Options options
;
58 scoped_refptr
<dbus::Bus
> bus
= new dbus::Bus(options
);
60 dbus::ObjectProxy
* object_proxy1
=
61 bus
->GetObjectProxyWithOptions(
62 "org.chromium.TestService",
63 dbus::ObjectPath("/org/chromium/TestObject"),
64 dbus::ObjectProxy::IGNORE_SERVICE_UNKNOWN_ERRORS
);
65 ASSERT_TRUE(object_proxy1
);
67 // This should return the same object.
68 dbus::ObjectProxy
* object_proxy2
=
69 bus
->GetObjectProxyWithOptions(
70 "org.chromium.TestService",
71 dbus::ObjectPath("/org/chromium/TestObject"),
72 dbus::ObjectProxy::IGNORE_SERVICE_UNKNOWN_ERRORS
);
73 ASSERT_TRUE(object_proxy2
);
74 EXPECT_EQ(object_proxy1
, object_proxy2
);
77 dbus::ObjectProxy
* object_proxy3
=
78 bus
->GetObjectProxyWithOptions(
79 "org.chromium.TestService",
80 dbus::ObjectPath("/org/chromium/DifferentTestObject"),
81 dbus::ObjectProxy::IGNORE_SERVICE_UNKNOWN_ERRORS
);
82 ASSERT_TRUE(object_proxy3
);
83 EXPECT_NE(object_proxy1
, object_proxy3
);
85 bus
->ShutdownAndBlock();
88 TEST(BusTest
, RemoveObjectProxy
) {
89 // Setup the current thread's MessageLoop.
90 MessageLoop message_loop
;
92 // Start the D-Bus thread.
93 base::Thread::Options thread_options
;
94 thread_options
.message_loop_type
= MessageLoop::TYPE_IO
;
95 base::Thread
dbus_thread("D-Bus thread");
96 dbus_thread
.StartWithOptions(thread_options
);
99 dbus::Bus::Options options
;
100 options
.dbus_task_runner
= dbus_thread
.message_loop_proxy();
101 scoped_refptr
<dbus::Bus
> bus
= new dbus::Bus(options
);
102 ASSERT_FALSE(bus
->shutdown_completed());
104 // Try to remove a non existant object proxy should return false.
106 bus
->RemoveObjectProxy("org.chromium.TestService",
107 dbus::ObjectPath("/org/chromium/TestObject"),
108 base::Bind(&base::DoNothing
)));
110 dbus::ObjectProxy
* object_proxy1
=
111 bus
->GetObjectProxy("org.chromium.TestService",
112 dbus::ObjectPath("/org/chromium/TestObject"));
113 ASSERT_TRUE(object_proxy1
);
115 // Increment the reference count to the object proxy to avoid destroying it
116 // while removing the object.
117 object_proxy1
->AddRef();
119 // Remove the object from the bus. This will invalidate any other usage of
120 // object_proxy1 other than destroy it. We keep this object for a comparison
123 bus
->RemoveObjectProxy("org.chromium.TestService",
124 dbus::ObjectPath("/org/chromium/TestObject"),
125 base::Bind(&base::DoNothing
)));
127 // This should return a different object because the first object was removed
128 // from the bus, but not deleted from memory.
129 dbus::ObjectProxy
* object_proxy2
=
130 bus
->GetObjectProxy("org.chromium.TestService",
131 dbus::ObjectPath("/org/chromium/TestObject"));
132 ASSERT_TRUE(object_proxy2
);
134 // Compare the new object with the first object. The first object still exists
135 // thanks to the increased reference.
136 EXPECT_NE(object_proxy1
, object_proxy2
);
138 // Release object_proxy1.
139 object_proxy1
->Release();
141 // Shut down synchronously.
142 bus
->ShutdownOnDBusThreadAndBlock();
143 EXPECT_TRUE(bus
->shutdown_completed());
147 TEST(BusTest
, GetExportedObject
) {
148 dbus::Bus::Options options
;
149 scoped_refptr
<dbus::Bus
> bus
= new dbus::Bus(options
);
151 dbus::ExportedObject
* object_proxy1
=
152 bus
->GetExportedObject(dbus::ObjectPath("/org/chromium/TestObject"));
153 ASSERT_TRUE(object_proxy1
);
155 // This should return the same object.
156 dbus::ExportedObject
* object_proxy2
=
157 bus
->GetExportedObject(dbus::ObjectPath("/org/chromium/TestObject"));
158 ASSERT_TRUE(object_proxy2
);
159 EXPECT_EQ(object_proxy1
, object_proxy2
);
162 dbus::ExportedObject
* object_proxy3
=
163 bus
->GetExportedObject(
164 dbus::ObjectPath("/org/chromium/DifferentTestObject"));
165 ASSERT_TRUE(object_proxy3
);
166 EXPECT_NE(object_proxy1
, object_proxy3
);
168 bus
->ShutdownAndBlock();
171 TEST(BusTest
, UnregisterExportedObject
) {
172 // Start the D-Bus thread.
173 base::Thread::Options thread_options
;
174 thread_options
.message_loop_type
= MessageLoop::TYPE_IO
;
175 base::Thread
dbus_thread("D-Bus thread");
176 dbus_thread
.StartWithOptions(thread_options
);
179 dbus::Bus::Options options
;
180 options
.dbus_task_runner
= dbus_thread
.message_loop_proxy();
181 scoped_refptr
<dbus::Bus
> bus
= new dbus::Bus(options
);
182 ASSERT_FALSE(bus
->shutdown_completed());
184 dbus::ExportedObject
* object_proxy1
=
185 bus
->GetExportedObject(dbus::ObjectPath("/org/chromium/TestObject"));
186 ASSERT_TRUE(object_proxy1
);
188 // Increment the reference count to the object proxy to avoid destroying it
189 // calling UnregisterExportedObject. This ensures the dbus::ExportedObject is
190 // not freed from memory. See http://crbug.com/137846 for details.
191 object_proxy1
->AddRef();
193 bus
->UnregisterExportedObject(dbus::ObjectPath("/org/chromium/TestObject"));
195 // This should return a new object because the object_proxy1 is still in
197 dbus::ExportedObject
* object_proxy2
=
198 bus
->GetExportedObject(dbus::ObjectPath("/org/chromium/TestObject"));
199 ASSERT_TRUE(object_proxy2
);
200 EXPECT_NE(object_proxy1
, object_proxy2
);
202 // Release the incremented reference.
203 object_proxy1
->Release();
205 // Shut down synchronously.
206 bus
->ShutdownOnDBusThreadAndBlock();
207 EXPECT_TRUE(bus
->shutdown_completed());
211 TEST(BusTest
, ShutdownAndBlock
) {
212 dbus::Bus::Options options
;
213 scoped_refptr
<dbus::Bus
> bus
= new dbus::Bus(options
);
214 ASSERT_FALSE(bus
->shutdown_completed());
216 // Shut down synchronously.
217 bus
->ShutdownAndBlock();
218 EXPECT_TRUE(bus
->shutdown_completed());
221 TEST(BusTest
, ShutdownAndBlockWithDBusThread
) {
222 // Start the D-Bus thread.
223 base::Thread::Options thread_options
;
224 thread_options
.message_loop_type
= MessageLoop::TYPE_IO
;
225 base::Thread
dbus_thread("D-Bus thread");
226 dbus_thread
.StartWithOptions(thread_options
);
229 dbus::Bus::Options options
;
230 options
.dbus_task_runner
= dbus_thread
.message_loop_proxy();
231 scoped_refptr
<dbus::Bus
> bus
= new dbus::Bus(options
);
232 ASSERT_FALSE(bus
->shutdown_completed());
234 // Shut down synchronously.
235 bus
->ShutdownOnDBusThreadAndBlock();
236 EXPECT_TRUE(bus
->shutdown_completed());
240 TEST(BusTest
, AddFilterFunction
) {
241 dbus::Bus::Options options
;
242 scoped_refptr
<dbus::Bus
> bus
= new dbus::Bus(options
);
243 // Should connect before calling AddFilterFunction().
248 ASSERT_TRUE(bus
->AddFilterFunction(&DummyHandler
, &data1
));
249 // Cannot add the same function with the same data.
250 ASSERT_FALSE(bus
->AddFilterFunction(&DummyHandler
, &data1
));
251 // Can add the same function with different data.
252 ASSERT_TRUE(bus
->AddFilterFunction(&DummyHandler
, &data2
));
254 ASSERT_TRUE(bus
->RemoveFilterFunction(&DummyHandler
, &data1
));
255 ASSERT_FALSE(bus
->RemoveFilterFunction(&DummyHandler
, &data1
));
256 ASSERT_TRUE(bus
->RemoveFilterFunction(&DummyHandler
, &data2
));
258 bus
->ShutdownAndBlock();
261 TEST(BusTest
, DoubleAddAndRemoveMatch
) {
262 dbus::Bus::Options options
;
263 scoped_refptr
<dbus::Bus
> bus
= new dbus::Bus(options
);
264 dbus::ScopedDBusError error
;
268 // Adds the same rule twice.
270 "type='signal',interface='org.chromium.TestService',path='/'",
272 ASSERT_FALSE(error
.is_set());
275 "type='signal',interface='org.chromium.TestService',path='/'",
277 ASSERT_FALSE(error
.is_set());
279 // Removes the same rule twice.
280 ASSERT_TRUE(bus
->RemoveMatch(
281 "type='signal',interface='org.chromium.TestService',path='/'",
283 ASSERT_FALSE(error
.is_set());
285 // The rule should be still in the bus since it was removed only once.
286 // A second removal shouldn't give an error.
287 ASSERT_TRUE(bus
->RemoveMatch(
288 "type='signal',interface='org.chromium.TestService',path='/'",
290 ASSERT_FALSE(error
.is_set());
292 // A third attemp to remove the same rule should fail.
293 ASSERT_FALSE(bus
->RemoveMatch(
294 "type='signal',interface='org.chromium.TestService',path='/'",
297 bus
->ShutdownAndBlock();