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 207a6e2bd6843def5589bb21e9e6eec44576ee43..f1a47674f5c5baa13afd86c0c1f42fb17d74bfe2 100644 |
--- a/mojo/public/cpp/bindings/tests/sync_method_unittest.cc |
+++ b/mojo/public/cpp/bindings/tests/sync_method_unittest.cc |
@@ -345,6 +345,120 @@ TEST_F(SyncMethodTest, AsyncRequestQueuedDuringSyncCall) { |
EXPECT_TRUE(async_echo_response_dispatched); |
} |
+TEST_F(SyncMethodTest, 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. |
+ |
+ 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( |
+ [&impl, &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); |
+ |
+ impl.binding()->Close(); |
+ }); |
+ |
+ bool connection_error_dispatched = false; |
+ base::RunLoop run_loop3; |
+ ptr.set_connection_error_handler( |
+ [&connection_error_dispatched, &run_loop3]() { |
+ connection_error_dispatched = true; |
+ run_loop3.Quit(); |
+ }); |
+ |
+ int32_t result_value = -1; |
+ ASSERT_FALSE(ptr->Echo(456, &result_value)); |
+ EXPECT_EQ(-1, result_value); |
+ ASSERT_FALSE(connection_error_dispatched); |
+ EXPECT_FALSE(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); |
+ |
+ // Run until the AsyncEcho response is dispatched. |
+ run_loop2.Run(); |
+ |
+ EXPECT_TRUE(async_echo_response_dispatched); |
+ ASSERT_FALSE(connection_error_dispatched); |
+ EXPECT_FALSE(ptr.encountered_error()); |
+ |
+ // Run until the error notification is dispatched. |
+ run_loop3.Run(); |
+ |
+ ASSERT_TRUE(connection_error_dispatched); |
+ EXPECT_TRUE(ptr.encountered_error()); |
+} |
+ |
+TEST_F(SyncMethodTest, 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. |
+ |
+ MessagePipe pipe; |
+ |
+ TestSyncPtr ptr; |
+ ptr.Bind(TestSyncPtrInfo(std::move(pipe.handle0), 0u)); |
+ |
+ MessagePipeHandle raw_binding_handle = pipe.handle1.get(); |
+ TestSyncImpl impl(MakeRequest<TestSync>(std::move(pipe.handle1))); |
+ |
+ 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); |
+ }); |
+ |
+ bool connection_error_dispatched = false; |
+ base::RunLoop run_loop; |
+ ptr.set_connection_error_handler([&connection_error_dispatched, &run_loop]() { |
+ connection_error_dispatched = true; |
+ run_loop.Quit(); |
+ }); |
+ |
+ int32_t result_value = -1; |
+ ASSERT_FALSE(ptr->Echo(456, &result_value)); |
+ EXPECT_EQ(-1, result_value); |
+ ASSERT_FALSE(connection_error_dispatched); |
+ |
+ run_loop.Run(); |
+ ASSERT_TRUE(connection_error_dispatched); |
+} |
+ |
} // namespace |
} // namespace test |
} // namespace mojo |