xref: /aosp_15_r20/external/libchrome/dbus/end_to_end_async_unittest.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
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