1 // Copyright 2015 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 "mojo/public/cpp/bindings/lib/multiplex_router.h"
6
7 #include <utility>
8
9 #include "base/bind.h"
10 #include "base/memory/ptr_util.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/run_loop.h"
14 #include "base/threading/thread_task_runner_handle.h"
15 #include "mojo/public/cpp/bindings/interface_endpoint_client.h"
16 #include "mojo/public/cpp/bindings/message.h"
17 #include "mojo/public/cpp/bindings/message_filter.h"
18 #include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
19 #include "mojo/public/cpp/bindings/tests/message_queue.h"
20 #include "mojo/public/cpp/bindings/tests/router_test_util.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22
23 namespace mojo {
24 namespace test {
25 namespace {
26
27 using mojo::internal::MultiplexRouter;
28
29 class MultiplexRouterTest : public testing::Test {
30 public:
MultiplexRouterTest()31 MultiplexRouterTest() {}
32
SetUp()33 void SetUp() override {
34 MessagePipe pipe;
35 router0_ = new MultiplexRouter(true, std::move(pipe.handle0),
36 base::ThreadTaskRunnerHandle::Get());
37 router1_ = new MultiplexRouter(true, std::move(pipe.handle1),
38 base::ThreadTaskRunnerHandle::Get());
39 router0_->CreateEndpointHandlePair(&endpoint0_, &endpoint1_);
40 endpoint1_ =
41 EmulatePassingEndpointHandle(std::move(endpoint1_), router1_.get());
42 }
43
TearDown()44 void TearDown() override {}
45
PumpMessages()46 void PumpMessages() { base::RunLoop().RunUntilIdle(); }
47
EmulatePassingEndpointHandle(ScopedInterfaceEndpointHandle handle,MultiplexRouter * target)48 ScopedInterfaceEndpointHandle EmulatePassingEndpointHandle(
49 ScopedInterfaceEndpointHandle handle,
50 MultiplexRouter* target) {
51 CHECK(!handle.is_local());
52
53 return target->CreateLocalEndpointHandle(handle.release());
54 }
55
56 protected:
57 scoped_refptr<MultiplexRouter> router0_;
58 scoped_refptr<MultiplexRouter> router1_;
59 ScopedInterfaceEndpointHandle endpoint0_;
60 ScopedInterfaceEndpointHandle endpoint1_;
61
62 private:
63 base::MessageLoop loop_;
64 };
65
TEST_F(MultiplexRouterTest,BasicRequestResponse)66 TEST_F(MultiplexRouterTest, BasicRequestResponse) {
67 InterfaceEndpointClient client0(std::move(endpoint0_), nullptr,
68 base::WrapUnique(new PassThroughFilter()),
69 false, base::ThreadTaskRunnerHandle::Get());
70 ResponseGenerator generator;
71 InterfaceEndpointClient client1(std::move(endpoint1_), &generator,
72 base::WrapUnique(new PassThroughFilter()),
73 false, base::ThreadTaskRunnerHandle::Get());
74
75 Message request;
76 AllocRequestMessage(1, "hello", &request);
77
78 MessageQueue message_queue;
79 base::RunLoop run_loop;
80 client0.AcceptWithResponder(
81 &request,
82 new MessageAccumulator(&message_queue, run_loop.QuitClosure()));
83
84 run_loop.Run();
85
86 EXPECT_FALSE(message_queue.IsEmpty());
87
88 Message response;
89 message_queue.Pop(&response);
90
91 EXPECT_EQ(std::string("hello world!"),
92 std::string(reinterpret_cast<const char*>(response.payload())));
93
94 // Send a second message on the pipe.
95 Message request2;
96 AllocRequestMessage(1, "hello again", &request2);
97
98 base::RunLoop run_loop2;
99 client0.AcceptWithResponder(
100 &request2,
101 new MessageAccumulator(&message_queue, run_loop2.QuitClosure()));
102
103 run_loop2.Run();
104
105 EXPECT_FALSE(message_queue.IsEmpty());
106
107 message_queue.Pop(&response);
108
109 EXPECT_EQ(std::string("hello again world!"),
110 std::string(reinterpret_cast<const char*>(response.payload())));
111 }
112
TEST_F(MultiplexRouterTest,BasicRequestResponse_Synchronous)113 TEST_F(MultiplexRouterTest, BasicRequestResponse_Synchronous) {
114 InterfaceEndpointClient client0(std::move(endpoint0_), nullptr,
115 base::WrapUnique(new PassThroughFilter()),
116 false, base::ThreadTaskRunnerHandle::Get());
117 ResponseGenerator generator;
118 InterfaceEndpointClient client1(std::move(endpoint1_), &generator,
119 base::WrapUnique(new PassThroughFilter()),
120 false, base::ThreadTaskRunnerHandle::Get());
121
122 Message request;
123 AllocRequestMessage(1, "hello", &request);
124
125 MessageQueue message_queue;
126 client0.AcceptWithResponder(&request, new MessageAccumulator(&message_queue));
127
128 router1_->WaitForIncomingMessage(MOJO_DEADLINE_INDEFINITE);
129 router0_->WaitForIncomingMessage(MOJO_DEADLINE_INDEFINITE);
130
131 EXPECT_FALSE(message_queue.IsEmpty());
132
133 Message response;
134 message_queue.Pop(&response);
135
136 EXPECT_EQ(std::string("hello world!"),
137 std::string(reinterpret_cast<const char*>(response.payload())));
138
139 // Send a second message on the pipe.
140 Message request2;
141 AllocRequestMessage(1, "hello again", &request2);
142
143 client0.AcceptWithResponder(&request2,
144 new MessageAccumulator(&message_queue));
145
146 router1_->WaitForIncomingMessage(MOJO_DEADLINE_INDEFINITE);
147 router0_->WaitForIncomingMessage(MOJO_DEADLINE_INDEFINITE);
148
149 EXPECT_FALSE(message_queue.IsEmpty());
150
151 message_queue.Pop(&response);
152
153 EXPECT_EQ(std::string("hello again world!"),
154 std::string(reinterpret_cast<const char*>(response.payload())));
155 }
156
TEST_F(MultiplexRouterTest,RequestWithNoReceiver)157 TEST_F(MultiplexRouterTest, RequestWithNoReceiver) {
158 InterfaceEndpointClient client0(std::move(endpoint0_), nullptr,
159 base::WrapUnique(new PassThroughFilter()),
160 false, base::ThreadTaskRunnerHandle::Get());
161 InterfaceEndpointClient client1(std::move(endpoint1_), nullptr,
162 base::WrapUnique(new PassThroughFilter()),
163 false, base::ThreadTaskRunnerHandle::Get());
164
165 // Without an incoming receiver set on client1, we expect client0 to observe
166 // an error as a result of sending a message.
167
168 Message request;
169 AllocRequestMessage(1, "hello", &request);
170
171 MessageQueue message_queue;
172 base::RunLoop run_loop, run_loop2;
173 client0.set_connection_error_handler(run_loop.QuitClosure());
174 client1.set_connection_error_handler(run_loop2.QuitClosure());
175 client0.AcceptWithResponder(
176 &request, new MessageAccumulator(&message_queue, run_loop.QuitClosure()));
177
178 run_loop.Run();
179 run_loop2.Run();
180
181 EXPECT_TRUE(client0.encountered_error());
182 EXPECT_TRUE(client1.encountered_error());
183 EXPECT_TRUE(message_queue.IsEmpty());
184 }
185
186 // Tests MultiplexRouter using the LazyResponseGenerator. The responses will not
187 // be sent until after the requests have been accepted.
TEST_F(MultiplexRouterTest,LazyResponses)188 TEST_F(MultiplexRouterTest, LazyResponses) {
189 InterfaceEndpointClient client0(std::move(endpoint0_), nullptr,
190 base::WrapUnique(new PassThroughFilter()),
191 false, base::ThreadTaskRunnerHandle::Get());
192 base::RunLoop run_loop;
193 LazyResponseGenerator generator(run_loop.QuitClosure());
194 InterfaceEndpointClient client1(std::move(endpoint1_), &generator,
195 base::WrapUnique(new PassThroughFilter()),
196 false, base::ThreadTaskRunnerHandle::Get());
197
198 Message request;
199 AllocRequestMessage(1, "hello", &request);
200
201 MessageQueue message_queue;
202 base::RunLoop run_loop2;
203 client0.AcceptWithResponder(
204 &request,
205 new MessageAccumulator(&message_queue, run_loop2.QuitClosure()));
206 run_loop.Run();
207
208 // The request has been received but the response has not been sent yet.
209 EXPECT_TRUE(message_queue.IsEmpty());
210
211 // Send the response.
212 EXPECT_TRUE(generator.responder_is_valid());
213 generator.CompleteWithResponse();
214 run_loop2.Run();
215
216 // Check the response.
217 EXPECT_FALSE(message_queue.IsEmpty());
218 Message response;
219 message_queue.Pop(&response);
220 EXPECT_EQ(std::string("hello world!"),
221 std::string(reinterpret_cast<const char*>(response.payload())));
222
223 // Send a second message on the pipe.
224 base::RunLoop run_loop3;
225 generator.set_closure(run_loop3.QuitClosure());
226 Message request2;
227 AllocRequestMessage(1, "hello again", &request2);
228
229 base::RunLoop run_loop4;
230 client0.AcceptWithResponder(
231 &request2,
232 new MessageAccumulator(&message_queue, run_loop4.QuitClosure()));
233 run_loop3.Run();
234
235 // The request has been received but the response has not been sent yet.
236 EXPECT_TRUE(message_queue.IsEmpty());
237
238 // Send the second response.
239 EXPECT_TRUE(generator.responder_is_valid());
240 generator.CompleteWithResponse();
241 run_loop4.Run();
242
243 // Check the second response.
244 EXPECT_FALSE(message_queue.IsEmpty());
245 message_queue.Pop(&response);
246 EXPECT_EQ(std::string("hello again world!"),
247 std::string(reinterpret_cast<const char*>(response.payload())));
248 }
249
ForwardErrorHandler(bool * called,const base::Closure & callback)250 void ForwardErrorHandler(bool* called, const base::Closure& callback) {
251 *called = true;
252 callback.Run();
253 }
254
255 // Tests that if the receiving application destroys the responder_ without
256 // sending a response, then we trigger connection error at both sides. Moreover,
257 // both sides still appear to have a valid message pipe handle bound.
TEST_F(MultiplexRouterTest,MissingResponses)258 TEST_F(MultiplexRouterTest, MissingResponses) {
259 base::RunLoop run_loop0, run_loop1;
260 InterfaceEndpointClient client0(std::move(endpoint0_), nullptr,
261 base::WrapUnique(new PassThroughFilter()),
262 false, base::ThreadTaskRunnerHandle::Get());
263 bool error_handler_called0 = false;
264 client0.set_connection_error_handler(
265 base::Bind(&ForwardErrorHandler, &error_handler_called0,
266 run_loop0.QuitClosure()));
267
268 base::RunLoop run_loop3;
269 LazyResponseGenerator generator(run_loop3.QuitClosure());
270 InterfaceEndpointClient client1(std::move(endpoint1_), &generator,
271 base::WrapUnique(new PassThroughFilter()),
272 false, base::ThreadTaskRunnerHandle::Get());
273 bool error_handler_called1 = false;
274 client1.set_connection_error_handler(
275 base::Bind(&ForwardErrorHandler, &error_handler_called1,
276 run_loop1.QuitClosure()));
277
278 Message request;
279 AllocRequestMessage(1, "hello", &request);
280
281 MessageQueue message_queue;
282 client0.AcceptWithResponder(&request, new MessageAccumulator(&message_queue));
283 run_loop3.Run();
284
285 // The request has been received but no response has been sent.
286 EXPECT_TRUE(message_queue.IsEmpty());
287
288 // Destroy the responder MessagerReceiver but don't send any response.
289 generator.CompleteWithoutResponse();
290 run_loop0.Run();
291 run_loop1.Run();
292
293 // Check that no response was received.
294 EXPECT_TRUE(message_queue.IsEmpty());
295
296 // Connection error handler is called at both sides.
297 EXPECT_TRUE(error_handler_called0);
298 EXPECT_TRUE(error_handler_called1);
299
300 // The error flag is set at both sides.
301 EXPECT_TRUE(client0.encountered_error());
302 EXPECT_TRUE(client1.encountered_error());
303
304 // The message pipe handle is valid at both sides.
305 EXPECT_TRUE(router0_->is_valid());
306 EXPECT_TRUE(router1_->is_valid());
307 }
308
TEST_F(MultiplexRouterTest,LateResponse)309 TEST_F(MultiplexRouterTest, LateResponse) {
310 // Test that things won't blow up if we try to send a message to a
311 // MessageReceiver, which was given to us via AcceptWithResponder,
312 // after the router has gone away.
313
314 base::RunLoop run_loop;
315 LazyResponseGenerator generator(run_loop.QuitClosure());
316 {
317 InterfaceEndpointClient client0(std::move(endpoint0_), nullptr,
318 base::WrapUnique(new PassThroughFilter()),
319 false, base::ThreadTaskRunnerHandle::Get());
320 InterfaceEndpointClient client1(std::move(endpoint1_), &generator,
321 base::WrapUnique(new PassThroughFilter()),
322 false, base::ThreadTaskRunnerHandle::Get());
323
324 Message request;
325 AllocRequestMessage(1, "hello", &request);
326
327 MessageQueue message_queue;
328 client0.AcceptWithResponder(&request,
329 new MessageAccumulator(&message_queue));
330
331 run_loop.Run();
332
333 EXPECT_TRUE(generator.has_responder());
334 }
335
336 EXPECT_FALSE(generator.responder_is_valid());
337 generator.CompleteWithResponse(); // This should end up doing nothing.
338 }
339
340 // TODO(yzshen): add more tests.
341
342 } // namespace
343 } // namespace test
344 } // namespace mojo
345