1 // Copyright (c) 2011 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.
10 #include "base/memory/scoped_ptr.h"
11 #include "base/message_loop.h"
12 #include "base/stl_util.h"
13 #include "base/threading/thread.h"
14 #include "base/threading/thread_restrictions.h"
16 #include "dbus/message.h"
17 #include "dbus/object_proxy.h"
18 #include "dbus/test_service.h"
19 #include "testing/gtest/include/gtest/gtest.h"
21 // The end-to-end test exercises the asynchronous APIs in ObjectProxy and
23 class EndToEndAsyncTest
: public testing::Test
{
28 virtual void SetUp() {
29 // Make the main thread not to allow IO.
30 base::ThreadRestrictions::SetIOAllowed(false);
32 // Start the D-Bus thread.
33 dbus_thread_
.reset(new base::Thread("D-Bus Thread"));
34 base::Thread::Options thread_options
;
35 thread_options
.message_loop_type
= MessageLoop::TYPE_IO
;
36 ASSERT_TRUE(dbus_thread_
->StartWithOptions(thread_options
));
38 // Start the test service, using the D-Bus thread.
39 dbus::TestService::Options options
;
40 options
.dbus_thread_message_loop_proxy
= dbus_thread_
->message_loop_proxy();
41 test_service_
.reset(new dbus::TestService(options
));
42 ASSERT_TRUE(test_service_
->StartService());
43 ASSERT_TRUE(test_service_
->WaitUntilServiceIsStarted());
44 ASSERT_TRUE(test_service_
->HasDBusThread());
46 // Create the client, using the D-Bus thread.
47 dbus::Bus::Options bus_options
;
48 bus_options
.bus_type
= dbus::Bus::SESSION
;
49 bus_options
.connection_type
= dbus::Bus::PRIVATE
;
50 bus_options
.dbus_thread_message_loop_proxy
=
51 dbus_thread_
->message_loop_proxy();
52 bus_
= new dbus::Bus(bus_options
);
53 object_proxy_
= bus_
->GetObjectProxy("org.chromium.TestService",
54 "/org/chromium/TestObject");
55 ASSERT_TRUE(bus_
->HasDBusThread());
57 // Connect to the "Test" signal from the remote object.
58 object_proxy_
->ConnectToSignal(
59 "org.chromium.TestInterface",
61 base::Bind(&EndToEndAsyncTest::OnTestSignal
,
62 base::Unretained(this)),
63 base::Bind(&EndToEndAsyncTest::OnConnected
,
64 base::Unretained(this)));
65 // Wait until the object proxy is connected to the signal.
69 virtual void TearDown() {
70 bus_
->ShutdownOnDBusThreadAndBlock();
72 // Shut down the service.
73 test_service_
->ShutdownAndBlock();
75 // Reset to the default.
76 base::ThreadRestrictions::SetIOAllowed(true);
78 // Stopping a thread is considered an IO operation, so do this after
80 test_service_
->Stop();
84 // Calls the method asynchronously. OnResponse() will be called once the
85 // response is received.
86 void CallMethod(dbus::MethodCall
* method_call
,
88 object_proxy_
->CallMethod(method_call
,
90 base::Bind(&EndToEndAsyncTest::OnResponse
,
91 base::Unretained(this)));
94 // Wait for the give number of responses.
95 void WaitForResponses(size_t num_responses
) {
96 while (response_strings_
.size() < num_responses
) {
101 // Called when the response is received.
102 void OnResponse(dbus::Response
* response
) {
103 // |response| will be deleted on exit of the function. Copy the
104 // payload to |response_strings_|.
106 dbus::MessageReader
reader(response
);
107 std::string response_string
;
108 ASSERT_TRUE(reader
.PopString(&response_string
));
109 response_strings_
.push_back(response_string
);
111 response_strings_
.push_back("");
113 message_loop_
.Quit();
116 // Called when the "Test" signal is received, in the main thread.
117 // Copy the string payload to |test_signal_string_|.
118 void OnTestSignal(dbus::Signal
* signal
) {
119 dbus::MessageReader
reader(signal
);
120 ASSERT_TRUE(reader
.PopString(&test_signal_string_
));
121 message_loop_
.Quit();
124 // Called when connected to the signal.
125 void OnConnected(const std::string
& interface_name
,
126 const std::string
& signal_name
,
128 ASSERT_TRUE(success
);
129 message_loop_
.Quit();
132 // Wait for the hey signal to be received.
133 void WaitForTestSignal() {
134 // OnTestSignal() will quit the message loop.
138 MessageLoop message_loop_
;
139 std::vector
<std::string
> response_strings_
;
140 scoped_ptr
<base::Thread
> dbus_thread_
;
141 scoped_refptr
<dbus::Bus
> bus_
;
142 dbus::ObjectProxy
* object_proxy_
;
143 scoped_ptr
<dbus::TestService
> test_service_
;
144 // Text message from "Test" signal.
145 std::string test_signal_string_
;
148 TEST_F(EndToEndAsyncTest
, Echo
) {
149 const char* kHello
= "hello";
151 // Create the method call.
152 dbus::MethodCall
method_call("org.chromium.TestInterface", "Echo");
153 dbus::MessageWriter
writer(&method_call
);
154 writer
.AppendString(kHello
);
157 const int timeout_ms
= dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
;
158 CallMethod(&method_call
, timeout_ms
);
160 // Check the response.
162 EXPECT_EQ(kHello
, response_strings_
[0]);
165 // Call Echo method three times.
166 TEST_F(EndToEndAsyncTest
, EchoThreeTimes
) {
167 const char* kMessages
[] = { "foo", "bar", "baz" };
169 for (size_t i
= 0; i
< arraysize(kMessages
); ++i
) {
170 // Create the method call.
171 dbus::MethodCall
method_call("org.chromium.TestInterface", "Echo");
172 dbus::MessageWriter
writer(&method_call
);
173 writer
.AppendString(kMessages
[i
]);
176 const int timeout_ms
= dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
;
177 CallMethod(&method_call
, timeout_ms
);
180 // Check the responses.
182 // Sort as the order of the returned messages is not deterministic.
183 std::sort(response_strings_
.begin(), response_strings_
.end());
184 EXPECT_EQ("bar", response_strings_
[0]);
185 EXPECT_EQ("baz", response_strings_
[1]);
186 EXPECT_EQ("foo", response_strings_
[2]);
189 TEST_F(EndToEndAsyncTest
, Timeout
) {
190 const char* kHello
= "hello";
192 // Create the method call.
193 dbus::MethodCall
method_call("org.chromium.TestInterface", "SlowEcho");
194 dbus::MessageWriter
writer(&method_call
);
195 writer
.AppendString(kHello
);
197 // Call the method with timeout of 0ms.
198 const int timeout_ms
= 0;
199 CallMethod(&method_call
, timeout_ms
);
202 // Should fail because of timeout.
203 ASSERT_EQ("", response_strings_
[0]);
206 TEST_F(EndToEndAsyncTest
, NonexistentMethod
) {
207 dbus::MethodCall
method_call("org.chromium.TestInterface", "Nonexistent");
209 const int timeout_ms
= dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
;
210 CallMethod(&method_call
, timeout_ms
);
213 // Should fail because the method is nonexistent.
214 ASSERT_EQ("", response_strings_
[0]);
217 TEST_F(EndToEndAsyncTest
, BrokenMethod
) {
218 dbus::MethodCall
method_call("org.chromium.TestInterface", "BrokenMethod");
220 const int timeout_ms
= dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
;
221 CallMethod(&method_call
, timeout_ms
);
224 // Should fail because the method is broken.
225 ASSERT_EQ("", response_strings_
[0]);
228 TEST_F(EndToEndAsyncTest
, TestSignal
) {
229 const char kMessage
[] = "hello, world";
230 // Send the test signal from the exported object.
231 test_service_
->SendTestSignal(kMessage
);
232 // Receive the signal with the object proxy. The signal is handled in
233 // EndToEndAsyncTest::OnTestSignal() in the main thread.
235 ASSERT_EQ(kMessage
, test_signal_string_
);
238 TEST_F(EndToEndAsyncTest
, TestSignalFromRoot
) {
239 const char kMessage
[] = "hello, world";
240 // Send the test signal from the root object path, to see if we can
241 // handle signals sent from "/", like dbus-send does.
242 test_service_
->SendTestSignalFromRoot(kMessage
);
243 // Receive the signal with the object proxy. The signal is handled in
244 // EndToEndAsyncTest::OnTestSignal() in the main thread.
246 ASSERT_EQ(kMessage
, test_signal_string_
);