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