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.
4
5 #include <stddef.h>
6
7 #include <algorithm>
8 #include <memory>
9 #include <string>
10 #include <vector>
11
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "base/macros.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/run_loop.h"
17 #include "base/single_thread_task_runner.h"
18 #include "base/stl_util.h"
19 #include "base/test/test_timeouts.h"
20 #include "base/threading/thread.h"
21 #include "base/threading/thread_restrictions.h"
22 #include "dbus/bus.h"
23 #include "dbus/message.h"
24 #include "dbus/object_path.h"
25 #include "dbus/object_proxy.h"
26 #include "dbus/test_service.h"
27 #include "testing/gtest/include/gtest/gtest.h"
28
29 namespace dbus {
30
31 namespace {
32
33 // See comments in ObjectProxy::RunResponseCallback() for why the number was
34 // chosen.
35 const int kHugePayloadSize = 64 << 20; // 64 MB
36
37 } // namespace
38
39 // The end-to-end test exercises the asynchronous APIs in ObjectProxy and
40 // ExportedObject.
41 class EndToEndAsyncTest : public testing::Test {
42 public:
SetUp()43 void SetUp() override {
44 // Make the main thread not to allow IO.
45 base::ThreadRestrictions::SetIOAllowed(false);
46
47 // Start the D-Bus thread.
48 dbus_thread_.reset(new base::Thread("D-Bus Thread"));
49 base::Thread::Options thread_options;
50 thread_options.message_loop_type = base::MessageLoop::TYPE_IO;
51 ASSERT_TRUE(dbus_thread_->StartWithOptions(thread_options));
52
53 // Start the test service, using the D-Bus thread.
54 TestService::Options options;
55 options.dbus_task_runner = dbus_thread_->task_runner();
56 test_service_.reset(new TestService(options));
57 ASSERT_TRUE(test_service_->StartService());
58 ASSERT_TRUE(test_service_->WaitUntilServiceIsStarted());
59 ASSERT_TRUE(test_service_->HasDBusThread());
60
61 // Create the client, using the D-Bus thread.
62 Bus::Options bus_options;
63 bus_options.bus_type = Bus::SESSION;
64 bus_options.connection_type = Bus::PRIVATE;
65 bus_options.dbus_task_runner = dbus_thread_->task_runner();
66 bus_ = new Bus(bus_options);
67 object_proxy_ = bus_->GetObjectProxy(
68 test_service_->service_name(),
69 ObjectPath("/org/chromium/TestObject"));
70 ASSERT_TRUE(bus_->HasDBusThread());
71
72 // Connect to the "Test" signal of "org.chromium.TestInterface" from
73 // the remote object.
74 object_proxy_->ConnectToSignal(
75 "org.chromium.TestInterface",
76 "Test",
77 base::Bind(&EndToEndAsyncTest::OnTestSignal,
78 base::Unretained(this)),
79 base::Bind(&EndToEndAsyncTest::OnConnected,
80 base::Unretained(this)));
81 // Wait until the object proxy is connected to the signal.
82 run_loop_.reset(new base::RunLoop());
83 run_loop_->Run();
84
85 // Connect to the "Test2" signal of "org.chromium.TestInterface" from
86 // the remote object. There was a bug where we were emitting error
87 // messages like "Requested to remove an unknown match rule: ..." at
88 // the shutdown of Bus when an object proxy is connected to more than
89 // one signal of the same interface. See crosbug.com/23382 for details.
90 object_proxy_->ConnectToSignal(
91 "org.chromium.TestInterface",
92 "Test2",
93 base::Bind(&EndToEndAsyncTest::OnTest2Signal,
94 base::Unretained(this)),
95 base::Bind(&EndToEndAsyncTest::OnConnected,
96 base::Unretained(this)));
97 // Wait until the object proxy is connected to the signal.
98 run_loop_.reset(new base::RunLoop());
99 run_loop_->Run();
100
101 // Create a second object proxy for the root object.
102 root_object_proxy_ = bus_->GetObjectProxy(test_service_->service_name(),
103 ObjectPath("/"));
104 ASSERT_TRUE(bus_->HasDBusThread());
105
106 // Connect to the "Test" signal of "org.chromium.TestInterface" from
107 // the root remote object too.
108 root_object_proxy_->ConnectToSignal(
109 "org.chromium.TestInterface",
110 "Test",
111 base::Bind(&EndToEndAsyncTest::OnRootTestSignal,
112 base::Unretained(this)),
113 base::Bind(&EndToEndAsyncTest::OnConnected,
114 base::Unretained(this)));
115 // Wait until the root object proxy is connected to the signal.
116 run_loop_.reset(new base::RunLoop());
117 run_loop_->Run();
118 }
119
TearDown()120 void TearDown() override {
121 bus_->ShutdownOnDBusThreadAndBlock();
122
123 // Shut down the service.
124 test_service_->ShutdownAndBlock();
125
126 // Reset to the default.
127 base::ThreadRestrictions::SetIOAllowed(true);
128
129 // Stopping a thread is considered an IO operation, so do this after
130 // allowing IO.
131 test_service_->Stop();
132 }
133
134 protected:
135 // Replaces the bus with a broken one.
SetUpBrokenBus()136 void SetUpBrokenBus() {
137 // Shut down the existing bus.
138 bus_->ShutdownOnDBusThreadAndBlock();
139
140 // Create new bus with invalid address.
141 const char kInvalidAddress[] = "";
142 Bus::Options bus_options;
143 bus_options.bus_type = Bus::CUSTOM_ADDRESS;
144 bus_options.address = kInvalidAddress;
145 bus_options.connection_type = Bus::PRIVATE;
146 bus_options.dbus_task_runner = dbus_thread_->task_runner();
147 bus_ = new Bus(bus_options);
148 ASSERT_TRUE(bus_->HasDBusThread());
149
150 // Create new object proxy.
151 object_proxy_ = bus_->GetObjectProxy(
152 test_service_->service_name(),
153 ObjectPath("/org/chromium/TestObject"));
154 }
155
156 // Calls the method asynchronously. OnResponse() will be called once the
157 // response is received.
CallMethod(MethodCall * method_call,int timeout_ms)158 void CallMethod(MethodCall* method_call,
159 int timeout_ms) {
160 object_proxy_->CallMethod(method_call,
161 timeout_ms,
162 base::Bind(&EndToEndAsyncTest::OnResponse,
163 base::Unretained(this)));
164 }
165
166 // Calls the method asynchronously. OnResponse() will be called once the
167 // response is received without error, otherwise OnError() will be called.
CallMethodWithErrorCallback(MethodCall * method_call,int timeout_ms)168 void CallMethodWithErrorCallback(MethodCall* method_call,
169 int timeout_ms) {
170 object_proxy_->CallMethodWithErrorCallback(
171 method_call,
172 timeout_ms,
173 base::Bind(&EndToEndAsyncTest::OnResponse, base::Unretained(this)),
174 base::Bind(&EndToEndAsyncTest::OnError, base::Unretained(this)));
175 }
176
177 // Wait for the give number of responses.
WaitForResponses(size_t num_responses)178 void WaitForResponses(size_t num_responses) {
179 while (response_strings_.size() < num_responses) {
180 run_loop_.reset(new base::RunLoop);
181 run_loop_->Run();
182 }
183 }
184
185 // Called when the response is received.
OnResponse(Response * response)186 void OnResponse(Response* response) {
187 // |response| will be deleted on exit of the function. Copy the
188 // payload to |response_strings_|.
189 if (response) {
190 MessageReader reader(response);
191 std::string response_string;
192 ASSERT_TRUE(reader.PopString(&response_string));
193 response_strings_.push_back(response_string);
194 } else {
195 response_strings_.push_back(std::string());
196 }
197 run_loop_->Quit();
198 };
199
200 // Wait for the given number of errors.
WaitForErrors(size_t num_errors)201 void WaitForErrors(size_t num_errors) {
202 while (error_names_.size() < num_errors) {
203 run_loop_.reset(new base::RunLoop);
204 run_loop_->Run();
205 }
206 }
207
208 // Called when an error is received.
OnError(ErrorResponse * error)209 void OnError(ErrorResponse* error) {
210 // |error| will be deleted on exit of the function. Copy the payload to
211 // |error_names_|.
212 if (error) {
213 ASSERT_NE("", error->GetErrorName());
214 error_names_.push_back(error->GetErrorName());
215 } else {
216 error_names_.push_back(std::string());
217 }
218 run_loop_->Quit();
219 }
220
221 // Called when the "Test" signal is received, in the main thread.
222 // Copy the string payload to |test_signal_string_|.
OnTestSignal(Signal * signal)223 void OnTestSignal(Signal* signal) {
224 MessageReader reader(signal);
225 ASSERT_TRUE(reader.PopString(&test_signal_string_));
226 run_loop_->Quit();
227 }
228
229 // Called when the "Test" signal is received, in the main thread, by
230 // the root object proxy. Copy the string payload to
231 // |root_test_signal_string_|.
OnRootTestSignal(Signal * signal)232 void OnRootTestSignal(Signal* signal) {
233 MessageReader reader(signal);
234 ASSERT_TRUE(reader.PopString(&root_test_signal_string_));
235 run_loop_->Quit();
236 }
237
238 // Called when the "Test2" signal is received, in the main thread.
OnTest2Signal(Signal * signal)239 void OnTest2Signal(Signal* signal) {
240 MessageReader reader(signal);
241 run_loop_->Quit();
242 }
243
244 // Called when connected to the signal.
OnConnected(const std::string & interface_name,const std::string & signal_name,bool success)245 void OnConnected(const std::string& interface_name,
246 const std::string& signal_name,
247 bool success) {
248 ASSERT_TRUE(success);
249 run_loop_->Quit();
250 }
251
252 // Wait for the hey signal to be received.
WaitForTestSignal()253 void WaitForTestSignal() {
254 // OnTestSignal() will quit the message loop.
255 run_loop_.reset(new base::RunLoop);
256 run_loop_->Run();
257 }
258
259 base::MessageLoop message_loop_;
260 std::unique_ptr<base::RunLoop> run_loop_;
261 std::vector<std::string> response_strings_;
262 std::vector<std::string> error_names_;
263 std::unique_ptr<base::Thread> dbus_thread_;
264 scoped_refptr<Bus> bus_;
265 ObjectProxy* object_proxy_;
266 ObjectProxy* root_object_proxy_;
267 std::unique_ptr<TestService> test_service_;
268 // Text message from "Test" signal.
269 std::string test_signal_string_;
270 // Text message from "Test" signal delivered to root.
271 std::string root_test_signal_string_;
272 };
273
TEST_F(EndToEndAsyncTest,Echo)274 TEST_F(EndToEndAsyncTest, Echo) {
275 const char* kHello = "hello";
276
277 // Create the method call.
278 MethodCall method_call("org.chromium.TestInterface", "Echo");
279 MessageWriter writer(&method_call);
280 writer.AppendString(kHello);
281
282 // Call the method.
283 const int timeout_ms = ObjectProxy::TIMEOUT_USE_DEFAULT;
284 CallMethod(&method_call, timeout_ms);
285
286 // Check the response.
287 WaitForResponses(1);
288 EXPECT_EQ(kHello, response_strings_[0]);
289 }
290
TEST_F(EndToEndAsyncTest,EchoWithErrorCallback)291 TEST_F(EndToEndAsyncTest, EchoWithErrorCallback) {
292 const char* kHello = "hello";
293
294 // Create the method call.
295 MethodCall method_call("org.chromium.TestInterface", "Echo");
296 MessageWriter writer(&method_call);
297 writer.AppendString(kHello);
298
299 // Call the method.
300 const int timeout_ms = ObjectProxy::TIMEOUT_USE_DEFAULT;
301 CallMethodWithErrorCallback(&method_call, timeout_ms);
302
303 // Check the response.
304 WaitForResponses(1);
305 EXPECT_EQ(kHello, response_strings_[0]);
306 EXPECT_TRUE(error_names_.empty());
307 }
308
309 // Call Echo method three times.
TEST_F(EndToEndAsyncTest,EchoThreeTimes)310 TEST_F(EndToEndAsyncTest, EchoThreeTimes) {
311 const char* kMessages[] = { "foo", "bar", "baz" };
312
313 for (size_t i = 0; i < arraysize(kMessages); ++i) {
314 // Create the method call.
315 MethodCall method_call("org.chromium.TestInterface", "Echo");
316 MessageWriter writer(&method_call);
317 writer.AppendString(kMessages[i]);
318
319 // Call the method.
320 const int timeout_ms = ObjectProxy::TIMEOUT_USE_DEFAULT;
321 CallMethod(&method_call, timeout_ms);
322 }
323
324 // Check the responses.
325 WaitForResponses(3);
326 // Sort as the order of the returned messages is not deterministic.
327 std::sort(response_strings_.begin(), response_strings_.end());
328 EXPECT_EQ("bar", response_strings_[0]);
329 EXPECT_EQ("baz", response_strings_[1]);
330 EXPECT_EQ("foo", response_strings_[2]);
331 }
332
TEST_F(EndToEndAsyncTest,Echo_HugePayload)333 TEST_F(EndToEndAsyncTest, Echo_HugePayload) {
334 const std::string kHugePayload(kHugePayloadSize, 'o');
335
336 // Create the method call with a huge payload.
337 MethodCall method_call("org.chromium.TestInterface", "Echo");
338 MessageWriter writer(&method_call);
339 writer.AppendString(kHugePayload);
340
341 // Call the method.
342 const int timeout_ms = ObjectProxy::TIMEOUT_USE_DEFAULT;
343 CallMethod(&method_call, timeout_ms);
344
345 // This caused a DCHECK failure before. Ensure that the issue is fixed.
346 WaitForResponses(1);
347 EXPECT_EQ(kHugePayload, response_strings_[0]);
348 }
349
TEST_F(EndToEndAsyncTest,BrokenBus)350 TEST_F(EndToEndAsyncTest, BrokenBus) {
351 const char* kHello = "hello";
352
353 // Set up a broken bus.
354 SetUpBrokenBus();
355
356 // Create the method call.
357 MethodCall method_call("org.chromium.TestInterface", "Echo");
358 MessageWriter writer(&method_call);
359 writer.AppendString(kHello);
360
361 // Call the method.
362 const int timeout_ms = ObjectProxy::TIMEOUT_USE_DEFAULT;
363 CallMethod(&method_call, timeout_ms);
364 WaitForResponses(1);
365
366 // Should fail because of the broken bus.
367 ASSERT_EQ("", response_strings_[0]);
368 }
369
TEST_F(EndToEndAsyncTest,BrokenBusWithErrorCallback)370 TEST_F(EndToEndAsyncTest, BrokenBusWithErrorCallback) {
371 const char* kHello = "hello";
372
373 // Set up a broken bus.
374 SetUpBrokenBus();
375
376 // Create the method call.
377 MethodCall method_call("org.chromium.TestInterface", "Echo");
378 MessageWriter writer(&method_call);
379 writer.AppendString(kHello);
380
381 // Call the method.
382 const int timeout_ms = ObjectProxy::TIMEOUT_USE_DEFAULT;
383 CallMethodWithErrorCallback(&method_call, timeout_ms);
384 WaitForErrors(1);
385
386 // Should fail because of the broken bus.
387 ASSERT_TRUE(response_strings_.empty());
388 ASSERT_EQ("", error_names_[0]);
389 }
390
TEST_F(EndToEndAsyncTest,Timeout)391 TEST_F(EndToEndAsyncTest, Timeout) {
392 const char* kHello = "hello";
393
394 // Create the method call.
395 MethodCall method_call("org.chromium.TestInterface", "SlowEcho");
396 MessageWriter writer(&method_call);
397 writer.AppendString(kHello);
398
399 // Call the method with timeout of 0ms.
400 const int timeout_ms = 0;
401 CallMethod(&method_call, timeout_ms);
402 WaitForResponses(1);
403
404 // Should fail because of timeout.
405 ASSERT_EQ("", response_strings_[0]);
406 }
407
TEST_F(EndToEndAsyncTest,TimeoutWithErrorCallback)408 TEST_F(EndToEndAsyncTest, TimeoutWithErrorCallback) {
409 const char* kHello = "hello";
410
411 // Create the method call.
412 MethodCall method_call("org.chromium.TestInterface", "SlowEcho");
413 MessageWriter writer(&method_call);
414 writer.AppendString(kHello);
415
416 // Call the method with timeout of 0ms.
417 const int timeout_ms = 0;
418 CallMethodWithErrorCallback(&method_call, timeout_ms);
419 WaitForErrors(1);
420
421 // Should fail because of timeout.
422 ASSERT_TRUE(response_strings_.empty());
423 ASSERT_EQ(DBUS_ERROR_NO_REPLY, error_names_[0]);
424 }
425
TEST_F(EndToEndAsyncTest,CancelPendingCalls)426 TEST_F(EndToEndAsyncTest, CancelPendingCalls) {
427 const char* kHello = "hello";
428
429 // Create the method call.
430 MethodCall method_call("org.chromium.TestInterface", "Echo");
431 MessageWriter writer(&method_call);
432 writer.AppendString(kHello);
433
434 // Call the method.
435 const int timeout_ms = ObjectProxy::TIMEOUT_USE_DEFAULT;
436 CallMethod(&method_call, timeout_ms);
437
438 // Remove the object proxy before receiving the result.
439 // This results in cancelling the pending method call.
440 bus_->RemoveObjectProxy(test_service_->service_name(),
441 ObjectPath("/org/chromium/TestObject"),
442 base::DoNothing());
443
444 // We shouldn't receive any responses. Wait for a while just to make sure.
445 run_loop_.reset(new base::RunLoop);
446 message_loop_.task_runner()->PostDelayedTask(
447 FROM_HERE, run_loop_->QuitClosure(), TestTimeouts::tiny_timeout());
448 run_loop_->Run();
449 EXPECT_TRUE(response_strings_.empty());
450 }
451
452 // Tests calling a method that sends its reply asynchronously.
TEST_F(EndToEndAsyncTest,AsyncEcho)453 TEST_F(EndToEndAsyncTest, AsyncEcho) {
454 const char* kHello = "hello";
455
456 // Create the method call.
457 MethodCall method_call("org.chromium.TestInterface", "AsyncEcho");
458 MessageWriter writer(&method_call);
459 writer.AppendString(kHello);
460
461 // Call the method.
462 const int timeout_ms = ObjectProxy::TIMEOUT_USE_DEFAULT;
463 CallMethod(&method_call, timeout_ms);
464
465 // Check the response.
466 WaitForResponses(1);
467 EXPECT_EQ(kHello, response_strings_[0]);
468 }
469
TEST_F(EndToEndAsyncTest,NonexistentMethod)470 TEST_F(EndToEndAsyncTest, NonexistentMethod) {
471 MethodCall method_call("org.chromium.TestInterface", "Nonexistent");
472
473 const int timeout_ms = ObjectProxy::TIMEOUT_USE_DEFAULT;
474 CallMethod(&method_call, timeout_ms);
475 WaitForResponses(1);
476
477 // Should fail because the method is nonexistent.
478 ASSERT_EQ("", response_strings_[0]);
479 }
480
TEST_F(EndToEndAsyncTest,NonexistentMethodWithErrorCallback)481 TEST_F(EndToEndAsyncTest, NonexistentMethodWithErrorCallback) {
482 MethodCall method_call("org.chromium.TestInterface", "Nonexistent");
483
484 const int timeout_ms = ObjectProxy::TIMEOUT_USE_DEFAULT;
485 CallMethodWithErrorCallback(&method_call, timeout_ms);
486 WaitForErrors(1);
487
488 // Should fail because the method is nonexistent.
489 ASSERT_TRUE(response_strings_.empty());
490 ASSERT_EQ(DBUS_ERROR_UNKNOWN_METHOD, error_names_[0]);
491 }
492
TEST_F(EndToEndAsyncTest,BrokenMethod)493 TEST_F(EndToEndAsyncTest, BrokenMethod) {
494 MethodCall method_call("org.chromium.TestInterface", "BrokenMethod");
495
496 const int timeout_ms = ObjectProxy::TIMEOUT_USE_DEFAULT;
497 CallMethod(&method_call, timeout_ms);
498 WaitForResponses(1);
499
500 // Should fail because the method is broken.
501 ASSERT_EQ("", response_strings_[0]);
502 }
503
TEST_F(EndToEndAsyncTest,BrokenMethodWithErrorCallback)504 TEST_F(EndToEndAsyncTest, BrokenMethodWithErrorCallback) {
505 MethodCall method_call("org.chromium.TestInterface", "BrokenMethod");
506
507 const int timeout_ms = ObjectProxy::TIMEOUT_USE_DEFAULT;
508 CallMethodWithErrorCallback(&method_call, timeout_ms);
509 WaitForErrors(1);
510
511 // Should fail because the method is broken.
512 ASSERT_TRUE(response_strings_.empty());
513 ASSERT_EQ(DBUS_ERROR_FAILED, error_names_[0]);
514 }
515
TEST_F(EndToEndAsyncTest,InvalidServiceName)516 TEST_F(EndToEndAsyncTest, InvalidServiceName) {
517 // Bus name cannot contain '/'.
518 const std::string invalid_service_name = ":1/2";
519
520 // Replace object proxy with new one.
521 object_proxy_ = bus_->GetObjectProxy(invalid_service_name,
522 ObjectPath("/org/chromium/TestObject"));
523
524 MethodCall method_call("org.chromium.TestInterface", "Echo");
525
526 const int timeout_ms = ObjectProxy::TIMEOUT_USE_DEFAULT;
527 CallMethodWithErrorCallback(&method_call, timeout_ms);
528 WaitForErrors(1);
529
530 // Should fail because of the invalid bus name.
531 ASSERT_TRUE(response_strings_.empty());
532 ASSERT_EQ("", error_names_[0]);
533 }
534
TEST_F(EndToEndAsyncTest,EmptyResponseCallback)535 TEST_F(EndToEndAsyncTest, EmptyResponseCallback) {
536 const char* kHello = "hello";
537
538 // Create the method call.
539 MethodCall method_call("org.chromium.TestInterface", "Echo");
540 MessageWriter writer(&method_call);
541 writer.AppendString(kHello);
542
543 // Call the method with an empty callback.
544 const int timeout_ms = ObjectProxy::TIMEOUT_USE_DEFAULT;
545 object_proxy_->CallMethod(&method_call, timeout_ms, base::DoNothing());
546 // Post a delayed task to quit the message loop.
547 run_loop_.reset(new base::RunLoop);
548 message_loop_.task_runner()->PostDelayedTask(
549 FROM_HERE, run_loop_->QuitClosure(), TestTimeouts::tiny_timeout());
550 run_loop_->Run();
551 // We cannot tell if the empty callback is called, but at least we can
552 // check if the test does not crash.
553 }
554
TEST_F(EndToEndAsyncTest,TestSignal)555 TEST_F(EndToEndAsyncTest, TestSignal) {
556 const char kMessage[] = "hello, world";
557 // Send the test signal from the exported object.
558 test_service_->SendTestSignal(kMessage);
559 // Receive the signal with the object proxy. The signal is handled in
560 // EndToEndAsyncTest::OnTestSignal() in the main thread.
561 WaitForTestSignal();
562 ASSERT_EQ(kMessage, test_signal_string_);
563 }
564
TEST_F(EndToEndAsyncTest,TestSignalFromRoot)565 TEST_F(EndToEndAsyncTest, TestSignalFromRoot) {
566 const char kMessage[] = "hello, world";
567 // Object proxies are tied to a particular object path, if a signal
568 // arrives from a different object path like "/" the first object proxy
569 // |object_proxy_| should not handle it, and should leave it for the root
570 // object proxy |root_object_proxy_|.
571 test_service_->SendTestSignalFromRoot(kMessage);
572 WaitForTestSignal();
573 // Verify the signal was not received by the specific proxy.
574 ASSERT_TRUE(test_signal_string_.empty());
575 // Verify the string WAS received by the root proxy.
576 ASSERT_EQ(kMessage, root_test_signal_string_);
577 }
578
TEST_F(EndToEndAsyncTest,TestHugeSignal)579 TEST_F(EndToEndAsyncTest, TestHugeSignal) {
580 const std::string kHugeMessage(kHugePayloadSize, 'o');
581
582 // Send the huge signal from the exported object.
583 test_service_->SendTestSignal(kHugeMessage);
584 // This caused a DCHECK failure before. Ensure that the issue is fixed.
585 WaitForTestSignal();
586 ASSERT_EQ(kHugeMessage, test_signal_string_);
587 }
588
589 class SignalMultipleHandlerTest : public EndToEndAsyncTest {
590 public:
591 SignalMultipleHandlerTest() = default;
592
SetUp()593 void SetUp() override {
594 // Set up base class.
595 EndToEndAsyncTest::SetUp();
596
597 // Connect the root object proxy's signal handler to a new handler
598 // so that we can verify that a second call to ConnectSignal() delivers
599 // to both our new handler and the old.
600 object_proxy_->ConnectToSignal(
601 "org.chromium.TestInterface",
602 "Test",
603 base::Bind(&SignalMultipleHandlerTest::OnAdditionalTestSignal,
604 base::Unretained(this)),
605 base::Bind(&SignalMultipleHandlerTest::OnAdditionalConnected,
606 base::Unretained(this)));
607 // Wait until the object proxy is connected to the signal.
608 run_loop_.reset(new base::RunLoop);
609 run_loop_->Run();
610 }
611
612 protected:
613 // Called when the "Test" signal is received, in the main thread.
614 // Copy the string payload to |additional_test_signal_string_|.
OnAdditionalTestSignal(Signal * signal)615 void OnAdditionalTestSignal(Signal* signal) {
616 MessageReader reader(signal);
617 ASSERT_TRUE(reader.PopString(&additional_test_signal_string_));
618 run_loop_->Quit();
619 }
620
621 // Called when connected to the signal.
OnAdditionalConnected(const std::string & interface_name,const std::string & signal_name,bool success)622 void OnAdditionalConnected(const std::string& interface_name,
623 const std::string& signal_name,
624 bool success) {
625 ASSERT_TRUE(success);
626 run_loop_->Quit();
627 }
628
629 // Text message from "Test" signal delivered to additional handler.
630 std::string additional_test_signal_string_;
631 };
632
TEST_F(SignalMultipleHandlerTest,TestMultipleHandlers)633 TEST_F(SignalMultipleHandlerTest, TestMultipleHandlers) {
634 const char kMessage[] = "hello, world";
635 // Send the test signal from the exported object.
636 test_service_->SendTestSignal(kMessage);
637 // Receive the signal with the object proxy.
638 WaitForTestSignal();
639 // Verify the string WAS received by the original handler.
640 ASSERT_EQ(kMessage, test_signal_string_);
641 // Verify the signal WAS ALSO received by the additional handler.
642 ASSERT_EQ(kMessage, additional_test_signal_string_);
643 }
644
645 } // namespace dbus
646