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