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