• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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