blob: 150ed29e902de15cecbc084c788c5f2f44ae8b55 [file] [log] [blame]
[email protected]a51076112011-08-17 20:58:121// 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.
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.h"
12#include "base/stl_util.h"
[email protected]65e8e252011-11-11 08:36:2213#include "base/test/test_timeouts.h"
[email protected]a51076112011-08-17 20:58:1214#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_proxy.h"
19#include "dbus/test_service.h"
20#include "testing/gtest/include/gtest/gtest.h"
21
[email protected]829f0e4c2011-08-31 18:02:4322// The end-to-end test exercises the asynchronous APIs in ObjectProxy and
[email protected]a51076112011-08-17 20:58:1223// ExportedObject.
24class EndToEndAsyncTest : public testing::Test {
25 public:
26 EndToEndAsyncTest() {
27 }
28
[email protected]ea78b1e2011-08-27 07:26:3429 virtual void SetUp() {
[email protected]a51076112011-08-17 20:58:1230 // Make the main thread not to allow IO.
31 base::ThreadRestrictions::SetIOAllowed(false);
32
[email protected]a51076112011-08-17 20:58:1233 // Start the D-Bus thread.
34 dbus_thread_.reset(new base::Thread("D-Bus Thread"));
35 base::Thread::Options thread_options;
36 thread_options.message_loop_type = MessageLoop::TYPE_IO;
[email protected]12f97662011-08-20 01:07:1737 ASSERT_TRUE(dbus_thread_->StartWithOptions(thread_options));
[email protected]a51076112011-08-17 20:58:1238
[email protected]12f97662011-08-20 01:07:1739 // Start the test service, using the D-Bus thread.
40 dbus::TestService::Options options;
[email protected]56d82c9c2011-09-06 20:03:2441 options.dbus_thread_message_loop_proxy = dbus_thread_->message_loop_proxy();
[email protected]12f97662011-08-20 01:07:1742 test_service_.reset(new dbus::TestService(options));
43 ASSERT_TRUE(test_service_->StartService());
44 ASSERT_TRUE(test_service_->WaitUntilServiceIsStarted());
45 ASSERT_TRUE(test_service_->HasDBusThread());
46
47 // Create the client, using the D-Bus thread.
[email protected]a51076112011-08-17 20:58:1248 dbus::Bus::Options bus_options;
49 bus_options.bus_type = dbus::Bus::SESSION;
50 bus_options.connection_type = dbus::Bus::PRIVATE;
[email protected]56d82c9c2011-09-06 20:03:2451 bus_options.dbus_thread_message_loop_proxy =
52 dbus_thread_->message_loop_proxy();
[email protected]a51076112011-08-17 20:58:1253 bus_ = new dbus::Bus(bus_options);
54 object_proxy_ = bus_->GetObjectProxy("org.chromium.TestService",
55 "/org/chromium/TestObject");
[email protected]12f97662011-08-20 01:07:1756 ASSERT_TRUE(bus_->HasDBusThread());
[email protected]3beaaa4e2011-08-23 07:29:2157
[email protected]0ad9ef82011-11-23 22:08:3858 // Connect to the "Test" signal of "org.chromium.TestInterface" from
59 // the remote object.
[email protected]3beaaa4e2011-08-23 07:29:2160 object_proxy_->ConnectToSignal(
61 "org.chromium.TestInterface",
62 "Test",
63 base::Bind(&EndToEndAsyncTest::OnTestSignal,
64 base::Unretained(this)),
65 base::Bind(&EndToEndAsyncTest::OnConnected,
66 base::Unretained(this)));
[email protected]4c985c62011-12-13 17:08:4267 // Wait until the object proxy is connected to the signal.
68 message_loop_.Run();
69
[email protected]0ad9ef82011-11-23 22:08:3870 // Connect to the "Test2" signal of "org.chromium.TestInterface" from
71 // the remote object. There was a bug where we were emitting error
72 // messages like "Requested to remove an unknown match rule: ..." at
73 // the shutdown of Bus when an object proxy is connected to more than
74 // one signal of the same interface. See crosbug.com/23382 for details.
75 object_proxy_->ConnectToSignal(
76 "org.chromium.TestInterface",
77 "Test2",
78 base::Bind(&EndToEndAsyncTest::OnTest2Signal,
79 base::Unretained(this)),
80 base::Bind(&EndToEndAsyncTest::OnConnected,
81 base::Unretained(this)));
[email protected]3beaaa4e2011-08-23 07:29:2182 // Wait until the object proxy is connected to the signal.
83 message_loop_.Run();
[email protected]a51076112011-08-17 20:58:1284 }
85
[email protected]ea78b1e2011-08-27 07:26:3486 virtual void TearDown() {
[email protected]e20d39fe2011-09-02 06:56:2387 bus_->ShutdownOnDBusThreadAndBlock();
[email protected]a51076112011-08-17 20:58:1288
[email protected]12f97662011-08-20 01:07:1789 // Shut down the service.
[email protected]e20d39fe2011-09-02 06:56:2390 test_service_->ShutdownAndBlock();
[email protected]12f97662011-08-20 01:07:1791
[email protected]a51076112011-08-17 20:58:1292 // Reset to the default.
93 base::ThreadRestrictions::SetIOAllowed(true);
94
[email protected]829f0e4c2011-08-31 18:02:4395 // Stopping a thread is considered an IO operation, so do this after
[email protected]a51076112011-08-17 20:58:1296 // allowing IO.
97 test_service_->Stop();
98 }
99
100 protected:
[email protected]829f0e4c2011-08-31 18:02:43101 // Calls the method asynchronously. OnResponse() will be called once the
[email protected]a51076112011-08-17 20:58:12102 // response is received.
103 void CallMethod(dbus::MethodCall* method_call,
104 int timeout_ms) {
105 object_proxy_->CallMethod(method_call,
106 timeout_ms,
107 base::Bind(&EndToEndAsyncTest::OnResponse,
108 base::Unretained(this)));
109 }
110
111 // Wait for the give number of responses.
112 void WaitForResponses(size_t num_responses) {
113 while (response_strings_.size() < num_responses) {
114 message_loop_.Run();
115 }
116 }
117
118 // Called when the response is received.
119 void OnResponse(dbus::Response* response) {
120 // |response| will be deleted on exit of the function. Copy the
121 // payload to |response_strings_|.
122 if (response) {
123 dbus::MessageReader reader(response);
124 std::string response_string;
125 ASSERT_TRUE(reader.PopString(&response_string));
126 response_strings_.push_back(response_string);
127 } else {
128 response_strings_.push_back("");
129 }
130 message_loop_.Quit();
131 };
132
[email protected]3beaaa4e2011-08-23 07:29:21133 // Called when the "Test" signal is received, in the main thread.
134 // Copy the string payload to |test_signal_string_|.
135 void OnTestSignal(dbus::Signal* signal) {
136 dbus::MessageReader reader(signal);
137 ASSERT_TRUE(reader.PopString(&test_signal_string_));
138 message_loop_.Quit();
139 }
140
[email protected]0ad9ef82011-11-23 22:08:38141 // Called when the "Test2" signal is received, in the main thread.
142 void OnTest2Signal(dbus::Signal* signal) {
143 dbus::MessageReader reader(signal);
144 message_loop_.Quit();
145 }
146
[email protected]3beaaa4e2011-08-23 07:29:21147 // Called when connected to the signal.
148 void OnConnected(const std::string& interface_name,
149 const std::string& signal_name,
150 bool success) {
151 ASSERT_TRUE(success);
152 message_loop_.Quit();
153 }
154
155 // Wait for the hey signal to be received.
156 void WaitForTestSignal() {
157 // OnTestSignal() will quit the message loop.
158 message_loop_.Run();
159 }
160
[email protected]a51076112011-08-17 20:58:12161 MessageLoop message_loop_;
162 std::vector<std::string> response_strings_;
163 scoped_ptr<base::Thread> dbus_thread_;
164 scoped_refptr<dbus::Bus> bus_;
165 dbus::ObjectProxy* object_proxy_;
166 scoped_ptr<dbus::TestService> test_service_;
[email protected]3beaaa4e2011-08-23 07:29:21167 // Text message from "Test" signal.
168 std::string test_signal_string_;
[email protected]a51076112011-08-17 20:58:12169};
170
171TEST_F(EndToEndAsyncTest, Echo) {
172 const char* kHello = "hello";
173
174 // Create the method call.
175 dbus::MethodCall method_call("org.chromium.TestInterface", "Echo");
176 dbus::MessageWriter writer(&method_call);
177 writer.AppendString(kHello);
178
179 // Call the method.
180 const int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT;
181 CallMethod(&method_call, timeout_ms);
182
183 // Check the response.
184 WaitForResponses(1);
185 EXPECT_EQ(kHello, response_strings_[0]);
186}
187
188// Call Echo method three times.
189TEST_F(EndToEndAsyncTest, EchoThreeTimes) {
190 const char* kMessages[] = { "foo", "bar", "baz" };
191
192 for (size_t i = 0; i < arraysize(kMessages); ++i) {
193 // Create the method call.
194 dbus::MethodCall method_call("org.chromium.TestInterface", "Echo");
195 dbus::MessageWriter writer(&method_call);
196 writer.AppendString(kMessages[i]);
197
198 // Call the method.
199 const int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT;
200 CallMethod(&method_call, timeout_ms);
201 }
202
203 // Check the responses.
204 WaitForResponses(3);
205 // Sort as the order of the returned messages is not deterministic.
206 std::sort(response_strings_.begin(), response_strings_.end());
207 EXPECT_EQ("bar", response_strings_[0]);
208 EXPECT_EQ("baz", response_strings_[1]);
209 EXPECT_EQ("foo", response_strings_[2]);
210}
211
212TEST_F(EndToEndAsyncTest, Timeout) {
213 const char* kHello = "hello";
214
215 // Create the method call.
216 dbus::MethodCall method_call("org.chromium.TestInterface", "SlowEcho");
217 dbus::MessageWriter writer(&method_call);
218 writer.AppendString(kHello);
219
[email protected]12f97662011-08-20 01:07:17220 // Call the method with timeout of 0ms.
221 const int timeout_ms = 0;
[email protected]a51076112011-08-17 20:58:12222 CallMethod(&method_call, timeout_ms);
223 WaitForResponses(1);
224
225 // Should fail because of timeout.
226 ASSERT_EQ("", response_strings_[0]);
227}
228
[email protected]9aa74cc2011-11-30 04:57:42229// Tests calling a method that sends its reply asynchronously.
230TEST_F(EndToEndAsyncTest, AsyncEcho) {
231 const char* kHello = "hello";
232
233 // Create the method call.
234 dbus::MethodCall method_call("org.chromium.TestInterface", "AsyncEcho");
235 dbus::MessageWriter writer(&method_call);
236 writer.AppendString(kHello);
237
238 // Call the method.
239 const int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT;
240 CallMethod(&method_call, timeout_ms);
241
242 // Check the response.
243 WaitForResponses(1);
244 EXPECT_EQ(kHello, response_strings_[0]);
245}
246
[email protected]a51076112011-08-17 20:58:12247TEST_F(EndToEndAsyncTest, NonexistentMethod) {
248 dbus::MethodCall method_call("org.chromium.TestInterface", "Nonexistent");
249
250 const int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT;
251 CallMethod(&method_call, timeout_ms);
252 WaitForResponses(1);
253
254 // Should fail because the method is nonexistent.
255 ASSERT_EQ("", response_strings_[0]);
256}
257
258TEST_F(EndToEndAsyncTest, BrokenMethod) {
259 dbus::MethodCall method_call("org.chromium.TestInterface", "BrokenMethod");
260
261 const int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT;
262 CallMethod(&method_call, timeout_ms);
263 WaitForResponses(1);
264
265 // Should fail because the method is broken.
266 ASSERT_EQ("", response_strings_[0]);
267}
[email protected]3beaaa4e2011-08-23 07:29:21268
[email protected]65e8e252011-11-11 08:36:22269TEST_F(EndToEndAsyncTest, EmptyResponseCallback) {
270 const char* kHello = "hello";
271
272 // Create the method call.
273 dbus::MethodCall method_call("org.chromium.TestInterface", "Echo");
274 dbus::MessageWriter writer(&method_call);
275 writer.AppendString(kHello);
276
277 // Call the method with an empty callback.
278 const int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT;
279 object_proxy_->CallMethod(&method_call,
280 timeout_ms,
281 dbus::ObjectProxy::EmptyResponseCallback());
282 // Post a delayed task to quit the message loop.
283 message_loop_.PostDelayedTask(FROM_HERE,
284 MessageLoop::QuitClosure(),
285 TestTimeouts::tiny_timeout_ms());
286 message_loop_.Run();
287 // We cannot tell if the empty callback is called, but at least we can
288 // check if the test does not crash.
289}
290
[email protected]4c985c62011-12-13 17:08:42291TEST_F(EndToEndAsyncTest, TestSignal) {
[email protected]3beaaa4e2011-08-23 07:29:21292 const char kMessage[] = "hello, world";
293 // Send the test signal from the exported object.
294 test_service_->SendTestSignal(kMessage);
[email protected]829f0e4c2011-08-31 18:02:43295 // Receive the signal with the object proxy. The signal is handled in
[email protected]3beaaa4e2011-08-23 07:29:21296 // EndToEndAsyncTest::OnTestSignal() in the main thread.
297 WaitForTestSignal();
298 ASSERT_EQ(kMessage, test_signal_string_);
299}
[email protected]df159b22011-09-14 22:10:24300
[email protected]4c985c62011-12-13 17:08:42301TEST_F(EndToEndAsyncTest, TestSignalFromRoot) {
[email protected]df159b22011-09-14 22:10:24302 const char kMessage[] = "hello, world";
303 // Send the test signal from the root object path, to see if we can
304 // handle signals sent from "/", like dbus-send does.
305 test_service_->SendTestSignalFromRoot(kMessage);
306 // Receive the signal with the object proxy. The signal is handled in
307 // EndToEndAsyncTest::OnTestSignal() in the main thread.
308 WaitForTestSignal();
309 ASSERT_EQ(kMessage, test_signal_string_);
310}