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