| Index: mojo/public/cpp/bindings/tests/sync_method_unittest.cc
|
| diff --git a/mojo/public/cpp/bindings/tests/sync_method_unittest.cc b/mojo/public/cpp/bindings/tests/sync_method_unittest.cc
|
| index acd379a0cfc2824d6a430220f3bdbec9b1606192..b4f794ee35994cf51877e5bfd484b8d4927e12e0 100644
|
| --- a/mojo/public/cpp/bindings/tests/sync_method_unittest.cc
|
| +++ b/mojo/public/cpp/bindings/tests/sync_method_unittest.cc
|
| @@ -9,9 +9,13 @@
|
| #include "base/macros.h"
|
| #include "base/message_loop/message_loop.h"
|
| #include "base/run_loop.h"
|
| +#include "base/sequence_token.h"
|
| +#include "base/test/sequenced_worker_pool_owner.h"
|
| +#include "base/threading/sequenced_worker_pool.h"
|
| #include "base/threading/thread.h"
|
| #include "mojo/public/cpp/bindings/associated_binding.h"
|
| #include "mojo/public/cpp/bindings/binding.h"
|
| +#include "mojo/public/cpp/bindings/tests/thread_per_task_sequenced_task_runner.h"
|
| #include "mojo/public/interfaces/bindings/tests/test_sync_methods.mojom.h"
|
| #include "testing/gtest/include/gtest/gtest.h"
|
|
|
| @@ -227,7 +231,9 @@ class TestSyncServiceThread {
|
| impl_.reset();
|
| }
|
|
|
| - base::Thread* thread() { return &thread_; }
|
| + base::SequencedTaskRunner* task_runner() {
|
| + return thread_.task_runner().get();
|
| + }
|
| bool ping_called() const {
|
| base::AutoLock locker(lock_);
|
| return ping_called_;
|
| @@ -244,6 +250,52 @@ class TestSyncServiceThread {
|
| DISALLOW_COPY_AND_ASSIGN(TestSyncServiceThread);
|
| };
|
|
|
| +template <typename Interface>
|
| +class TestSyncServiceSequencedPool {
|
| + public:
|
| + TestSyncServiceSequencedPool()
|
| + : pool_(2, "TestSyncServiceSequencedPool"),
|
| + token_(base::SequencedWorkerPool::GetSequenceToken()),
|
| + task_runner_(pool_.pool()->GetSequencedTaskRunner(token_)),
|
| + ping_called_(false) {}
|
| +
|
| + void SetUp(InterfaceRequest<Interface> request) {
|
| + CHECK(task_runner_->RunsTasksOnCurrentThread());
|
| + impl_.reset(new typename ImplTraits<Interface>::Type(std::move(request)));
|
| + impl_->set_ping_handler(
|
| + [this](const typename Interface::PingCallback& callback) {
|
| + {
|
| + base::AutoLock locker(lock_);
|
| + ping_called_ = true;
|
| + }
|
| + callback.Run();
|
| + });
|
| + }
|
| +
|
| + void TearDown() {
|
| + CHECK(task_runner_->RunsTasksOnCurrentThread());
|
| + impl_.reset();
|
| + }
|
| +
|
| + base::SequencedTaskRunner* task_runner() { return task_runner_.get(); }
|
| + bool ping_called() const {
|
| + base::AutoLock locker(lock_);
|
| + return ping_called_;
|
| + }
|
| +
|
| + private:
|
| + base::SequencedWorkerPoolOwner pool_;
|
| + base::SequencedWorkerPool::SequenceToken token_;
|
| + scoped_refptr<base::SequencedTaskRunner> task_runner_;
|
| +
|
| + std::unique_ptr<typename ImplTraits<Interface>::Type> impl_;
|
| +
|
| + mutable base::Lock lock_;
|
| + bool ping_called_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(TestSyncServiceSequencedPool);
|
| +};
|
| +
|
| class SyncMethodTest : public testing::Test {
|
| public:
|
| SyncMethodTest() {}
|
| @@ -334,11 +386,87 @@ template <typename Func>
|
| TestSync::AsyncEchoCallback BindAsyncEchoCallback(Func func) {
|
| return base::Bind(&CallAsyncEchoCallback<Func>, func);
|
| }
|
| +class SequencedTaskRunnerTestBase;
|
| +
|
| +void RunTestOnSequencedTaskRunner(
|
| + std::unique_ptr<SequencedTaskRunnerTestBase> test);
|
| +
|
| +class SequencedTaskRunnerTestBase {
|
| + public:
|
| + virtual ~SequencedTaskRunnerTestBase() = default;
|
| +
|
| + void RunTest() {
|
| + SetUp();
|
| + Run();
|
| + }
|
| +
|
| + virtual void Run() = 0;
|
| +
|
| + virtual void SetUp() {}
|
| + virtual void TearDown() {}
|
| +
|
| + protected:
|
| + void Done() {
|
| + TearDown();
|
| + task_runner_->PostTask(FROM_HERE, quit_closure_);
|
| + delete this;
|
| + }
|
| +
|
| + base::Closure DoneClosure() {
|
| + return base::Bind(&SequencedTaskRunnerTestBase::Done,
|
| + base::Unretained(this));
|
| + }
|
| +
|
| + private:
|
| + friend void RunTestOnSequencedTaskRunner(
|
| + std::unique_ptr<SequencedTaskRunnerTestBase> test);
|
| +
|
| + void Init(const base::Closure& quit_closure) {
|
| + task_runner_ = base::SequencedTaskRunnerHandle::Get();
|
| + quit_closure_ = quit_closure;
|
| + }
|
| +
|
| + scoped_refptr<base::SequencedTaskRunner> task_runner_;
|
| + base::Closure quit_closure_;
|
| +};
|
| +
|
| +template <typename TypeParam>
|
| +class SyncMethodCommonOnSequencedTaskRunnerCommonTest : public testing::Test {
|
| + base::MessageLoop message_loop_;
|
| +};
|
| +
|
| +template <typename TypeParam>
|
| +class SyncMethodCommonOnSequencedTaskRunnerTest
|
| + : public SequencedTaskRunnerTestBase {
|
| + public:
|
| + void SetUp() override {
|
| + InterfacePtr<TypeParam> ptr;
|
| + impl_ = base::MakeUnique<typename ImplTraits<TypeParam>::Type>(
|
| + MakeRequest(&ptr_));
|
| + }
|
| +
|
| + protected:
|
| + InterfacePtr<TypeParam> ptr_;
|
| + std::unique_ptr<typename ImplTraits<TypeParam>::Type> impl_;
|
| +};
|
| +
|
| +void RunTestOnSequencedTaskRunner(
|
| + std::unique_ptr<SequencedTaskRunnerTestBase> test) {
|
| + ThreadPerTaskSequencedTaskRunnerOwner task_runner_owner;
|
| + base::RunLoop run_loop;
|
| + test->Init(run_loop.QuitClosure());
|
| + task_runner_owner.GetSequencedTaskRunner()->PostTask(
|
| + FROM_HERE, base::Bind(&SequencedTaskRunnerTestBase::RunTest,
|
| + base::Unretained(test.release())));
|
| + run_loop.Run();
|
| +}
|
|
|
| // TestSync and TestSyncMaster exercise Router and MultiplexRouter,
|
| // respectively.
|
| using InterfaceTypes = testing::Types<TestSync, TestSyncMaster>;
|
| TYPED_TEST_CASE(SyncMethodCommonTest, InterfaceTypes);
|
| +TYPED_TEST_CASE(SyncMethodCommonOnSequencedTaskRunnerCommonTest,
|
| + InterfaceTypes);
|
|
|
| TYPED_TEST(SyncMethodCommonTest, CallSyncMethodAsynchronously) {
|
| InterfacePtr<TypeParam> ptr;
|
| @@ -350,11 +478,49 @@ TYPED_TEST(SyncMethodCommonTest, CallSyncMethodAsynchronously) {
|
| run_loop.Run();
|
| }
|
|
|
| +#define SEQUENCED_TASK_RUNNER_TYPED_TEST_NAME(fixture_name, name) \
|
| + fixture_name##name##_SequencedTaskRunnerTestSuffix
|
| +
|
| +#define SEQUENCED_TASK_RUNNER_TYPED_TEST(base_fixture, fixture_name, name) \
|
| + template <typename TypeParam> \
|
| + class SEQUENCED_TASK_RUNNER_TYPED_TEST_NAME(fixture_name, name) \
|
| + : public fixture_name<TypeParam> { \
|
| + void Run() override; \
|
| + }; \
|
| + TYPED_TEST(base_fixture, name) { \
|
| + RunTestOnSequencedTaskRunner( \
|
| + base::MakeUnique<SEQUENCED_TASK_RUNNER_TYPED_TEST_NAME( \
|
| + fixture_name, name) < TypeParam>> ()); \
|
| + } \
|
| + template <typename TypeParam> \
|
| + void SEQUENCED_TASK_RUNNER_TYPED_TEST_NAME(fixture_name, \
|
| + name)<TypeParam>::Run()
|
| +
|
| +#define SEQUENCED_TASK_RUNNER_TYPED_TEST_F(base_fixture, fixture_name, name) \
|
| + template <typename TypeParam> \
|
| + class SEQUENCED_TASK_RUNNER_TYPED_TEST_NAME(fixture_name, name); \
|
| + TYPED_TEST(base_fixture, name) { \
|
| + RunTestOnSequencedTaskRunner( \
|
| + base::MakeUnique<SEQUENCED_TASK_RUNNER_TYPED_TEST_NAME( \
|
| + fixture_name, name) < TypeParam>> ()); \
|
| + } \
|
| + template <typename TypeParam> \
|
| + class SEQUENCED_TASK_RUNNER_TYPED_TEST_NAME(fixture_name, name) \
|
| + : public fixture_name<TypeParam>
|
| +
|
| +SEQUENCED_TASK_RUNNER_TYPED_TEST(
|
| + SyncMethodCommonOnSequencedTaskRunnerCommonTest,
|
| + SyncMethodCommonOnSequencedTaskRunnerTest,
|
| + CallSyncMethodAsynchronously) {
|
| + this->ptr_->Echo(
|
| + 123, base::Bind(&ExpectValueAndRunClosure, 123, this->DoneClosure()));
|
| +}
|
| +
|
| TYPED_TEST(SyncMethodCommonTest, BasicSyncCalls) {
|
| InterfacePtr<TypeParam> ptr;
|
|
|
| TestSyncServiceThread<TypeParam> service_thread;
|
| - service_thread.thread()->task_runner()->PostTask(
|
| + service_thread.task_runner()->PostTask(
|
| FROM_HERE, base::Bind(&TestSyncServiceThread<TypeParam>::SetUp,
|
| base::Unretained(&service_thread),
|
| base::Passed(MakeRequest(&ptr))));
|
| @@ -366,13 +532,36 @@ TYPED_TEST(SyncMethodCommonTest, BasicSyncCalls) {
|
| ASSERT_EQ(42, output_value);
|
|
|
| base::RunLoop run_loop;
|
| - service_thread.thread()->task_runner()->PostTaskAndReply(
|
| + service_thread.task_runner()->PostTaskAndReply(
|
| FROM_HERE, base::Bind(&TestSyncServiceThread<TypeParam>::TearDown,
|
| base::Unretained(&service_thread)),
|
| run_loop.QuitClosure());
|
| run_loop.Run();
|
| }
|
|
|
| +TYPED_TEST(SyncMethodCommonTest, BasicSyncCallsOnSequencedTaskRunner) {
|
| + InterfacePtr<TypeParam> ptr;
|
| +
|
| + TestSyncServiceSequencedPool<TypeParam> service_pool;
|
| + service_pool.task_runner()->PostTask(
|
| + FROM_HERE, base::Bind(&TestSyncServiceSequencedPool<TypeParam>::SetUp,
|
| + base::Unretained(&service_pool),
|
| + base::Passed(MakeRequest(&ptr))));
|
| + ASSERT_TRUE(ptr->Ping());
|
| + ASSERT_TRUE(service_pool.ping_called());
|
| +
|
| + int32_t output_value = -1;
|
| + ASSERT_TRUE(ptr->Echo(42, &output_value));
|
| + ASSERT_EQ(42, output_value);
|
| +
|
| + base::RunLoop run_loop;
|
| + service_pool.task_runner()->PostTaskAndReply(
|
| + FROM_HERE, base::Bind(&TestSyncServiceSequencedPool<TypeParam>::TearDown,
|
| + base::Unretained(&service_pool)),
|
| + run_loop.QuitClosure());
|
| + run_loop.Run();
|
| +}
|
| +
|
| TYPED_TEST(SyncMethodCommonTest, ReenteredBySyncMethodBinding) {
|
| // Test that an interface pointer waiting for a sync call response can be
|
| // reentered by a binding serving sync methods on the same thread.
|
| @@ -385,6 +574,19 @@ TYPED_TEST(SyncMethodCommonTest, ReenteredBySyncMethodBinding) {
|
| EXPECT_EQ(42, output_value);
|
| }
|
|
|
| +SEQUENCED_TASK_RUNNER_TYPED_TEST(
|
| + SyncMethodCommonOnSequencedTaskRunnerCommonTest,
|
| + SyncMethodCommonOnSequencedTaskRunnerTest,
|
| + ReenteredBySyncMethodBinding) {
|
| + // Test that an interface pointer waiting for a sync call response can be
|
| + // reentered by a binding serving sync methods on the same thread.
|
| +
|
| + int32_t output_value = -1;
|
| + ASSERT_TRUE(this->ptr_->Echo(42, &output_value));
|
| + EXPECT_EQ(42, output_value);
|
| + this->Done();
|
| +}
|
| +
|
| TYPED_TEST(SyncMethodCommonTest, InterfacePtrDestroyedDuringSyncCall) {
|
| // Test that it won't result in crash or hang if an interface pointer is
|
| // destroyed while it is waiting for a sync call response.
|
| @@ -398,6 +600,22 @@ TYPED_TEST(SyncMethodCommonTest, InterfacePtrDestroyedDuringSyncCall) {
|
| ASSERT_FALSE(ptr->Ping());
|
| }
|
|
|
| +SEQUENCED_TASK_RUNNER_TYPED_TEST(
|
| + SyncMethodCommonOnSequencedTaskRunnerCommonTest,
|
| + SyncMethodCommonOnSequencedTaskRunnerTest,
|
| + InterfacePtrDestroyedDuringSyncCall) {
|
| + // Test that it won't result in crash or hang if an interface pointer is
|
| + // destroyed while it is waiting for a sync call response.
|
| +
|
| + auto* ptr = &this->ptr_;
|
| + this->impl_->set_ping_handler([ptr](const TestSync::PingCallback& callback) {
|
| + ptr->reset();
|
| + callback.Run();
|
| + });
|
| + ASSERT_FALSE(this->ptr_->Ping());
|
| + this->Done();
|
| +}
|
| +
|
| TYPED_TEST(SyncMethodCommonTest, BindingDestroyedDuringSyncCall) {
|
| // Test that it won't result in crash or hang if a binding is
|
| // closed (and therefore the message pipe handle is closed) while the
|
| @@ -412,6 +630,24 @@ TYPED_TEST(SyncMethodCommonTest, BindingDestroyedDuringSyncCall) {
|
| ASSERT_FALSE(ptr->Ping());
|
| }
|
|
|
| +SEQUENCED_TASK_RUNNER_TYPED_TEST(
|
| + SyncMethodCommonOnSequencedTaskRunnerCommonTest,
|
| + SyncMethodCommonOnSequencedTaskRunnerTest,
|
| + BindingDestroyedDuringSyncCall) {
|
| + // Test that it won't result in crash or hang if a binding is
|
| + // closed (and therefore the message pipe handle is closed) while the
|
| + // corresponding interface pointer is waiting for a sync call response.
|
| +
|
| + auto& impl = *this->impl_;
|
| + this->impl_->set_ping_handler(
|
| + [&impl](const TestSync::PingCallback& callback) {
|
| + impl.binding()->Close();
|
| + callback.Run();
|
| + });
|
| + ASSERT_FALSE(this->ptr_->Ping());
|
| + this->Done();
|
| +}
|
| +
|
| TYPED_TEST(SyncMethodCommonTest, NestedSyncCallsWithInOrderResponses) {
|
| // Test that we can call a sync method on an interface ptr, while there is
|
| // already a sync call ongoing. The responses arrive in order.
|
| @@ -438,6 +674,35 @@ TYPED_TEST(SyncMethodCommonTest, NestedSyncCallsWithInOrderResponses) {
|
| EXPECT_EQ(123, result_value);
|
| }
|
|
|
| +SEQUENCED_TASK_RUNNER_TYPED_TEST(
|
| + SyncMethodCommonOnSequencedTaskRunnerCommonTest,
|
| + SyncMethodCommonOnSequencedTaskRunnerTest,
|
| + NestedSyncCallsWithInOrderResponses) {
|
| + // Test that we can call a sync method on an interface ptr, while there is
|
| + // already a sync call ongoing. The responses arrive in order.
|
| +
|
| + // The same variable is used to store the output of the two sync calls, in
|
| + // order to test that responses are handled in the correct order.
|
| + int32_t result_value = -1;
|
| +
|
| + bool first_call = true;
|
| + auto& ptr = this->ptr_;
|
| + auto& impl = *this->impl_;
|
| + impl.set_echo_handler([&first_call, &ptr, &result_value](
|
| + int32_t value, const TestSync::EchoCallback& callback) {
|
| + if (first_call) {
|
| + first_call = false;
|
| + ASSERT_TRUE(ptr->Echo(456, &result_value));
|
| + EXPECT_EQ(456, result_value);
|
| + }
|
| + callback.Run(value);
|
| + });
|
| +
|
| + ASSERT_TRUE(ptr->Echo(123, &result_value));
|
| + EXPECT_EQ(123, result_value);
|
| + this->Done();
|
| +}
|
| +
|
| TYPED_TEST(SyncMethodCommonTest, NestedSyncCallsWithOutOfOrderResponses) {
|
| // Test that we can call a sync method on an interface ptr, while there is
|
| // already a sync call ongoing. The responses arrive out of order.
|
| @@ -464,6 +729,35 @@ TYPED_TEST(SyncMethodCommonTest, NestedSyncCallsWithOutOfOrderResponses) {
|
| EXPECT_EQ(123, result_value);
|
| }
|
|
|
| +SEQUENCED_TASK_RUNNER_TYPED_TEST(
|
| + SyncMethodCommonOnSequencedTaskRunnerCommonTest,
|
| + SyncMethodCommonOnSequencedTaskRunnerTest,
|
| + NestedSyncCallsWithOutOfOrderResponses) {
|
| + // Test that we can call a sync method on an interface ptr, while there is
|
| + // already a sync call ongoing. The responses arrive out of order.
|
| +
|
| + // The same variable is used to store the output of the two sync calls, in
|
| + // order to test that responses are handled in the correct order.
|
| + int32_t result_value = -1;
|
| +
|
| + bool first_call = true;
|
| + auto& ptr = this->ptr_;
|
| + auto& impl = *this->impl_;
|
| + impl.set_echo_handler([&first_call, &ptr, &result_value](
|
| + int32_t value, const TestSync::EchoCallback& callback) {
|
| + callback.Run(value);
|
| + if (first_call) {
|
| + first_call = false;
|
| + ASSERT_TRUE(ptr->Echo(456, &result_value));
|
| + EXPECT_EQ(456, result_value);
|
| + }
|
| + });
|
| +
|
| + ASSERT_TRUE(ptr->Echo(123, &result_value));
|
| + EXPECT_EQ(123, result_value);
|
| + this->Done();
|
| +}
|
| +
|
| TYPED_TEST(SyncMethodCommonTest, AsyncResponseQueuedDuringSyncCall) {
|
| // Test that while an interface pointer is waiting for the response to a sync
|
| // call, async responses are queued until the sync call completes.
|
| @@ -519,6 +813,54 @@ TYPED_TEST(SyncMethodCommonTest, AsyncResponseQueuedDuringSyncCall) {
|
| EXPECT_TRUE(async_echo_response_dispatched);
|
| }
|
|
|
| +SEQUENCED_TASK_RUNNER_TYPED_TEST_F(
|
| + SyncMethodCommonOnSequencedTaskRunnerCommonTest,
|
| + SyncMethodCommonOnSequencedTaskRunnerTest,
|
| + AsyncResponseQueuedDuringSyncCall) {
|
| + // Test that while an interface pointer is waiting for the response to a sync
|
| + // call, async responses are queued until the sync call completes.
|
| +
|
| + void Run() override {
|
| + this->impl_->set_async_echo_handler(
|
| + [this](int32_t value, const TestSync::AsyncEchoCallback& callback) {
|
| + async_echo_request_value_ = value;
|
| + async_echo_request_callback_ = callback;
|
| + OnAsyncEchoReceived();
|
| + });
|
| +
|
| + this->ptr_->AsyncEcho(123, BindAsyncEchoCallback([this](int32_t result) {
|
| + async_echo_response_dispatched_ = true;
|
| + EXPECT_EQ(123, result);
|
| + EXPECT_TRUE(async_echo_response_dispatched_);
|
| + this->Done();
|
| + }));
|
| + }
|
| +
|
| + // Called when the AsyncEcho request reaches the service side.
|
| + void OnAsyncEchoReceived() {
|
| + this->impl_->set_echo_handler(
|
| + [this](int32_t value, const TestSync::EchoCallback& callback) {
|
| + // Send back the async response first.
|
| + EXPECT_FALSE(async_echo_request_callback_.is_null());
|
| + async_echo_request_callback_.Run(async_echo_request_value_);
|
| +
|
| + callback.Run(value);
|
| + });
|
| +
|
| + int32_t result_value = -1;
|
| + ASSERT_TRUE(this->ptr_->Echo(456, &result_value));
|
| + EXPECT_EQ(456, result_value);
|
| +
|
| + // Although the AsyncEcho response arrives before the Echo response, it
|
| + // should be queued and not yet dispatched.
|
| + EXPECT_FALSE(async_echo_response_dispatched_);
|
| + }
|
| +
|
| + int32_t async_echo_request_value_ = -1;
|
| + TestSync::AsyncEchoCallback async_echo_request_callback_;
|
| + bool async_echo_response_dispatched_ = false;
|
| +};
|
| +
|
| TYPED_TEST(SyncMethodCommonTest, AsyncRequestQueuedDuringSyncCall) {
|
| // Test that while an interface pointer is waiting for the response to a sync
|
| // call, async requests for a binding running on the same thread are queued
|
| @@ -568,6 +910,46 @@ TYPED_TEST(SyncMethodCommonTest, AsyncRequestQueuedDuringSyncCall) {
|
| EXPECT_TRUE(async_echo_response_dispatched);
|
| }
|
|
|
| +SEQUENCED_TASK_RUNNER_TYPED_TEST_F(
|
| + SyncMethodCommonOnSequencedTaskRunnerCommonTest,
|
| + SyncMethodCommonOnSequencedTaskRunnerTest,
|
| + AsyncRequestQueuedDuringSyncCall) {
|
| + // Test that while an interface pointer is waiting for the response to a sync
|
| + // call, async requests for a binding running on the same thread are queued
|
| + // until the sync call completes.
|
| + void Run() override {
|
| + this->impl_->set_async_echo_handler(
|
| + [this](int32_t value, const TestSync::AsyncEchoCallback& callback) {
|
| + async_echo_request_dispatched_ = true;
|
| + callback.Run(value);
|
| + });
|
| +
|
| + this->ptr_->AsyncEcho(123, BindAsyncEchoCallback([this](int32_t result) {
|
| + EXPECT_EQ(123, result);
|
| + this->Done();
|
| + }));
|
| +
|
| + this->impl_->set_echo_handler(
|
| + [this](int32_t value, const TestSync::EchoCallback& callback) {
|
| + // Although the AsyncEcho request is sent before the Echo request, it
|
| + // shouldn't be dispatched yet at this point, because there is an
|
| + // ongoing
|
| + // sync call on the same thread.
|
| + EXPECT_FALSE(async_echo_request_dispatched_);
|
| + callback.Run(value);
|
| + });
|
| +
|
| + int32_t result_value = -1;
|
| + ASSERT_TRUE(this->ptr_->Echo(456, &result_value));
|
| + EXPECT_EQ(456, result_value);
|
| +
|
| + // Although the AsyncEcho request is sent before the Echo request, it
|
| + // shouldn't be dispatched yet.
|
| + EXPECT_FALSE(async_echo_request_dispatched_);
|
| + }
|
| + bool async_echo_request_dispatched_ = false;
|
| +};
|
| +
|
| TYPED_TEST(SyncMethodCommonTest,
|
| QueuedMessagesProcessedBeforeErrorNotification) {
|
| // Test that while an interface pointer is waiting for the response to a sync
|
| @@ -592,19 +974,17 @@ TYPED_TEST(SyncMethodCommonTest,
|
| bool async_echo_response_dispatched = false;
|
| bool connection_error_dispatched = false;
|
| base::RunLoop run_loop2;
|
| - ptr->AsyncEcho(
|
| - 123,
|
| - BindAsyncEchoCallback(
|
| - [&async_echo_response_dispatched, &connection_error_dispatched, &ptr,
|
| - &run_loop2](int32_t result) {
|
| - async_echo_response_dispatched = true;
|
| - // At this point, error notification should not be dispatched
|
| - // yet.
|
| - EXPECT_FALSE(connection_error_dispatched);
|
| - EXPECT_FALSE(ptr.encountered_error());
|
| - EXPECT_EQ(123, result);
|
| - run_loop2.Quit();
|
| - }));
|
| + ptr->AsyncEcho(123, BindAsyncEchoCallback([&async_echo_response_dispatched,
|
| + &connection_error_dispatched, &ptr,
|
| + &run_loop2](int32_t result) {
|
| + async_echo_response_dispatched = true;
|
| + // At this point, error notification should not be dispatched
|
| + // yet.
|
| + EXPECT_FALSE(connection_error_dispatched);
|
| + EXPECT_FALSE(ptr.encountered_error());
|
| + EXPECT_EQ(123, result);
|
| + run_loop2.Quit();
|
| + }));
|
| // Run until the AsyncEcho request reaches the service side.
|
| run_loop1.Run();
|
|
|
| @@ -619,9 +999,9 @@ TYPED_TEST(SyncMethodCommonTest,
|
| });
|
|
|
| base::RunLoop run_loop3;
|
| - ptr.set_connection_error_handler(
|
| - base::Bind(&SetFlagAndRunClosure, &connection_error_dispatched,
|
| - run_loop3.QuitClosure()));
|
| + ptr.set_connection_error_handler(base::Bind(&SetFlagAndRunClosure,
|
| + &connection_error_dispatched,
|
| + run_loop3.QuitClosure()));
|
|
|
| int32_t result_value = -1;
|
| ASSERT_FALSE(ptr->Echo(456, &result_value));
|
| @@ -645,6 +1025,75 @@ TYPED_TEST(SyncMethodCommonTest,
|
| EXPECT_TRUE(ptr.encountered_error());
|
| }
|
|
|
| +SEQUENCED_TASK_RUNNER_TYPED_TEST_F(
|
| + SyncMethodCommonOnSequencedTaskRunnerCommonTest,
|
| + SyncMethodCommonOnSequencedTaskRunnerTest,
|
| + QueuedMessagesProcessedBeforeErrorNotification) {
|
| + // Test that while an interface pointer is waiting for the response to a sync
|
| + // call, async responses are queued. If the message pipe is disconnected
|
| + // before the queued messages are processed, the connection error
|
| + // notification is delayed until all the queued messages are processed.
|
| +
|
| + void Run() override {
|
| + this->impl_->set_async_echo_handler(
|
| + [this](int32_t value, const TestSync::AsyncEchoCallback& callback) {
|
| + async_echo_request_value_ = value;
|
| + async_echo_request_callback_ = callback;
|
| + Run2();
|
| + });
|
| +
|
| + this->ptr_->AsyncEcho(123, BindAsyncEchoCallback([this](int32_t result) {
|
| + async_echo_response_dispatched_ = true;
|
| + // At this point, error notification should not be
|
| + // dispatched
|
| + // yet.
|
| + EXPECT_FALSE(connection_error_dispatched_);
|
| + EXPECT_FALSE(this->ptr_.encountered_error());
|
| + EXPECT_EQ(123, result);
|
| + EXPECT_TRUE(async_echo_response_dispatched_);
|
| + }));
|
| + }
|
| +
|
| + // Invoked when the AsyncEcho request reaches the service side.
|
| + void Run2() {
|
| + this->impl_->set_echo_handler(
|
| + [this](int32_t value, const TestSync::EchoCallback& callback) {
|
| + // Send back the async response first.
|
| + EXPECT_FALSE(async_echo_request_callback_.is_null());
|
| + async_echo_request_callback_.Run(async_echo_request_value_);
|
| +
|
| + this->impl_->binding()->Close();
|
| + });
|
| +
|
| + this->ptr_.set_connection_error_handler(
|
| + base::Bind(&SetFlagAndRunClosure, &connection_error_dispatched_,
|
| + LambdaBinder<>::BindLambda([this]() { Run4(); })));
|
| +
|
| + int32_t result_value = -1;
|
| + ASSERT_FALSE(this->ptr_->Echo(456, &result_value));
|
| + EXPECT_EQ(-1, result_value);
|
| + ASSERT_FALSE(connection_error_dispatched_);
|
| + EXPECT_FALSE(this->ptr_.encountered_error());
|
| +
|
| + // Although the AsyncEcho response arrives before the Echo response, it
|
| + // should
|
| + // be queued and not yet dispatched.
|
| + EXPECT_FALSE(async_echo_response_dispatched_);
|
| + }
|
| +
|
| + // Invoked when the error notification is dispatched.
|
| + void Run4() {
|
| + ASSERT_TRUE(connection_error_dispatched_);
|
| + EXPECT_TRUE(this->ptr_.encountered_error());
|
| + this->Done();
|
| + }
|
| +
|
| + int32_t async_echo_request_value_ = -1;
|
| + TestSync::AsyncEchoCallback async_echo_request_callback_;
|
| + bool async_echo_response_dispatched_ = false;
|
| + bool connection_error_dispatched_ = false;
|
| +};
|
| +
|
| TYPED_TEST(SyncMethodCommonTest, InvalidMessageDuringSyncCall) {
|
| // Test that while an interface pointer is waiting for the response to a sync
|
| // call, an invalid incoming message will disconnect the message pipe, cause
|
| @@ -686,6 +1135,49 @@ TYPED_TEST(SyncMethodCommonTest, InvalidMessageDuringSyncCall) {
|
| ASSERT_TRUE(connection_error_dispatched);
|
| }
|
|
|
| +SEQUENCED_TASK_RUNNER_TYPED_TEST_F(
|
| + SyncMethodCommonOnSequencedTaskRunnerCommonTest,
|
| + SyncMethodCommonOnSequencedTaskRunnerTest,
|
| + InvalidMessageDuringSyncCall) {
|
| + // Test that while an interface pointer is waiting for the response to a sync
|
| + // call, an invalid incoming message will disconnect the message pipe, cause
|
| + // the sync call to return false, and run the connection error handler
|
| + // asynchronously.
|
| +
|
| + void Run() override {
|
| + MessagePipe pipe;
|
| +
|
| + this->ptr_.Bind(InterfacePtrInfo<TypeParam>(std::move(pipe.handle0), 0u));
|
| +
|
| + MessagePipeHandle raw_binding_handle = pipe.handle1.get();
|
| + this->impl_ = base::MakeUnique<typename ImplTraits<TypeParam>::Type>(
|
| + MakeRequest<TypeParam>(std::move(pipe.handle1)));
|
| +
|
| + this->impl_->set_echo_handler([raw_binding_handle](
|
| + int32_t value, const TestSync::EchoCallback& callback) {
|
| + // Write a 1-byte message, which is considered invalid.
|
| + char invalid_message = 0;
|
| + MojoResult result =
|
| + WriteMessageRaw(raw_binding_handle, &invalid_message, 1u, nullptr, 0u,
|
| + MOJO_WRITE_MESSAGE_FLAG_NONE);
|
| + ASSERT_EQ(MOJO_RESULT_OK, result);
|
| + callback.Run(value);
|
| + });
|
| +
|
| + this->ptr_.set_connection_error_handler(
|
| + LambdaBinder<>::BindLambda([this]() {
|
| + connection_error_dispatched_ = true;
|
| + this->Done();
|
| + }));
|
| +
|
| + int32_t result_value = -1;
|
| + ASSERT_FALSE(this->ptr_->Echo(456, &result_value));
|
| + EXPECT_EQ(-1, result_value);
|
| + ASSERT_FALSE(connection_error_dispatched_);
|
| + }
|
| + bool connection_error_dispatched_ = false;
|
| +};
|
| +
|
| TEST_F(SyncMethodAssociatedTest, ReenteredBySyncMethodAssoBindingOfSameRouter) {
|
| // Test that an interface pointer waiting for a sync call response can be
|
| // reentered by an associated binding serving sync methods on the same thread.
|
|
|