Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(139)

Unified Diff: mojo/public/cpp/bindings/tests/sync_method_unittest.cc

Issue 1713203002: Mojo C++ bindings: support sync methods - part 2 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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 fd519b0f4df83b12cb62dd7acf23901cd1f45374..207a6e2bd6843def5589bb21e9e6eec44576ee43 100644
--- a/mojo/public/cpp/bindings/tests/sync_method_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/sync_method_unittest.cc
@@ -30,26 +30,47 @@ class TestSyncImpl : public TestSync {
public:
TestSyncImpl(TestSyncRequest request) : binding_(this, std::move(request)) {}
- void set_ping_notification(const Closure& closure) {
- ping_notification_ = closure;
+ using PingHandler = Callback<void(const PingCallback&)>;
+ void set_ping_handler(const PingHandler& handler) { ping_handler_ = handler; }
+
+ using EchoHandler = Callback<void(int32_t, const EchoCallback&)>;
+ void set_echo_handler(const EchoHandler& handler) { echo_handler_ = handler; }
+
+ using AsyncEchoHandler = Callback<void(int32_t, const AsyncEchoCallback&)>;
+ void set_async_echo_handler(const AsyncEchoHandler& handler) {
+ async_echo_handler_ = handler;
}
// TestSync implementation:
- void Get(const GetCallback& callback) override { callback.Run(42); }
- void Set(int32_t value, const SetCallback& callback) override {
- callback.Run();
- }
void Ping(const PingCallback& callback) override {
- ping_notification_.Run();
- callback.Run();
+ if (ping_handler_.is_null()) {
+ callback.Run();
+ return;
+ }
+ ping_handler_.Run(callback);
}
void Echo(int32_t value, const EchoCallback& callback) override {
- callback.Run(value);
+ if (echo_handler_.is_null()) {
+ callback.Run(value);
+ return;
+ }
+ echo_handler_.Run(value, callback);
+ }
+ void AsyncEcho(int32_t value, const AsyncEchoCallback& callback) override {
+ if (async_echo_handler_.is_null()) {
+ callback.Run(value);
+ return;
+ }
+ async_echo_handler_.Run(value, callback);
}
+ Binding<TestSync>* binding() { return &binding_; }
+
private:
Binding<TestSync> binding_;
- Closure ping_notification_;
+ PingHandler ping_handler_;
+ EchoHandler echo_handler_;
+ AsyncEchoHandler async_echo_handler_;
DISALLOW_COPY_AND_ASSIGN(TestSyncImpl);
};
@@ -67,9 +88,12 @@ class TestSyncServiceThread {
void SetUp(TestSyncRequest request) {
CHECK(thread_.task_runner()->BelongsToCurrentThread());
impl_.reset(new TestSyncImpl(std::move(request)));
- impl_->set_ping_notification([this]() {
- base::AutoLock locker(lock_);
- ping_called_ = true;
+ impl_->set_ping_handler([this](const TestSync::PingCallback& callback) {
+ {
+ base::AutoLock locker(lock_);
+ ping_called_ = true;
+ }
+ callback.Run();
});
}
@@ -130,6 +154,197 @@ TEST_F(SyncMethodTest, BasicSyncCalls) {
run_loop.Run();
}
+TEST_F(SyncMethodTest, 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.
+
+ TestSyncPtr ptr;
+ // The binding lives on the same thread as the interface pointer.
+ TestSyncImpl impl(GetProxy(&ptr));
+ int32_t output_value = -1;
+ ASSERT_TRUE(ptr->Echo(42, &output_value));
+ EXPECT_EQ(42, output_value);
+}
+
+TEST_F(SyncMethodTest, InterefacePtrDestroyedDuringSyncCall) {
+ // 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.
+
+ TestSyncPtr ptr;
+ TestSyncImpl impl(GetProxy(&ptr));
+ impl.set_ping_handler([&ptr](const TestSync::PingCallback& callback) {
+ ptr.reset();
+ callback.Run();
+ });
+ ASSERT_FALSE(ptr->Ping());
+}
+
+TEST_F(SyncMethodTest, 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.
+
+ TestSyncPtr ptr;
+ TestSyncImpl impl(GetProxy(&ptr));
+ impl.set_ping_handler([&impl](const TestSync::PingCallback& callback) {
+ impl.binding()->Close();
+ callback.Run();
+ });
+ ASSERT_FALSE(ptr->Ping());
+}
+
+TEST_F(SyncMethodTest, 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.
+
+ TestSyncPtr ptr;
+ TestSyncImpl impl(GetProxy(&ptr));
+
+ // 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;
+ 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);
+}
+
+TEST_F(SyncMethodTest, 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.
+
+ TestSyncPtr ptr;
+ TestSyncImpl impl(GetProxy(&ptr));
+
+ // 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;
+ 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);
+}
+
+TEST_F(SyncMethodTest, 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.
+
+ TestSyncPtr ptr;
+ TestSyncImpl impl(GetProxy(&ptr));
+
+ int32_t async_echo_request_value = -1;
+ TestSync::AsyncEchoCallback async_echo_request_callback;
+ base::RunLoop run_loop1;
+ impl.set_async_echo_handler(
+ [&async_echo_request_value, &async_echo_request_callback, &run_loop1](
+ int32_t value, const TestSync::AsyncEchoCallback& callback) {
+ async_echo_request_value = value;
+ async_echo_request_callback = callback;
+ run_loop1.Quit();
+ });
+
+ bool async_echo_response_dispatched = false;
+ base::RunLoop run_loop2;
+ ptr->AsyncEcho(123,
+ [&async_echo_response_dispatched, &run_loop2](int32_t result) {
+ async_echo_response_dispatched = true;
+ EXPECT_EQ(123, result);
+ run_loop2.Quit();
+ });
+ // Run until the AsyncEcho request reaches the service side.
+ run_loop1.Run();
+
+ impl.set_echo_handler(
+ [&async_echo_request_value, &async_echo_request_callback](
+ 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(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);
+
+ // Run until the AsyncEcho response is dispatched.
+ run_loop2.Run();
+
+ EXPECT_TRUE(async_echo_response_dispatched);
+}
+
+TEST_F(SyncMethodTest, 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.
+
+ TestSyncPtr ptr;
+ TestSyncImpl impl(GetProxy(&ptr));
+
+ bool async_echo_request_dispatched = false;
+ impl.set_async_echo_handler([&async_echo_request_dispatched](
+ int32_t value, const TestSync::AsyncEchoCallback& callback) {
+ async_echo_request_dispatched = true;
+ callback.Run(value);
+ });
+
+ bool async_echo_response_dispatched = false;
+ base::RunLoop run_loop;
+ ptr->AsyncEcho(123,
+ [&async_echo_response_dispatched, &run_loop](int32_t result) {
+ async_echo_response_dispatched = true;
+ EXPECT_EQ(123, result);
+ run_loop.Quit();
+ });
+
+ impl.set_echo_handler([&async_echo_request_dispatched](
+ 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(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);
+
+ // Run until the AsyncEcho response is dispatched.
+ run_loop.Run();
+
+ EXPECT_TRUE(async_echo_response_dispatched);
+}
+
} // namespace
} // namespace test
} // namespace mojo
« no previous file with comments | « mojo/public/cpp/bindings/tests/router_unittest.cc ('k') | mojo/public/interfaces/bindings/tests/test_sync_methods.mojom » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698