blob: d69556983906755675bf2efcfc4557e508e8a533 [file] [log] [blame]
adamk@chromium.org35c0eef2012-02-11 06:45:23 +09001// Copyright (c) 2012 The Chromium Authors. All rights reserved.
satorux@chromium.orgdccbb7b2011-08-24 04:25:20 +09002// 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/bus.h"
6
satorux@chromium.orgd336d452011-09-02 15:56:23 +09007#include "base/bind.h"
satorux@chromium.orgdccbb7b2011-08-24 04:25:20 +09008#include "base/memory/ref_counted.h"
avi@chromium.orga29af562013-07-18 08:00:30 +09009#include "base/message_loop/message_loop.h"
thestig@chromium.orgc2482f12013-06-11 07:52:34 +090010#include "base/run_loop.h"
satorux@chromium.orgd336d452011-09-02 15:56:23 +090011#include "base/threading/thread.h"
satorux@chromium.orgdccbb7b2011-08-24 04:25:20 +090012#include "dbus/exported_object.h"
keybuk@google.combf4649a2012-02-15 06:29:06 +090013#include "dbus/object_path.h"
satorux@chromium.orgdccbb7b2011-08-24 04:25:20 +090014#include "dbus/object_proxy.h"
deymo@chromium.org7894ebf2013-01-31 15:08:02 +090015#include "dbus/scoped_dbus_error.h"
thestig@chromium.orgc2482f12013-06-11 07:52:34 +090016#include "dbus/test_service.h"
satorux@chromium.orgdccbb7b2011-08-24 04:25:20 +090017
18#include "testing/gtest/include/gtest/gtest.h"
19
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +090020namespace dbus {
21
satorux@chromium.org66bc4c22011-10-06 09:20:53 +090022namespace {
23
24// Used to test AddFilterFunction().
25DBusHandlerResult DummyHandler(DBusConnection* connection,
26 DBusMessage* raw_message,
27 void* user_data) {
28 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
29}
30
thestig@chromium.orgc2482f12013-06-11 07:52:34 +090031// Test helper for BusTest.ListenForServiceOwnerChange that wraps a
32// base::RunLoop. At Run() time, the caller pass in the expected number of
33// quit calls, and at QuitIfConditionIsSatisified() time, only quit the RunLoop
34// if the expected number of quit calls have been reached.
35class RunLoopWithExpectedCount {
36 public:
37 RunLoopWithExpectedCount() : expected_quit_calls_(0), actual_quit_calls_(0) {}
38 ~RunLoopWithExpectedCount() {}
39
40 void Run(int expected_quit_calls) {
41 DCHECK_EQ(0, expected_quit_calls_);
42 DCHECK_EQ(0, actual_quit_calls_);
43 expected_quit_calls_ = expected_quit_calls;
44 run_loop_.reset(new base::RunLoop());
45 run_loop_->Run();
46 }
47
48 void QuitIfConditionIsSatisified() {
49 if (++actual_quit_calls_ != expected_quit_calls_)
50 return;
51 run_loop_->Quit();
52 expected_quit_calls_ = 0;
53 actual_quit_calls_ = 0;
54 }
55
56 private:
57 scoped_ptr<base::RunLoop> run_loop_;
58 int expected_quit_calls_;
59 int actual_quit_calls_;
60
61 DISALLOW_COPY_AND_ASSIGN(RunLoopWithExpectedCount);
62};
63
64// Test helper for BusTest.ListenForServiceOwnerChange.
65void OnServiceOwnerChanged(RunLoopWithExpectedCount* run_loop_state,
66 std::string* service_owner,
67 int* num_of_owner_changes,
68 const std::string& new_service_owner) {
69 *service_owner = new_service_owner;
70 ++(*num_of_owner_changes);
71 run_loop_state->QuitIfConditionIsSatisified();
72}
73
satorux@chromium.org66bc4c22011-10-06 09:20:53 +090074} // namespace
75
satorux@chromium.orgdccbb7b2011-08-24 04:25:20 +090076TEST(BusTest, GetObjectProxy) {
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +090077 Bus::Options options;
78 scoped_refptr<Bus> bus = new Bus(options);
satorux@chromium.orgdccbb7b2011-08-24 04:25:20 +090079
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +090080 ObjectProxy* object_proxy1 =
satorux@chromium.orgdccbb7b2011-08-24 04:25:20 +090081 bus->GetObjectProxy("org.chromium.TestService",
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +090082 ObjectPath("/org/chromium/TestObject"));
satorux@chromium.orgdccbb7b2011-08-24 04:25:20 +090083 ASSERT_TRUE(object_proxy1);
84
85 // This should return the same object.
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +090086 ObjectProxy* object_proxy2 =
satorux@chromium.orgdccbb7b2011-08-24 04:25:20 +090087 bus->GetObjectProxy("org.chromium.TestService",
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +090088 ObjectPath("/org/chromium/TestObject"));
satorux@chromium.orgdccbb7b2011-08-24 04:25:20 +090089 ASSERT_TRUE(object_proxy2);
90 EXPECT_EQ(object_proxy1, object_proxy2);
91
92 // This should not.
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +090093 ObjectProxy* object_proxy3 =
keybuk@google.combf4649a2012-02-15 06:29:06 +090094 bus->GetObjectProxy(
95 "org.chromium.TestService",
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +090096 ObjectPath("/org/chromium/DifferentTestObject"));
satorux@chromium.orgdccbb7b2011-08-24 04:25:20 +090097 ASSERT_TRUE(object_proxy3);
98 EXPECT_NE(object_proxy1, object_proxy3);
satorux@chromium.orgf06eb892011-10-13 09:45:26 +090099
100 bus->ShutdownAndBlock();
satorux@chromium.orgdccbb7b2011-08-24 04:25:20 +0900101}
102
adamk@chromium.org35c0eef2012-02-11 06:45:23 +0900103TEST(BusTest, GetObjectProxyIgnoreUnknownService) {
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900104 Bus::Options options;
105 scoped_refptr<Bus> bus = new Bus(options);
adamk@chromium.org35c0eef2012-02-11 06:45:23 +0900106
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900107 ObjectProxy* object_proxy1 =
adamk@chromium.org35c0eef2012-02-11 06:45:23 +0900108 bus->GetObjectProxyWithOptions(
109 "org.chromium.TestService",
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900110 ObjectPath("/org/chromium/TestObject"),
111 ObjectProxy::IGNORE_SERVICE_UNKNOWN_ERRORS);
adamk@chromium.org35c0eef2012-02-11 06:45:23 +0900112 ASSERT_TRUE(object_proxy1);
113
114 // This should return the same object.
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900115 ObjectProxy* object_proxy2 =
adamk@chromium.org35c0eef2012-02-11 06:45:23 +0900116 bus->GetObjectProxyWithOptions(
117 "org.chromium.TestService",
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900118 ObjectPath("/org/chromium/TestObject"),
119 ObjectProxy::IGNORE_SERVICE_UNKNOWN_ERRORS);
adamk@chromium.org35c0eef2012-02-11 06:45:23 +0900120 ASSERT_TRUE(object_proxy2);
121 EXPECT_EQ(object_proxy1, object_proxy2);
122
123 // This should not.
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900124 ObjectProxy* object_proxy3 =
adamk@chromium.org35c0eef2012-02-11 06:45:23 +0900125 bus->GetObjectProxyWithOptions(
126 "org.chromium.TestService",
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900127 ObjectPath("/org/chromium/DifferentTestObject"),
128 ObjectProxy::IGNORE_SERVICE_UNKNOWN_ERRORS);
adamk@chromium.org35c0eef2012-02-11 06:45:23 +0900129 ASSERT_TRUE(object_proxy3);
130 EXPECT_NE(object_proxy1, object_proxy3);
131
132 bus->ShutdownAndBlock();
133}
134
deymo@chromium.org6d168a72013-01-30 05:29:12 +0900135TEST(BusTest, RemoveObjectProxy) {
136 // Setup the current thread's MessageLoop.
xhwang@chromium.orgdff6b132013-05-02 01:10:30 +0900137 base::MessageLoop message_loop;
deymo@chromium.org6d168a72013-01-30 05:29:12 +0900138
139 // Start the D-Bus thread.
140 base::Thread::Options thread_options;
xhwang@chromium.orgdff6b132013-05-02 01:10:30 +0900141 thread_options.message_loop_type = base::MessageLoop::TYPE_IO;
deymo@chromium.org6d168a72013-01-30 05:29:12 +0900142 base::Thread dbus_thread("D-Bus thread");
143 dbus_thread.StartWithOptions(thread_options);
144
145 // Create the bus.
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900146 Bus::Options options;
thestig@chromium.org074b1db2013-02-20 10:36:53 +0900147 options.dbus_task_runner = dbus_thread.message_loop_proxy();
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900148 scoped_refptr<Bus> bus = new Bus(options);
deymo@chromium.org6d168a72013-01-30 05:29:12 +0900149 ASSERT_FALSE(bus->shutdown_completed());
150
151 // Try to remove a non existant object proxy should return false.
152 ASSERT_FALSE(
153 bus->RemoveObjectProxy("org.chromium.TestService",
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900154 ObjectPath("/org/chromium/TestObject"),
deymo@chromium.org6d168a72013-01-30 05:29:12 +0900155 base::Bind(&base::DoNothing)));
156
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900157 ObjectProxy* object_proxy1 =
deymo@chromium.org6d168a72013-01-30 05:29:12 +0900158 bus->GetObjectProxy("org.chromium.TestService",
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900159 ObjectPath("/org/chromium/TestObject"));
deymo@chromium.org6d168a72013-01-30 05:29:12 +0900160 ASSERT_TRUE(object_proxy1);
161
162 // Increment the reference count to the object proxy to avoid destroying it
163 // while removing the object.
164 object_proxy1->AddRef();
165
166 // Remove the object from the bus. This will invalidate any other usage of
167 // object_proxy1 other than destroy it. We keep this object for a comparison
168 // at a later time.
169 ASSERT_TRUE(
170 bus->RemoveObjectProxy("org.chromium.TestService",
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900171 ObjectPath("/org/chromium/TestObject"),
deymo@chromium.org6d168a72013-01-30 05:29:12 +0900172 base::Bind(&base::DoNothing)));
173
174 // This should return a different object because the first object was removed
175 // from the bus, but not deleted from memory.
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900176 ObjectProxy* object_proxy2 =
deymo@chromium.org6d168a72013-01-30 05:29:12 +0900177 bus->GetObjectProxy("org.chromium.TestService",
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900178 ObjectPath("/org/chromium/TestObject"));
deymo@chromium.org6d168a72013-01-30 05:29:12 +0900179 ASSERT_TRUE(object_proxy2);
180
181 // Compare the new object with the first object. The first object still exists
182 // thanks to the increased reference.
183 EXPECT_NE(object_proxy1, object_proxy2);
184
185 // Release object_proxy1.
186 object_proxy1->Release();
187
188 // Shut down synchronously.
189 bus->ShutdownOnDBusThreadAndBlock();
190 EXPECT_TRUE(bus->shutdown_completed());
191 dbus_thread.Stop();
192}
193
satorux@chromium.orgdccbb7b2011-08-24 04:25:20 +0900194TEST(BusTest, GetExportedObject) {
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900195 Bus::Options options;
196 scoped_refptr<Bus> bus = new Bus(options);
satorux@chromium.orgdccbb7b2011-08-24 04:25:20 +0900197
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900198 ExportedObject* object_proxy1 =
199 bus->GetExportedObject(ObjectPath("/org/chromium/TestObject"));
satorux@chromium.orgdccbb7b2011-08-24 04:25:20 +0900200 ASSERT_TRUE(object_proxy1);
201
202 // This should return the same object.
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900203 ExportedObject* object_proxy2 =
204 bus->GetExportedObject(ObjectPath("/org/chromium/TestObject"));
satorux@chromium.orgdccbb7b2011-08-24 04:25:20 +0900205 ASSERT_TRUE(object_proxy2);
206 EXPECT_EQ(object_proxy1, object_proxy2);
207
208 // This should not.
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900209 ExportedObject* object_proxy3 =
keybuk@google.combf4649a2012-02-15 06:29:06 +0900210 bus->GetExportedObject(
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900211 ObjectPath("/org/chromium/DifferentTestObject"));
satorux@chromium.orgdccbb7b2011-08-24 04:25:20 +0900212 ASSERT_TRUE(object_proxy3);
213 EXPECT_NE(object_proxy1, object_proxy3);
satorux@chromium.orgf06eb892011-10-13 09:45:26 +0900214
215 bus->ShutdownAndBlock();
satorux@chromium.orgdccbb7b2011-08-24 04:25:20 +0900216}
satorux@chromium.orgd336d452011-09-02 15:56:23 +0900217
deymo@chromium.org03ec2482013-01-24 09:58:35 +0900218TEST(BusTest, UnregisterExportedObject) {
keybuk@chromium.orgd2ca8f32012-03-14 10:18:35 +0900219 // Start the D-Bus thread.
220 base::Thread::Options thread_options;
xhwang@chromium.orgdff6b132013-05-02 01:10:30 +0900221 thread_options.message_loop_type = base::MessageLoop::TYPE_IO;
keybuk@chromium.orgd2ca8f32012-03-14 10:18:35 +0900222 base::Thread dbus_thread("D-Bus thread");
223 dbus_thread.StartWithOptions(thread_options);
224
225 // Create the bus.
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900226 Bus::Options options;
thestig@chromium.org074b1db2013-02-20 10:36:53 +0900227 options.dbus_task_runner = dbus_thread.message_loop_proxy();
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900228 scoped_refptr<Bus> bus = new Bus(options);
keybuk@chromium.orgd2ca8f32012-03-14 10:18:35 +0900229 ASSERT_FALSE(bus->shutdown_completed());
230
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900231 ExportedObject* object_proxy1 =
232 bus->GetExportedObject(ObjectPath("/org/chromium/TestObject"));
keybuk@chromium.orgd2ca8f32012-03-14 10:18:35 +0900233 ASSERT_TRUE(object_proxy1);
234
deymo@chromium.org03ec2482013-01-24 09:58:35 +0900235 // Increment the reference count to the object proxy to avoid destroying it
236 // calling UnregisterExportedObject. This ensures the dbus::ExportedObject is
237 // not freed from memory. See http://crbug.com/137846 for details.
238 object_proxy1->AddRef();
239
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900240 bus->UnregisterExportedObject(ObjectPath("/org/chromium/TestObject"));
keybuk@chromium.orgd2ca8f32012-03-14 10:18:35 +0900241
deymo@chromium.org03ec2482013-01-24 09:58:35 +0900242 // This should return a new object because the object_proxy1 is still in
243 // alloc'ed memory.
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900244 ExportedObject* object_proxy2 =
245 bus->GetExportedObject(ObjectPath("/org/chromium/TestObject"));
keybuk@chromium.orgd2ca8f32012-03-14 10:18:35 +0900246 ASSERT_TRUE(object_proxy2);
247 EXPECT_NE(object_proxy1, object_proxy2);
248
deymo@chromium.org03ec2482013-01-24 09:58:35 +0900249 // Release the incremented reference.
250 object_proxy1->Release();
251
keybuk@chromium.orgd2ca8f32012-03-14 10:18:35 +0900252 // Shut down synchronously.
253 bus->ShutdownOnDBusThreadAndBlock();
254 EXPECT_TRUE(bus->shutdown_completed());
255 dbus_thread.Stop();
256}
257
satorux@chromium.orgd336d452011-09-02 15:56:23 +0900258TEST(BusTest, ShutdownAndBlock) {
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900259 Bus::Options options;
260 scoped_refptr<Bus> bus = new Bus(options);
satorux@chromium.orgd336d452011-09-02 15:56:23 +0900261 ASSERT_FALSE(bus->shutdown_completed());
262
263 // Shut down synchronously.
264 bus->ShutdownAndBlock();
265 EXPECT_TRUE(bus->shutdown_completed());
266}
267
268TEST(BusTest, ShutdownAndBlockWithDBusThread) {
269 // Start the D-Bus thread.
270 base::Thread::Options thread_options;
xhwang@chromium.orgdff6b132013-05-02 01:10:30 +0900271 thread_options.message_loop_type = base::MessageLoop::TYPE_IO;
satorux@chromium.orgd336d452011-09-02 15:56:23 +0900272 base::Thread dbus_thread("D-Bus thread");
273 dbus_thread.StartWithOptions(thread_options);
274
275 // Create the bus.
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900276 Bus::Options options;
thestig@chromium.org074b1db2013-02-20 10:36:53 +0900277 options.dbus_task_runner = dbus_thread.message_loop_proxy();
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900278 scoped_refptr<Bus> bus = new Bus(options);
satorux@chromium.orgd336d452011-09-02 15:56:23 +0900279 ASSERT_FALSE(bus->shutdown_completed());
280
281 // Shut down synchronously.
282 bus->ShutdownOnDBusThreadAndBlock();
283 EXPECT_TRUE(bus->shutdown_completed());
284 dbus_thread.Stop();
285}
satorux@chromium.org66bc4c22011-10-06 09:20:53 +0900286
287TEST(BusTest, AddFilterFunction) {
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900288 Bus::Options options;
289 scoped_refptr<Bus> bus = new Bus(options);
satorux@chromium.org66bc4c22011-10-06 09:20:53 +0900290 // Should connect before calling AddFilterFunction().
291 bus->Connect();
292
293 int data1 = 100;
294 int data2 = 200;
295 ASSERT_TRUE(bus->AddFilterFunction(&DummyHandler, &data1));
296 // Cannot add the same function with the same data.
297 ASSERT_FALSE(bus->AddFilterFunction(&DummyHandler, &data1));
298 // Can add the same function with different data.
299 ASSERT_TRUE(bus->AddFilterFunction(&DummyHandler, &data2));
300
301 ASSERT_TRUE(bus->RemoveFilterFunction(&DummyHandler, &data1));
302 ASSERT_FALSE(bus->RemoveFilterFunction(&DummyHandler, &data1));
303 ASSERT_TRUE(bus->RemoveFilterFunction(&DummyHandler, &data2));
304
305 bus->ShutdownAndBlock();
306}
deymo@chromium.org7894ebf2013-01-31 15:08:02 +0900307
308TEST(BusTest, DoubleAddAndRemoveMatch) {
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900309 Bus::Options options;
310 scoped_refptr<Bus> bus = new Bus(options);
311 ScopedDBusError error;
deymo@chromium.org7894ebf2013-01-31 15:08:02 +0900312
313 bus->Connect();
314
315 // Adds the same rule twice.
316 bus->AddMatch(
317 "type='signal',interface='org.chromium.TestService',path='/'",
318 error.get());
319 ASSERT_FALSE(error.is_set());
320
321 bus->AddMatch(
322 "type='signal',interface='org.chromium.TestService',path='/'",
323 error.get());
324 ASSERT_FALSE(error.is_set());
325
326 // Removes the same rule twice.
327 ASSERT_TRUE(bus->RemoveMatch(
328 "type='signal',interface='org.chromium.TestService',path='/'",
329 error.get()));
330 ASSERT_FALSE(error.is_set());
331
332 // The rule should be still in the bus since it was removed only once.
333 // A second removal shouldn't give an error.
334 ASSERT_TRUE(bus->RemoveMatch(
335 "type='signal',interface='org.chromium.TestService',path='/'",
336 error.get()));
337 ASSERT_FALSE(error.is_set());
338
339 // A third attemp to remove the same rule should fail.
340 ASSERT_FALSE(bus->RemoveMatch(
341 "type='signal',interface='org.chromium.TestService',path='/'",
342 error.get()));
343
344 bus->ShutdownAndBlock();
345}
thestig@chromium.orgc2482f12013-06-11 07:52:34 +0900346
347TEST(BusTest, ListenForServiceOwnerChange) {
348 // Setup the current thread's MessageLoop. Must be of TYPE_IO for the
349 // listeners to work.
350 base::MessageLoop message_loop(base::MessageLoop::TYPE_IO);
351 RunLoopWithExpectedCount run_loop_state;
352
353 // Create the bus.
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900354 Bus::Options bus_options;
355 scoped_refptr<Bus> bus = new Bus(bus_options);
thestig@chromium.orgc2482f12013-06-11 07:52:34 +0900356
357 // Add a listener.
358 std::string service_owner1;
359 int num_of_owner_changes1 = 0;
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900360 Bus::GetServiceOwnerCallback callback1 =
thestig@chromium.orgc2482f12013-06-11 07:52:34 +0900361 base::Bind(&OnServiceOwnerChanged,
362 &run_loop_state,
363 &service_owner1,
364 &num_of_owner_changes1);
365 bus->ListenForServiceOwnerChange("org.chromium.TestService", callback1);
366 // This should be a no-op.
367 bus->ListenForServiceOwnerChange("org.chromium.TestService", callback1);
368 base::RunLoop().RunUntilIdle();
369
370 // Nothing has happened yet. Check initial state.
371 EXPECT_TRUE(service_owner1.empty());
372 EXPECT_EQ(0, num_of_owner_changes1);
373
374 // Make an ownership change.
cmasone@chromium.org989857e2013-07-31 15:34:59 +0900375 ASSERT_TRUE(bus->RequestOwnershipAndBlock("org.chromium.TestService",
376 Bus::REQUIRE_PRIMARY));
thestig@chromium.orgc2482f12013-06-11 07:52:34 +0900377 run_loop_state.Run(1);
378
379 {
380 // Get the current service owner and check to make sure the listener got
381 // the right value.
382 std::string current_service_owner =
383 bus->GetServiceOwnerAndBlock("org.chromium.TestService",
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900384 Bus::REPORT_ERRORS);
thestig@chromium.orgc2482f12013-06-11 07:52:34 +0900385 ASSERT_FALSE(current_service_owner.empty());
386
387 // Make sure the listener heard about the new owner.
388 EXPECT_EQ(current_service_owner, service_owner1);
389
390 // Test the second ListenForServiceOwnerChange() above is indeed a no-op.
391 EXPECT_EQ(1, num_of_owner_changes1);
392 }
393
394 // Add a second listener.
395 std::string service_owner2;
396 int num_of_owner_changes2 = 0;
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900397 Bus::GetServiceOwnerCallback callback2 =
thestig@chromium.orgc2482f12013-06-11 07:52:34 +0900398 base::Bind(&OnServiceOwnerChanged,
399 &run_loop_state,
400 &service_owner2,
401 &num_of_owner_changes2);
402 bus->ListenForServiceOwnerChange("org.chromium.TestService", callback2);
403 base::RunLoop().RunUntilIdle();
404
405 // Release the ownership and make sure the service owner listeners fire with
406 // the right values and the right number of times.
407 ASSERT_TRUE(bus->ReleaseOwnership("org.chromium.TestService"));
408 run_loop_state.Run(2);
409
410 EXPECT_TRUE(service_owner1.empty());
411 EXPECT_TRUE(service_owner2.empty());
412 EXPECT_EQ(2, num_of_owner_changes1);
413 EXPECT_EQ(1, num_of_owner_changes2);
414
415 // Unlisten so shutdown can proceed correctly.
416 bus->UnlistenForServiceOwnerChange("org.chromium.TestService", callback1);
417 bus->UnlistenForServiceOwnerChange("org.chromium.TestService", callback2);
418 base::RunLoop().RunUntilIdle();
419
420 // Shut down synchronously.
421 bus->ShutdownAndBlock();
422 EXPECT_TRUE(bus->shutdown_completed());
423}
thestig@chromium.orgf0b7eac2013-06-13 15:37:19 +0900424
425} // namespace dbus