1 // Copyright 2016 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 <utility>
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/macros.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/run_loop.h"
12 #include "base/threading/thread.h"
13 #include "mojo/public/cpp/bindings/associated_binding.h"
14 #include "mojo/public/cpp/bindings/binding.h"
15 #include "mojo/public/interfaces/bindings/tests/test_sync_methods.mojom.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 namespace mojo {
19 namespace test {
20 namespace {
21
22 template <typename... Args>
23 struct LambdaBinder {
24 using CallbackType = base::Callback<void(Args...)>;
25
26 template <typename Func>
RunLambdamojo::test::__anon693158be0111::LambdaBinder27 static void RunLambda(Func func, Args... args) {
28 func(std::move(args)...);
29 }
30
31 template <typename Func>
BindLambdamojo::test::__anon693158be0111::LambdaBinder32 static CallbackType BindLambda(Func func) {
33 return base::Bind(&LambdaBinder::RunLambda<Func>, func);
34 }
35 };
36
37 class TestSyncCommonImpl {
38 public:
TestSyncCommonImpl()39 TestSyncCommonImpl() {}
40
41 using PingHandler = base::Callback<void(const base::Callback<void()>&)>;
42 using PingBinder = LambdaBinder<const base::Callback<void()>&>;
43 template <typename Func>
set_ping_handler(Func handler)44 void set_ping_handler(Func handler) {
45 ping_handler_ = PingBinder::BindLambda(handler);
46 }
47
48 using EchoHandler =
49 base::Callback<void(int32_t, const base::Callback<void(int32_t)>&)>;
50 using EchoBinder =
51 LambdaBinder<int32_t, const base::Callback<void(int32_t)>&>;
52 template <typename Func>
set_echo_handler(Func handler)53 void set_echo_handler(Func handler) {
54 echo_handler_ = EchoBinder::BindLambda(handler);
55 }
56
57 using AsyncEchoHandler =
58 base::Callback<void(int32_t, const base::Callback<void(int32_t)>&)>;
59 using AsyncEchoBinder =
60 LambdaBinder<int32_t, const base::Callback<void(int32_t)>&>;
61 template <typename Func>
set_async_echo_handler(Func handler)62 void set_async_echo_handler(Func handler) {
63 async_echo_handler_ = AsyncEchoBinder::BindLambda(handler);
64 }
65
66 using SendInterfaceHandler = base::Callback<void(TestSyncAssociatedPtrInfo)>;
67 using SendInterfaceBinder = LambdaBinder<TestSyncAssociatedPtrInfo>;
68 template <typename Func>
set_send_interface_handler(Func handler)69 void set_send_interface_handler(Func handler) {
70 send_interface_handler_ = SendInterfaceBinder::BindLambda(handler);
71 }
72
73 using SendRequestHandler = base::Callback<void(TestSyncAssociatedRequest)>;
74 using SendRequestBinder = LambdaBinder<TestSyncAssociatedRequest>;
75 template <typename Func>
set_send_request_handler(Func handler)76 void set_send_request_handler(Func handler) {
77 send_request_handler_ = SendRequestBinder::BindLambda(handler);
78 }
79
PingImpl(const base::Callback<void ()> & callback)80 void PingImpl(const base::Callback<void()>& callback) {
81 if (ping_handler_.is_null()) {
82 callback.Run();
83 return;
84 }
85 ping_handler_.Run(callback);
86 }
EchoImpl(int32_t value,const base::Callback<void (int32_t)> & callback)87 void EchoImpl(int32_t value, const base::Callback<void(int32_t)>& callback) {
88 if (echo_handler_.is_null()) {
89 callback.Run(value);
90 return;
91 }
92 echo_handler_.Run(value, callback);
93 }
AsyncEchoImpl(int32_t value,const base::Callback<void (int32_t)> & callback)94 void AsyncEchoImpl(int32_t value,
95 const base::Callback<void(int32_t)>& callback) {
96 if (async_echo_handler_.is_null()) {
97 callback.Run(value);
98 return;
99 }
100 async_echo_handler_.Run(value, callback);
101 }
SendInterfaceImpl(TestSyncAssociatedPtrInfo ptr)102 void SendInterfaceImpl(TestSyncAssociatedPtrInfo ptr) {
103 send_interface_handler_.Run(std::move(ptr));
104 }
SendRequestImpl(TestSyncAssociatedRequest request)105 void SendRequestImpl(TestSyncAssociatedRequest request) {
106 send_request_handler_.Run(std::move(request));
107 }
108
109 private:
110 PingHandler ping_handler_;
111 EchoHandler echo_handler_;
112 AsyncEchoHandler async_echo_handler_;
113 SendInterfaceHandler send_interface_handler_;
114 SendRequestHandler send_request_handler_;
115
116 DISALLOW_COPY_AND_ASSIGN(TestSyncCommonImpl);
117 };
118
119 class TestSyncImpl : public TestSync, public TestSyncCommonImpl {
120 public:
TestSyncImpl(TestSyncRequest request)121 explicit TestSyncImpl(TestSyncRequest request)
122 : binding_(this, std::move(request)) {}
123
124 // TestSync implementation:
Ping(const PingCallback & callback)125 void Ping(const PingCallback& callback) override { PingImpl(callback); }
Echo(int32_t value,const EchoCallback & callback)126 void Echo(int32_t value, const EchoCallback& callback) override {
127 EchoImpl(value, callback);
128 }
AsyncEcho(int32_t value,const AsyncEchoCallback & callback)129 void AsyncEcho(int32_t value, const AsyncEchoCallback& callback) override {
130 AsyncEchoImpl(value, callback);
131 }
132
binding()133 Binding<TestSync>* binding() { return &binding_; }
134
135 private:
136 Binding<TestSync> binding_;
137
138 DISALLOW_COPY_AND_ASSIGN(TestSyncImpl);
139 };
140
141 class TestSyncMasterImpl : public TestSyncMaster, public TestSyncCommonImpl {
142 public:
TestSyncMasterImpl(TestSyncMasterRequest request)143 explicit TestSyncMasterImpl(TestSyncMasterRequest request)
144 : binding_(this, std::move(request)) {}
145
146 // TestSyncMaster implementation:
Ping(const PingCallback & callback)147 void Ping(const PingCallback& callback) override { PingImpl(callback); }
Echo(int32_t value,const EchoCallback & callback)148 void Echo(int32_t value, const EchoCallback& callback) override {
149 EchoImpl(value, callback);
150 }
AsyncEcho(int32_t value,const AsyncEchoCallback & callback)151 void AsyncEcho(int32_t value, const AsyncEchoCallback& callback) override {
152 AsyncEchoImpl(value, callback);
153 }
SendInterface(TestSyncAssociatedPtrInfo ptr)154 void SendInterface(TestSyncAssociatedPtrInfo ptr) override {
155 SendInterfaceImpl(std::move(ptr));
156 }
SendRequest(TestSyncAssociatedRequest request)157 void SendRequest(TestSyncAssociatedRequest request) override {
158 SendRequestImpl(std::move(request));
159 }
160
binding()161 Binding<TestSyncMaster>* binding() { return &binding_; }
162
163 private:
164 Binding<TestSyncMaster> binding_;
165
166 DISALLOW_COPY_AND_ASSIGN(TestSyncMasterImpl);
167 };
168
169 class TestSyncAssociatedImpl : public TestSync, public TestSyncCommonImpl {
170 public:
TestSyncAssociatedImpl(TestSyncAssociatedRequest request)171 explicit TestSyncAssociatedImpl(TestSyncAssociatedRequest request)
172 : binding_(this, std::move(request)) {}
173
174 // TestSync implementation:
Ping(const PingCallback & callback)175 void Ping(const PingCallback& callback) override { PingImpl(callback); }
Echo(int32_t value,const EchoCallback & callback)176 void Echo(int32_t value, const EchoCallback& callback) override {
177 EchoImpl(value, callback);
178 }
AsyncEcho(int32_t value,const AsyncEchoCallback & callback)179 void AsyncEcho(int32_t value, const AsyncEchoCallback& callback) override {
180 AsyncEchoImpl(value, callback);
181 }
182
binding()183 AssociatedBinding<TestSync>* binding() { return &binding_; }
184
185 private:
186 AssociatedBinding<TestSync> binding_;
187
188 DISALLOW_COPY_AND_ASSIGN(TestSyncAssociatedImpl);
189 };
190
191 template <typename Interface>
192 struct ImplTraits;
193
194 template <>
195 struct ImplTraits<TestSync> {
196 using Type = TestSyncImpl;
197 };
198
199 template <>
200 struct ImplTraits<TestSyncMaster> {
201 using Type = TestSyncMasterImpl;
202 };
203
204 template <typename Interface>
205 class TestSyncServiceThread {
206 public:
TestSyncServiceThread()207 TestSyncServiceThread()
208 : thread_("TestSyncServiceThread"), ping_called_(false) {
209 thread_.Start();
210 }
211
SetUp(InterfaceRequest<Interface> request)212 void SetUp(InterfaceRequest<Interface> request) {
213 CHECK(thread_.task_runner()->BelongsToCurrentThread());
214 impl_.reset(new typename ImplTraits<Interface>::Type(std::move(request)));
215 impl_->set_ping_handler(
216 [this](const typename Interface::PingCallback& callback) {
217 {
218 base::AutoLock locker(lock_);
219 ping_called_ = true;
220 }
221 callback.Run();
222 });
223 }
224
TearDown()225 void TearDown() {
226 CHECK(thread_.task_runner()->BelongsToCurrentThread());
227 impl_.reset();
228 }
229
thread()230 base::Thread* thread() { return &thread_; }
ping_called() const231 bool ping_called() const {
232 base::AutoLock locker(lock_);
233 return ping_called_;
234 }
235
236 private:
237 base::Thread thread_;
238
239 std::unique_ptr<typename ImplTraits<Interface>::Type> impl_;
240
241 mutable base::Lock lock_;
242 bool ping_called_;
243
244 DISALLOW_COPY_AND_ASSIGN(TestSyncServiceThread);
245 };
246
247 class SyncMethodTest : public testing::Test {
248 public:
SyncMethodTest()249 SyncMethodTest() {}
~SyncMethodTest()250 ~SyncMethodTest() override { base::RunLoop().RunUntilIdle(); }
251
252 protected:
253 base::MessageLoop loop_;
254 };
255
256 template <typename T>
257 class SyncMethodCommonTest : public SyncMethodTest {
258 public:
SyncMethodCommonTest()259 SyncMethodCommonTest() {}
~SyncMethodCommonTest()260 ~SyncMethodCommonTest() override {}
261 };
262
263 class SyncMethodAssociatedTest : public SyncMethodTest {
264 public:
SyncMethodAssociatedTest()265 SyncMethodAssociatedTest() {}
~SyncMethodAssociatedTest()266 ~SyncMethodAssociatedTest() override {}
267
268 protected:
SetUp()269 void SetUp() override {
270 master_impl_.reset(new TestSyncMasterImpl(GetProxy(&master_ptr_)));
271
272 master_ptr_.associated_group()->CreateAssociatedInterface(
273 AssociatedGroup::WILL_PASS_REQUEST, &asso_ptr_info_, &asso_request_);
274 master_ptr_.associated_group()->CreateAssociatedInterface(
275 AssociatedGroup::WILL_PASS_PTR, &opposite_asso_ptr_info_,
276 &opposite_asso_request_);
277
278 master_impl_->set_send_interface_handler(
279 [this](TestSyncAssociatedPtrInfo ptr) {
280 opposite_asso_ptr_info_ = std::move(ptr);
281 });
282 base::RunLoop run_loop;
283 master_impl_->set_send_request_handler(
284 [this, &run_loop](TestSyncAssociatedRequest request) {
285 asso_request_ = std::move(request);
286 run_loop.Quit();
287 });
288
289 master_ptr_->SendInterface(std::move(opposite_asso_ptr_info_));
290 master_ptr_->SendRequest(std::move(asso_request_));
291 run_loop.Run();
292 }
293
TearDown()294 void TearDown() override {
295 asso_ptr_info_ = TestSyncAssociatedPtrInfo();
296 asso_request_ = TestSyncAssociatedRequest();
297 opposite_asso_ptr_info_ = TestSyncAssociatedPtrInfo();
298 opposite_asso_request_ = TestSyncAssociatedRequest();
299
300 master_ptr_ = nullptr;
301 master_impl_.reset();
302 }
303
304 InterfacePtr<TestSyncMaster> master_ptr_;
305 std::unique_ptr<TestSyncMasterImpl> master_impl_;
306
307 // An associated interface whose binding lives at the |master_impl_| side.
308 TestSyncAssociatedPtrInfo asso_ptr_info_;
309 TestSyncAssociatedRequest asso_request_;
310
311 // An associated interface whose binding lives at the |master_ptr_| side.
312 TestSyncAssociatedPtrInfo opposite_asso_ptr_info_;
313 TestSyncAssociatedRequest opposite_asso_request_;
314 };
315
SetFlagAndRunClosure(bool * flag,const base::Closure & closure)316 void SetFlagAndRunClosure(bool* flag, const base::Closure& closure) {
317 *flag = true;
318 closure.Run();
319 }
320
ExpectValueAndRunClosure(int32_t expected_value,const base::Closure & closure,int32_t value)321 void ExpectValueAndRunClosure(int32_t expected_value,
322 const base::Closure& closure,
323 int32_t value) {
324 EXPECT_EQ(expected_value, value);
325 closure.Run();
326 }
327
328 template <typename Func>
CallAsyncEchoCallback(Func func,int32_t value)329 void CallAsyncEchoCallback(Func func, int32_t value) {
330 func(value);
331 }
332
333 template <typename Func>
BindAsyncEchoCallback(Func func)334 TestSync::AsyncEchoCallback BindAsyncEchoCallback(Func func) {
335 return base::Bind(&CallAsyncEchoCallback<Func>, func);
336 }
337
338 // TestSync and TestSyncMaster exercise Router and MultiplexRouter,
339 // respectively.
340 using InterfaceTypes = testing::Types<TestSync, TestSyncMaster>;
341 TYPED_TEST_CASE(SyncMethodCommonTest, InterfaceTypes);
342
TYPED_TEST(SyncMethodCommonTest,CallSyncMethodAsynchronously)343 TYPED_TEST(SyncMethodCommonTest, CallSyncMethodAsynchronously) {
344 InterfacePtr<TypeParam> ptr;
345 typename ImplTraits<TypeParam>::Type impl(GetProxy(&ptr));
346
347 base::RunLoop run_loop;
348 ptr->Echo(123, base::Bind(&ExpectValueAndRunClosure, 123,
349 run_loop.QuitClosure()));
350 run_loop.Run();
351 }
352
TYPED_TEST(SyncMethodCommonTest,BasicSyncCalls)353 TYPED_TEST(SyncMethodCommonTest, BasicSyncCalls) {
354 InterfacePtr<TypeParam> ptr;
355
356 TestSyncServiceThread<TypeParam> service_thread;
357 service_thread.thread()->task_runner()->PostTask(
358 FROM_HERE, base::Bind(&TestSyncServiceThread<TypeParam>::SetUp,
359 base::Unretained(&service_thread),
360 base::Passed(GetProxy(&ptr))));
361 ASSERT_TRUE(ptr->Ping());
362 ASSERT_TRUE(service_thread.ping_called());
363
364 int32_t output_value = -1;
365 ASSERT_TRUE(ptr->Echo(42, &output_value));
366 ASSERT_EQ(42, output_value);
367
368 base::RunLoop run_loop;
369 service_thread.thread()->task_runner()->PostTaskAndReply(
370 FROM_HERE, base::Bind(&TestSyncServiceThread<TypeParam>::TearDown,
371 base::Unretained(&service_thread)),
372 run_loop.QuitClosure());
373 run_loop.Run();
374 }
375
TYPED_TEST(SyncMethodCommonTest,ReenteredBySyncMethodBinding)376 TYPED_TEST(SyncMethodCommonTest, ReenteredBySyncMethodBinding) {
377 // Test that an interface pointer waiting for a sync call response can be
378 // reentered by a binding serving sync methods on the same thread.
379
380 InterfacePtr<TypeParam> ptr;
381 // The binding lives on the same thread as the interface pointer.
382 typename ImplTraits<TypeParam>::Type impl(GetProxy(&ptr));
383 int32_t output_value = -1;
384 ASSERT_TRUE(ptr->Echo(42, &output_value));
385 EXPECT_EQ(42, output_value);
386 }
387
TYPED_TEST(SyncMethodCommonTest,InterfacePtrDestroyedDuringSyncCall)388 TYPED_TEST(SyncMethodCommonTest, InterfacePtrDestroyedDuringSyncCall) {
389 // Test that it won't result in crash or hang if an interface pointer is
390 // destroyed while it is waiting for a sync call response.
391
392 InterfacePtr<TypeParam> ptr;
393 typename ImplTraits<TypeParam>::Type impl(GetProxy(&ptr));
394 impl.set_ping_handler([&ptr](const TestSync::PingCallback& callback) {
395 ptr.reset();
396 callback.Run();
397 });
398 ASSERT_FALSE(ptr->Ping());
399 }
400
TYPED_TEST(SyncMethodCommonTest,BindingDestroyedDuringSyncCall)401 TYPED_TEST(SyncMethodCommonTest, BindingDestroyedDuringSyncCall) {
402 // Test that it won't result in crash or hang if a binding is
403 // closed (and therefore the message pipe handle is closed) while the
404 // corresponding interface pointer is waiting for a sync call response.
405
406 InterfacePtr<TypeParam> ptr;
407 typename ImplTraits<TypeParam>::Type impl(GetProxy(&ptr));
408 impl.set_ping_handler([&impl](const TestSync::PingCallback& callback) {
409 impl.binding()->Close();
410 callback.Run();
411 });
412 ASSERT_FALSE(ptr->Ping());
413 }
414
TYPED_TEST(SyncMethodCommonTest,NestedSyncCallsWithInOrderResponses)415 TYPED_TEST(SyncMethodCommonTest, NestedSyncCallsWithInOrderResponses) {
416 // Test that we can call a sync method on an interface ptr, while there is
417 // already a sync call ongoing. The responses arrive in order.
418
419 InterfacePtr<TypeParam> ptr;
420 typename ImplTraits<TypeParam>::Type impl(GetProxy(&ptr));
421
422 // The same variable is used to store the output of the two sync calls, in
423 // order to test that responses are handled in the correct order.
424 int32_t result_value = -1;
425
426 bool first_call = true;
427 impl.set_echo_handler([&first_call, &ptr, &result_value](
428 int32_t value, const TestSync::EchoCallback& callback) {
429 if (first_call) {
430 first_call = false;
431 ASSERT_TRUE(ptr->Echo(456, &result_value));
432 EXPECT_EQ(456, result_value);
433 }
434 callback.Run(value);
435 });
436
437 ASSERT_TRUE(ptr->Echo(123, &result_value));
438 EXPECT_EQ(123, result_value);
439 }
440
TYPED_TEST(SyncMethodCommonTest,NestedSyncCallsWithOutOfOrderResponses)441 TYPED_TEST(SyncMethodCommonTest, NestedSyncCallsWithOutOfOrderResponses) {
442 // Test that we can call a sync method on an interface ptr, while there is
443 // already a sync call ongoing. The responses arrive out of order.
444
445 InterfacePtr<TypeParam> ptr;
446 typename ImplTraits<TypeParam>::Type impl(GetProxy(&ptr));
447
448 // The same variable is used to store the output of the two sync calls, in
449 // order to test that responses are handled in the correct order.
450 int32_t result_value = -1;
451
452 bool first_call = true;
453 impl.set_echo_handler([&first_call, &ptr, &result_value](
454 int32_t value, const TestSync::EchoCallback& callback) {
455 callback.Run(value);
456 if (first_call) {
457 first_call = false;
458 ASSERT_TRUE(ptr->Echo(456, &result_value));
459 EXPECT_EQ(456, result_value);
460 }
461 });
462
463 ASSERT_TRUE(ptr->Echo(123, &result_value));
464 EXPECT_EQ(123, result_value);
465 }
466
TYPED_TEST(SyncMethodCommonTest,AsyncResponseQueuedDuringSyncCall)467 TYPED_TEST(SyncMethodCommonTest, AsyncResponseQueuedDuringSyncCall) {
468 // Test that while an interface pointer is waiting for the response to a sync
469 // call, async responses are queued until the sync call completes.
470
471 InterfacePtr<TypeParam> ptr;
472 typename ImplTraits<TypeParam>::Type impl(GetProxy(&ptr));
473
474 int32_t async_echo_request_value = -1;
475 TestSync::AsyncEchoCallback async_echo_request_callback;
476 base::RunLoop run_loop1;
477 impl.set_async_echo_handler(
478 [&async_echo_request_value, &async_echo_request_callback, &run_loop1](
479 int32_t value, const TestSync::AsyncEchoCallback& callback) {
480 async_echo_request_value = value;
481 async_echo_request_callback = callback;
482 run_loop1.Quit();
483 });
484
485 bool async_echo_response_dispatched = false;
486 base::RunLoop run_loop2;
487 ptr->AsyncEcho(
488 123,
489 BindAsyncEchoCallback(
490 [&async_echo_response_dispatched, &run_loop2](int32_t result) {
491 async_echo_response_dispatched = true;
492 EXPECT_EQ(123, result);
493 run_loop2.Quit();
494 }));
495 // Run until the AsyncEcho request reaches the service side.
496 run_loop1.Run();
497
498 impl.set_echo_handler(
499 [&async_echo_request_value, &async_echo_request_callback](
500 int32_t value, const TestSync::EchoCallback& callback) {
501 // Send back the async response first.
502 EXPECT_FALSE(async_echo_request_callback.is_null());
503 async_echo_request_callback.Run(async_echo_request_value);
504
505 callback.Run(value);
506 });
507
508 int32_t result_value = -1;
509 ASSERT_TRUE(ptr->Echo(456, &result_value));
510 EXPECT_EQ(456, result_value);
511
512 // Although the AsyncEcho response arrives before the Echo response, it should
513 // be queued and not yet dispatched.
514 EXPECT_FALSE(async_echo_response_dispatched);
515
516 // Run until the AsyncEcho response is dispatched.
517 run_loop2.Run();
518
519 EXPECT_TRUE(async_echo_response_dispatched);
520 }
521
TYPED_TEST(SyncMethodCommonTest,AsyncRequestQueuedDuringSyncCall)522 TYPED_TEST(SyncMethodCommonTest, AsyncRequestQueuedDuringSyncCall) {
523 // Test that while an interface pointer is waiting for the response to a sync
524 // call, async requests for a binding running on the same thread are queued
525 // until the sync call completes.
526
527 InterfacePtr<TypeParam> ptr;
528 typename ImplTraits<TypeParam>::Type impl(GetProxy(&ptr));
529
530 bool async_echo_request_dispatched = false;
531 impl.set_async_echo_handler([&async_echo_request_dispatched](
532 int32_t value, const TestSync::AsyncEchoCallback& callback) {
533 async_echo_request_dispatched = true;
534 callback.Run(value);
535 });
536
537 bool async_echo_response_dispatched = false;
538 base::RunLoop run_loop;
539 ptr->AsyncEcho(
540 123,
541 BindAsyncEchoCallback(
542 [&async_echo_response_dispatched, &run_loop](int32_t result) {
543 async_echo_response_dispatched = true;
544 EXPECT_EQ(123, result);
545 run_loop.Quit();
546 }));
547
548 impl.set_echo_handler([&async_echo_request_dispatched](
549 int32_t value, const TestSync::EchoCallback& callback) {
550 // Although the AsyncEcho request is sent before the Echo request, it
551 // shouldn't be dispatched yet at this point, because there is an ongoing
552 // sync call on the same thread.
553 EXPECT_FALSE(async_echo_request_dispatched);
554 callback.Run(value);
555 });
556
557 int32_t result_value = -1;
558 ASSERT_TRUE(ptr->Echo(456, &result_value));
559 EXPECT_EQ(456, result_value);
560
561 // Although the AsyncEcho request is sent before the Echo request, it
562 // shouldn't be dispatched yet.
563 EXPECT_FALSE(async_echo_request_dispatched);
564
565 // Run until the AsyncEcho response is dispatched.
566 run_loop.Run();
567
568 EXPECT_TRUE(async_echo_response_dispatched);
569 }
570
TYPED_TEST(SyncMethodCommonTest,QueuedMessagesProcessedBeforeErrorNotification)571 TYPED_TEST(SyncMethodCommonTest,
572 QueuedMessagesProcessedBeforeErrorNotification) {
573 // Test that while an interface pointer is waiting for the response to a sync
574 // call, async responses are queued. If the message pipe is disconnected
575 // before the queued messages are processed, the connection error
576 // notification is delayed until all the queued messages are processed.
577
578 InterfacePtr<TypeParam> ptr;
579 typename ImplTraits<TypeParam>::Type impl(GetProxy(&ptr));
580
581 int32_t async_echo_request_value = -1;
582 TestSync::AsyncEchoCallback async_echo_request_callback;
583 base::RunLoop run_loop1;
584 impl.set_async_echo_handler(
585 [&async_echo_request_value, &async_echo_request_callback, &run_loop1](
586 int32_t value, const TestSync::AsyncEchoCallback& callback) {
587 async_echo_request_value = value;
588 async_echo_request_callback = callback;
589 run_loop1.Quit();
590 });
591
592 bool async_echo_response_dispatched = false;
593 bool connection_error_dispatched = false;
594 base::RunLoop run_loop2;
595 ptr->AsyncEcho(
596 123,
597 BindAsyncEchoCallback(
598 [&async_echo_response_dispatched, &connection_error_dispatched, &ptr,
599 &run_loop2](int32_t result) {
600 async_echo_response_dispatched = true;
601 // At this point, error notification should not be dispatched
602 // yet.
603 EXPECT_FALSE(connection_error_dispatched);
604 EXPECT_FALSE(ptr.encountered_error());
605 EXPECT_EQ(123, result);
606 run_loop2.Quit();
607 }));
608 // Run until the AsyncEcho request reaches the service side.
609 run_loop1.Run();
610
611 impl.set_echo_handler(
612 [&impl, &async_echo_request_value, &async_echo_request_callback](
613 int32_t value, const TestSync::EchoCallback& callback) {
614 // Send back the async response first.
615 EXPECT_FALSE(async_echo_request_callback.is_null());
616 async_echo_request_callback.Run(async_echo_request_value);
617
618 impl.binding()->Close();
619 });
620
621 base::RunLoop run_loop3;
622 ptr.set_connection_error_handler(
623 base::Bind(&SetFlagAndRunClosure, &connection_error_dispatched,
624 run_loop3.QuitClosure()));
625
626 int32_t result_value = -1;
627 ASSERT_FALSE(ptr->Echo(456, &result_value));
628 EXPECT_EQ(-1, result_value);
629 ASSERT_FALSE(connection_error_dispatched);
630 EXPECT_FALSE(ptr.encountered_error());
631
632 // Although the AsyncEcho response arrives before the Echo response, it should
633 // be queued and not yet dispatched.
634 EXPECT_FALSE(async_echo_response_dispatched);
635
636 // Run until the AsyncEcho response is dispatched.
637 run_loop2.Run();
638
639 EXPECT_TRUE(async_echo_response_dispatched);
640
641 // Run until the error notification is dispatched.
642 run_loop3.Run();
643
644 ASSERT_TRUE(connection_error_dispatched);
645 EXPECT_TRUE(ptr.encountered_error());
646 }
647
TYPED_TEST(SyncMethodCommonTest,InvalidMessageDuringSyncCall)648 TYPED_TEST(SyncMethodCommonTest, InvalidMessageDuringSyncCall) {
649 // Test that while an interface pointer is waiting for the response to a sync
650 // call, an invalid incoming message will disconnect the message pipe, cause
651 // the sync call to return false, and run the connection error handler
652 // asynchronously.
653
654 MessagePipe pipe;
655
656 InterfacePtr<TypeParam> ptr;
657 ptr.Bind(InterfacePtrInfo<TypeParam>(std::move(pipe.handle0), 0u));
658
659 MessagePipeHandle raw_binding_handle = pipe.handle1.get();
660 typename ImplTraits<TypeParam>::Type impl(
661 MakeRequest<TypeParam>(std::move(pipe.handle1)));
662
663 impl.set_echo_handler([&raw_binding_handle](
664 int32_t value, const TestSync::EchoCallback& callback) {
665 // Write a 1-byte message, which is considered invalid.
666 char invalid_message = 0;
667 MojoResult result =
668 WriteMessageRaw(raw_binding_handle, &invalid_message, 1u, nullptr, 0u,
669 MOJO_WRITE_MESSAGE_FLAG_NONE);
670 ASSERT_EQ(MOJO_RESULT_OK, result);
671 callback.Run(value);
672 });
673
674 bool connection_error_dispatched = false;
675 base::RunLoop run_loop;
676 ptr.set_connection_error_handler(
677 base::Bind(&SetFlagAndRunClosure, &connection_error_dispatched,
678 run_loop.QuitClosure()));
679
680 int32_t result_value = -1;
681 ASSERT_FALSE(ptr->Echo(456, &result_value));
682 EXPECT_EQ(-1, result_value);
683 ASSERT_FALSE(connection_error_dispatched);
684
685 run_loop.Run();
686 ASSERT_TRUE(connection_error_dispatched);
687 }
688
TEST_F(SyncMethodAssociatedTest,ReenteredBySyncMethodAssoBindingOfSameRouter)689 TEST_F(SyncMethodAssociatedTest, ReenteredBySyncMethodAssoBindingOfSameRouter) {
690 // Test that an interface pointer waiting for a sync call response can be
691 // reentered by an associated binding serving sync methods on the same thread.
692 // The associated binding belongs to the same MultiplexRouter as the waiting
693 // interface pointer.
694
695 TestSyncAssociatedImpl opposite_asso_impl(std::move(opposite_asso_request_));
696 TestSyncAssociatedPtr opposite_asso_ptr;
697 opposite_asso_ptr.Bind(std::move(opposite_asso_ptr_info_));
698
699 master_impl_->set_echo_handler([&opposite_asso_ptr](
700 int32_t value, const TestSyncMaster::EchoCallback& callback) {
701 int32_t result_value = -1;
702
703 ASSERT_TRUE(opposite_asso_ptr->Echo(123, &result_value));
704 EXPECT_EQ(123, result_value);
705 callback.Run(value);
706 });
707
708 int32_t result_value = -1;
709 ASSERT_TRUE(master_ptr_->Echo(456, &result_value));
710 EXPECT_EQ(456, result_value);
711 }
712
TEST_F(SyncMethodAssociatedTest,ReenteredBySyncMethodAssoBindingOfDifferentRouter)713 TEST_F(SyncMethodAssociatedTest,
714 ReenteredBySyncMethodAssoBindingOfDifferentRouter) {
715 // Test that an interface pointer waiting for a sync call response can be
716 // reentered by an associated binding serving sync methods on the same thread.
717 // The associated binding belongs to a different MultiplexRouter as the
718 // waiting interface pointer.
719
720 TestSyncAssociatedImpl asso_impl(std::move(asso_request_));
721 TestSyncAssociatedPtr asso_ptr;
722 asso_ptr.Bind(std::move(asso_ptr_info_));
723
724 master_impl_->set_echo_handler(
725 [&asso_ptr](int32_t value, const TestSyncMaster::EchoCallback& callback) {
726 int32_t result_value = -1;
727
728 ASSERT_TRUE(asso_ptr->Echo(123, &result_value));
729 EXPECT_EQ(123, result_value);
730 callback.Run(value);
731 });
732
733 int32_t result_value = -1;
734 ASSERT_TRUE(master_ptr_->Echo(456, &result_value));
735 EXPECT_EQ(456, result_value);
736 }
737
738 // TODO(yzshen): Add more tests related to associated interfaces.
739
740 } // namespace
741 } // namespace test
742 } // namespace mojo
743