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
18namespace mojo {
19namespace test {
20namespace {
21
22template <typename... Args>
23struct LambdaBinder {
24  using CallbackType = base::Callback<void(Args...)>;
25
26  template <typename Func>
27  static void RunLambda(Func func, Args... args) {
28    func(std::move(args)...);
29  }
30
31  template <typename Func>
32  static CallbackType BindLambda(Func func) {
33    return base::Bind(&LambdaBinder::RunLambda<Func>, func);
34  }
35};
36
37class TestSyncCommonImpl {
38 public:
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>
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>
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>
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>
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>
76  void set_send_request_handler(Func handler) {
77    send_request_handler_ = SendRequestBinder::BindLambda(handler);
78  }
79
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  }
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  }
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  }
102  void SendInterfaceImpl(TestSyncAssociatedPtrInfo ptr) {
103    send_interface_handler_.Run(std::move(ptr));
104  }
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
119class TestSyncImpl : public TestSync, public TestSyncCommonImpl {
120 public:
121  explicit TestSyncImpl(TestSyncRequest request)
122      : binding_(this, std::move(request)) {}
123
124  // TestSync implementation:
125  void Ping(const PingCallback& callback) override { PingImpl(callback); }
126  void Echo(int32_t value, const EchoCallback& callback) override {
127    EchoImpl(value, callback);
128  }
129  void AsyncEcho(int32_t value, const AsyncEchoCallback& callback) override {
130    AsyncEchoImpl(value, callback);
131  }
132
133  Binding<TestSync>* binding() { return &binding_; }
134
135 private:
136  Binding<TestSync> binding_;
137
138  DISALLOW_COPY_AND_ASSIGN(TestSyncImpl);
139};
140
141class TestSyncMasterImpl : public TestSyncMaster, public TestSyncCommonImpl {
142 public:
143  explicit TestSyncMasterImpl(TestSyncMasterRequest request)
144      : binding_(this, std::move(request)) {}
145
146  // TestSyncMaster implementation:
147  void Ping(const PingCallback& callback) override { PingImpl(callback); }
148  void Echo(int32_t value, const EchoCallback& callback) override {
149    EchoImpl(value, callback);
150  }
151  void AsyncEcho(int32_t value, const AsyncEchoCallback& callback) override {
152    AsyncEchoImpl(value, callback);
153  }
154  void SendInterface(TestSyncAssociatedPtrInfo ptr) override {
155    SendInterfaceImpl(std::move(ptr));
156  }
157  void SendRequest(TestSyncAssociatedRequest request) override {
158    SendRequestImpl(std::move(request));
159  }
160
161  Binding<TestSyncMaster>* binding() { return &binding_; }
162
163 private:
164  Binding<TestSyncMaster> binding_;
165
166  DISALLOW_COPY_AND_ASSIGN(TestSyncMasterImpl);
167};
168
169class TestSyncAssociatedImpl : public TestSync, public TestSyncCommonImpl {
170 public:
171  explicit TestSyncAssociatedImpl(TestSyncAssociatedRequest request)
172      : binding_(this, std::move(request)) {}
173
174  // TestSync implementation:
175  void Ping(const PingCallback& callback) override { PingImpl(callback); }
176  void Echo(int32_t value, const EchoCallback& callback) override {
177    EchoImpl(value, callback);
178  }
179  void AsyncEcho(int32_t value, const AsyncEchoCallback& callback) override {
180    AsyncEchoImpl(value, callback);
181  }
182
183  AssociatedBinding<TestSync>* binding() { return &binding_; }
184
185 private:
186  AssociatedBinding<TestSync> binding_;
187
188  DISALLOW_COPY_AND_ASSIGN(TestSyncAssociatedImpl);
189};
190
191template <typename Interface>
192struct ImplTraits;
193
194template <>
195struct ImplTraits<TestSync> {
196  using Type = TestSyncImpl;
197};
198
199template <>
200struct ImplTraits<TestSyncMaster> {
201  using Type = TestSyncMasterImpl;
202};
203
204template <typename Interface>
205class TestSyncServiceThread {
206 public:
207  TestSyncServiceThread()
208      : thread_("TestSyncServiceThread"), ping_called_(false) {
209    thread_.Start();
210  }
211
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
225  void TearDown() {
226    CHECK(thread_.task_runner()->BelongsToCurrentThread());
227    impl_.reset();
228  }
229
230  base::Thread* thread() { return &thread_; }
231  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
247class SyncMethodTest : public testing::Test {
248 public:
249  SyncMethodTest() {}
250  ~SyncMethodTest() override { base::RunLoop().RunUntilIdle(); }
251
252 protected:
253  base::MessageLoop loop_;
254};
255
256template <typename T>
257class SyncMethodCommonTest : public SyncMethodTest {
258 public:
259  SyncMethodCommonTest() {}
260  ~SyncMethodCommonTest() override {}
261};
262
263class SyncMethodAssociatedTest : public SyncMethodTest {
264 public:
265  SyncMethodAssociatedTest() {}
266  ~SyncMethodAssociatedTest() override {}
267
268 protected:
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
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
316void SetFlagAndRunClosure(bool* flag, const base::Closure& closure) {
317  *flag = true;
318  closure.Run();
319}
320
321void 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
328template <typename Func>
329void CallAsyncEchoCallback(Func func, int32_t value) {
330  func(value);
331}
332
333template <typename Func>
334TestSync::AsyncEchoCallback BindAsyncEchoCallback(Func func) {
335  return base::Bind(&CallAsyncEchoCallback<Func>, func);
336}
337
338// TestSync and TestSyncMaster exercise Router and MultiplexRouter,
339// respectively.
340using InterfaceTypes = testing::Types<TestSync, TestSyncMaster>;
341TYPED_TEST_CASE(SyncMethodCommonTest, InterfaceTypes);
342
343TYPED_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
353TYPED_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
376TYPED_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
388TYPED_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
401TYPED_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
415TYPED_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
441TYPED_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
467TYPED_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
522TYPED_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
571TYPED_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
648TYPED_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
689TEST_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
713TEST_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