Index: mojo/edk/system/multiprocess_message_pipe_unittest.cc |
diff --git a/mojo/edk/system/multiprocess_message_pipe_unittest.cc b/mojo/edk/system/multiprocess_message_pipe_unittest.cc |
index 40622321e87503defa9af6b03f19c227647efa92..00c2ab564d4c3df196c0c93d337e1f99a6430b2e 100644 |
--- a/mojo/edk/system/multiprocess_message_pipe_unittest.cc |
+++ b/mojo/edk/system/multiprocess_message_pipe_unittest.cc |
@@ -6,29 +6,27 @@ |
#include <stdint.h> |
#include <stdio.h> |
#include <string.h> |
+ |
#include <string> |
#include <utility> |
#include <vector> |
-#include "base/bind.h" |
+#include "base/containers/hash_tables.h" |
#include "base/files/file_path.h" |
#include "base/files/file_util.h" |
#include "base/files/scoped_file.h" |
#include "base/files/scoped_temp_dir.h" |
-#include "base/location.h" |
#include "base/logging.h" |
+#include "base/strings/string_split.h" |
#include "build/build_config.h" |
-#include "mojo/edk/embedder/embedder.h" |
-#include "mojo/edk/embedder/platform_channel_pair.h" |
-#include "mojo/edk/embedder/platform_shared_buffer.h" |
#include "mojo/edk/embedder/scoped_platform_handle.h" |
-#include "mojo/edk/system/dispatcher.h" |
-#include "mojo/edk/system/message_pipe_test_utils.h" |
-#include "mojo/edk/system/platform_handle_dispatcher.h" |
-#include "mojo/edk/system/raw_channel.h" |
-#include "mojo/edk/system/shared_buffer_dispatcher.h" |
+#include "mojo/edk/system/handle_signals_state.h" |
#include "mojo/edk/system/test_utils.h" |
+#include "mojo/edk/test/mojo_test_base.h" |
#include "mojo/edk/test/test_utils.h" |
+#include "mojo/public/c/system/buffer.h" |
+#include "mojo/public/c/system/functions.h" |
+#include "mojo/public/c/system/types.h" |
#include "testing/gtest/include/gtest/gtest.h" |
@@ -36,27 +34,50 @@ namespace mojo { |
namespace edk { |
namespace { |
-class MultiprocessMessagePipeTest |
- : public test::MultiprocessMessagePipeTestBase {}; |
+class MultiprocessMessagePipeTest : public test::MojoTestBase { |
+ protected: |
+ // Convenience class for tests which will control command-driven children. |
+ // See the CommandDrivenClient definition below. |
+ class CommandDrivenClientController { |
+ public: |
+ explicit CommandDrivenClientController(MojoHandle h) : h_(h) {} |
+ |
+ void Send(const std::string& command) { |
+ WriteMessage(h_, command); |
+ EXPECT_EQ("ok", ReadMessage(h_)); |
+ } |
+ |
+ void SendHandle(const std::string& name, MojoHandle p) { |
+ WriteMessageWithHandles(h_, "take:" + name, &p, 1); |
+ EXPECT_EQ("ok", ReadMessage(h_)); |
+ } |
+ |
+ MojoHandle RetrieveHandle(const std::string& name) { |
+ WriteMessage(h_, "return:" + name); |
+ MojoHandle p; |
+ EXPECT_EQ("ok", ReadMessageWithHandles(h_, &p, 1)); |
+ return p; |
+ } |
+ |
+ void Exit() { WriteMessage(h_, "exit"); } |
+ |
+ private: |
+ MojoHandle h_; |
+ }; |
+}; |
// For each message received, sends a reply message with the same contents |
// repeated twice, until the other end is closed or it receives "quitquitquit" |
// (which it doesn't reply to). It'll return the number of messages received, |
// not including any "quitquitquit" message, modulo 100. |
-MOJO_MULTIPROCESS_TEST_CHILD_MAIN(EchoEcho) { |
- ScopedPlatformHandle client_platform_handle = |
- std::move(test::MultiprocessTestHelper::client_platform_handle); |
- CHECK(client_platform_handle.is_valid()); |
- ScopedMessagePipeHandle mp = |
- CreateMessagePipe(std::move(client_platform_handle)); |
- |
+DEFINE_TEST_CLIENT_WITH_PIPE(EchoEcho, MultiprocessMessagePipeTest, h) { |
const std::string quitquitquit("quitquitquit"); |
int rv = 0; |
for (;; rv = (rv + 1) % 100) { |
// Wait for our end of the message pipe to be readable. |
HandleSignalsState hss; |
MojoResult result = |
- MojoWait(mp.get().value(), MOJO_HANDLE_SIGNAL_READABLE, |
+ MojoWait(h, MOJO_HANDLE_SIGNAL_READABLE, |
MOJO_DEADLINE_INDEFINITE, &hss); |
if (result != MOJO_RESULT_OK) { |
// It was closed, probably. |
@@ -71,7 +92,7 @@ MOJO_MULTIPROCESS_TEST_CHILD_MAIN(EchoEcho) { |
std::string read_buffer(1000, '\0'); |
uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size()); |
- CHECK_EQ(MojoReadMessage(mp.get().value(), &read_buffer[0], |
+ CHECK_EQ(MojoReadMessage(h, &read_buffer[0], |
&read_buffer_size, nullptr, |
0, MOJO_READ_MESSAGE_FLAG_NONE), |
MOJO_RESULT_OK); |
@@ -84,13 +105,13 @@ MOJO_MULTIPROCESS_TEST_CHILD_MAIN(EchoEcho) { |
} |
std::string write_buffer = read_buffer + read_buffer; |
- CHECK_EQ(MojoWriteMessage(mp.get().value(), write_buffer.data(), |
+ CHECK_EQ(MojoWriteMessage(h, write_buffer.data(), |
static_cast<uint32_t>(write_buffer.size()), |
nullptr, 0u, MOJO_WRITE_MESSAGE_FLAG_NONE), |
MOJO_RESULT_OK); |
} |
- return rv; |
+ return rv; |
} |
// Sends "hello" to child, and expects "hellohello" back. |
@@ -101,41 +122,39 @@ MOJO_MULTIPROCESS_TEST_CHILD_MAIN(EchoEcho) { |
#define MAYBE_Basic Basic |
#endif // defined(OS_ANDROID) |
TEST_F(MultiprocessMessagePipeTest, MAYBE_Basic) { |
- helper()->StartChild("EchoEcho"); |
- |
- ScopedMessagePipeHandle mp = |
- CreateMessagePipe(std::move(helper()->server_platform_handle)); |
- |
- std::string hello("hello"); |
- ASSERT_EQ(MOJO_RESULT_OK, |
- MojoWriteMessage(mp.get().value(), hello.data(), |
- static_cast<uint32_t>(hello.size()), nullptr, 0u, |
- MOJO_WRITE_MESSAGE_FLAG_NONE)); |
+ RUN_CHILD_ON_PIPE(EchoEcho, h) |
+ std::string hello("hello"); |
+ ASSERT_EQ(MOJO_RESULT_OK, |
+ MojoWriteMessage(h, hello.data(), |
+ static_cast<uint32_t>(hello.size()), nullptr, 0u, |
+ MOJO_WRITE_MESSAGE_FLAG_NONE)); |
- HandleSignalsState hss; |
- ASSERT_EQ(MOJO_RESULT_OK, |
- MojoWait(mp.get().value(), MOJO_HANDLE_SIGNAL_READABLE, |
- MOJO_DEADLINE_INDEFINITE, &hss)); |
- // The child may or may not have closed its end of the message pipe and died |
- // (and we may or may not know it yet), so our end may or may not appear as |
- // writable. |
- EXPECT_TRUE((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE)); |
- EXPECT_TRUE((hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE)); |
- |
- std::string read_buffer(1000, '\0'); |
- uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size()); |
- CHECK_EQ(MojoReadMessage(mp.get().value(), &read_buffer[0], |
- &read_buffer_size, nullptr, 0, |
- MOJO_READ_MESSAGE_FLAG_NONE), |
- MOJO_RESULT_OK); |
- read_buffer.resize(read_buffer_size); |
- VLOG(2) << "Parent got: " << read_buffer; |
- ASSERT_EQ(hello + hello, read_buffer); |
+ HandleSignalsState hss; |
+ ASSERT_EQ(MOJO_RESULT_OK, |
+ MojoWait(h, MOJO_HANDLE_SIGNAL_READABLE, |
+ MOJO_DEADLINE_INDEFINITE, &hss)); |
+ // The child may or may not have closed its end of the message pipe and died |
+ // (and we may or may not know it yet), so our end may or may not appear as |
+ // writable. |
+ EXPECT_TRUE((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE)); |
+ EXPECT_TRUE((hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE)); |
- MojoClose(mp.release().value()); |
+ std::string read_buffer(1000, '\0'); |
+ uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size()); |
+ CHECK_EQ(MojoReadMessage(h, &read_buffer[0], |
+ &read_buffer_size, nullptr, 0, |
+ MOJO_READ_MESSAGE_FLAG_NONE), |
+ MOJO_RESULT_OK); |
+ read_buffer.resize(read_buffer_size); |
+ VLOG(2) << "Parent got: " << read_buffer; |
+ ASSERT_EQ(hello + hello, read_buffer); |
- // We sent one message. |
- ASSERT_EQ(1 % 100, helper()->WaitForChildShutdown()); |
+ std::string quitquitquit("quitquitquit"); |
+ CHECK_EQ(MojoWriteMessage(h, quitquitquit.data(), |
+ static_cast<uint32_t>(quitquitquit.size()), |
+ nullptr, 0u, MOJO_WRITE_MESSAGE_FLAG_NONE), |
+ MOJO_RESULT_OK); |
+ END_CHILD_AND_EXPECT_EXIT_CODE(1 % 100); |
} |
// Sends a bunch of messages to the child. Expects them "repeated" back. Waits |
@@ -147,71 +166,60 @@ TEST_F(MultiprocessMessagePipeTest, MAYBE_Basic) { |
#define MAYBE_QueueMessages QueueMessages |
#endif // defined(OS_ANDROID) |
TEST_F(MultiprocessMessagePipeTest, MAYBE_QueueMessages) { |
- helper()->StartChild("EchoEcho"); |
+ static const size_t kNumMessages = 1001; |
+ RUN_CHILD_ON_PIPE(EchoEcho, h) |
+ for (size_t i = 0; i < kNumMessages; i++) { |
+ std::string write_buffer(i, 'A' + (i % 26)); |
+ ASSERT_EQ(MOJO_RESULT_OK, |
+ MojoWriteMessage(h, write_buffer.data(), |
+ static_cast<uint32_t>(write_buffer.size()), |
+ nullptr, 0u, MOJO_WRITE_MESSAGE_FLAG_NONE)); |
+ } |
- ScopedMessagePipeHandle mp = |
- CreateMessagePipe(std::move(helper()->server_platform_handle)); |
+ for (size_t i = 0; i < kNumMessages; i++) { |
+ HandleSignalsState hss; |
+ ASSERT_EQ(MOJO_RESULT_OK, |
+ MojoWait(h, MOJO_HANDLE_SIGNAL_READABLE, |
+ MOJO_DEADLINE_INDEFINITE, &hss)); |
+ // The child may or may not have closed its end of the message pipe and |
+ // died (and we may or may not know it yet), so our end may or may not |
+ // appear as writable. |
+ ASSERT_TRUE((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE)); |
+ ASSERT_TRUE((hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE)); |
+ |
+ std::string read_buffer(kNumMessages * 2, '\0'); |
+ uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size()); |
+ ASSERT_EQ(MojoReadMessage(h, &read_buffer[0], |
+ &read_buffer_size, nullptr, 0, |
+ MOJO_READ_MESSAGE_FLAG_NONE), |
+ MOJO_RESULT_OK); |
+ read_buffer.resize(read_buffer_size); |
+ |
+ ASSERT_EQ(std::string(i * 2, 'A' + (i % 26)), read_buffer); |
+ } |
- static const size_t kNumMessages = 1001; |
- for (size_t i = 0; i < kNumMessages; i++) { |
- std::string write_buffer(i, 'A' + (i % 26)); |
+ const std::string quitquitquit("quitquitquit"); |
ASSERT_EQ(MOJO_RESULT_OK, |
- MojoWriteMessage(mp.get().value(), write_buffer.data(), |
- static_cast<uint32_t>(write_buffer.size()), |
- nullptr, 0u, MOJO_WRITE_MESSAGE_FLAG_NONE)); |
- } |
+ MojoWriteMessage(h, quitquitquit.data(), |
+ static_cast<uint32_t>(quitquitquit.size()), |
+ nullptr, 0u, MOJO_WRITE_MESSAGE_FLAG_NONE)); |
- for (size_t i = 0; i < kNumMessages; i++) { |
+ // Wait for it to become readable, which should fail (since we sent |
+ // "quitquitquit"). |
HandleSignalsState hss; |
- ASSERT_EQ(MOJO_RESULT_OK, |
- MojoWait(mp.get().value(), MOJO_HANDLE_SIGNAL_READABLE, |
+ ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION, |
+ MojoWait(h, MOJO_HANDLE_SIGNAL_READABLE, |
MOJO_DEADLINE_INDEFINITE, &hss)); |
- // The child may or may not have closed its end of the message pipe and died |
- // (and we may or may not know it yet), so our end may or may not appear as |
- // writable. |
- ASSERT_TRUE((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE)); |
- ASSERT_TRUE((hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE)); |
- |
- std::string read_buffer(kNumMessages * 2, '\0'); |
- uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size()); |
- ASSERT_EQ(MojoReadMessage(mp.get().value(), &read_buffer[0], |
- &read_buffer_size, nullptr, 0, |
- MOJO_READ_MESSAGE_FLAG_NONE), |
- MOJO_RESULT_OK); |
- read_buffer.resize(read_buffer_size); |
- |
- ASSERT_EQ(std::string(i * 2, 'A' + (i % 26)), read_buffer); |
- } |
- |
- const std::string quitquitquit("quitquitquit"); |
- ASSERT_EQ(MOJO_RESULT_OK, |
- MojoWriteMessage(mp.get().value(), quitquitquit.data(), |
- static_cast<uint32_t>(quitquitquit.size()), |
- nullptr, 0u, MOJO_WRITE_MESSAGE_FLAG_NONE)); |
- |
- // Wait for it to become readable, which should fail (since we sent |
- // "quitquitquit"). |
- HandleSignalsState hss; |
- ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION, |
- MojoWait(mp.get().value(), MOJO_HANDLE_SIGNAL_READABLE, |
- MOJO_DEADLINE_INDEFINITE, &hss)); |
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); |
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); |
- |
- ASSERT_EQ(static_cast<int>(kNumMessages % 100), |
- helper()->WaitForChildShutdown()); |
+ ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); |
+ ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); |
+ END_CHILD_AND_EXPECT_EXIT_CODE(static_cast<int>(kNumMessages % 100)); |
} |
-MOJO_MULTIPROCESS_TEST_CHILD_MAIN(CheckSharedBuffer) { |
- ScopedPlatformHandle client_platform_handle = |
- std::move(test::MultiprocessTestHelper::client_platform_handle); |
- CHECK(client_platform_handle.is_valid()); |
- ScopedMessagePipeHandle mp = |
- CreateMessagePipe(std::move(client_platform_handle)); |
- |
+DEFINE_TEST_CLIENT_WITH_PIPE(CheckSharedBuffer, MultiprocessMessagePipeTest, |
+ h) { |
// Wait for the first message from our parent. |
HandleSignalsState hss; |
- CHECK_EQ(MojoWait(mp.get().value(), MOJO_HANDLE_SIGNAL_READABLE, |
+ CHECK_EQ(MojoWait(h, MOJO_HANDLE_SIGNAL_READABLE, |
MOJO_DEADLINE_INDEFINITE, &hss), |
MOJO_RESULT_OK); |
// In this test, the parent definitely doesn't close its end of the message |
@@ -227,7 +235,7 @@ MOJO_MULTIPROCESS_TEST_CHILD_MAIN(CheckSharedBuffer) { |
uint32_t num_bytes = static_cast<uint32_t>(read_buffer.size()); |
MojoHandle handles[10]; |
uint32_t num_handlers = MOJO_ARRAYSIZE(handles); // Maximum number to receive |
- CHECK_EQ(MojoReadMessage(mp.get().value(), &read_buffer[0], |
+ CHECK_EQ(MojoReadMessage(h, &read_buffer[0], |
&num_bytes, &handles[0], |
&num_handlers, MOJO_READ_MESSAGE_FLAG_NONE), |
MOJO_RESULT_OK); |
@@ -250,15 +258,15 @@ MOJO_MULTIPROCESS_TEST_CHILD_MAIN(CheckSharedBuffer) { |
// And send a message to signal that we've written stuff. |
const std::string go2("go 2"); |
- CHECK_EQ(MojoWriteMessage(mp.get().value(), go2.data(), |
+ CHECK_EQ(MojoWriteMessage(h, go2.data(), |
static_cast<uint32_t>(go2.size()), nullptr, 0u, |
MOJO_WRITE_MESSAGE_FLAG_NONE), |
MOJO_RESULT_OK); |
// Now wait for our parent to send us a message. |
hss = HandleSignalsState(); |
- CHECK_EQ(MojoWait(mp.get().value(), MOJO_HANDLE_SIGNAL_READABLE, |
- MOJO_DEADLINE_INDEFINITE, &hss), |
+ CHECK_EQ(MojoWait(h, MOJO_HANDLE_SIGNAL_READABLE, |
+ MOJO_DEADLINE_INDEFINITE, &hss), |
MOJO_RESULT_OK); |
CHECK_EQ(hss.satisfied_signals, |
MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE); |
@@ -268,7 +276,7 @@ MOJO_MULTIPROCESS_TEST_CHILD_MAIN(CheckSharedBuffer) { |
read_buffer = std::string(100, '\0'); |
num_bytes = static_cast<uint32_t>(read_buffer.size()); |
- CHECK_EQ(MojoReadMessage(mp.get().value(), &read_buffer[0], &num_bytes, |
+ CHECK_EQ(MojoReadMessage(h, &read_buffer[0], &num_bytes, |
nullptr, 0, MOJO_READ_MESSAGE_FLAG_NONE), |
MOJO_RESULT_OK); |
read_buffer.resize(num_bytes); |
@@ -290,97 +298,85 @@ MOJO_MULTIPROCESS_TEST_CHILD_MAIN(CheckSharedBuffer) { |
#define MAYBE_SharedBufferPassing SharedBufferPassing |
#endif |
TEST_F(MultiprocessMessagePipeTest, MAYBE_SharedBufferPassing) { |
- helper()->StartChild("CheckSharedBuffer"); |
- |
- ScopedMessagePipeHandle mp = |
- CreateMessagePipe(std::move(helper()->server_platform_handle)); |
- |
- // Make a shared buffer. |
- MojoCreateSharedBufferOptions options; |
- options.struct_size = sizeof(options); |
- options.flags = MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE; |
- |
- MojoHandle shared_buffer; |
- ASSERT_EQ(MOJO_RESULT_OK, |
- MojoCreateSharedBuffer(&options, 100, &shared_buffer)); |
- |
- // Send the shared buffer. |
- const std::string go1("go 1"); |
- |
- MojoHandle duplicated_shared_buffer; |
- ASSERT_EQ(MOJO_RESULT_OK, |
- MojoDuplicateBufferHandle( |
- shared_buffer, |
- nullptr, |
- &duplicated_shared_buffer)); |
- MojoHandle handles[1]; |
- handles[0] = duplicated_shared_buffer; |
- ASSERT_EQ(MOJO_RESULT_OK, |
- MojoWriteMessage(mp.get().value(), &go1[0], |
- static_cast<uint32_t>(go1.size()), &handles[0], |
- MOJO_ARRAYSIZE(handles), |
- MOJO_WRITE_MESSAGE_FLAG_NONE)); |
- |
- // Wait for a message from the child. |
- HandleSignalsState hss; |
- ASSERT_EQ(MOJO_RESULT_OK, |
- MojoWait(mp.get().value(), MOJO_HANDLE_SIGNAL_READABLE, |
- MOJO_DEADLINE_INDEFINITE, &hss)); |
- EXPECT_TRUE((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE)); |
- EXPECT_TRUE((hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE)); |
+ RUN_CHILD_ON_PIPE(CheckSharedBuffer, h) |
+ // Make a shared buffer. |
+ MojoCreateSharedBufferOptions options; |
+ options.struct_size = sizeof(options); |
+ options.flags = MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE; |
- std::string read_buffer(100, '\0'); |
- uint32_t num_bytes = static_cast<uint32_t>(read_buffer.size()); |
- ASSERT_EQ(MOJO_RESULT_OK, |
- MojoReadMessage(mp.get().value(), &read_buffer[0], |
- &num_bytes, nullptr, 0, |
- MOJO_READ_MESSAGE_FLAG_NONE)); |
- read_buffer.resize(num_bytes); |
- ASSERT_EQ(std::string("go 2"), read_buffer); |
+ MojoHandle shared_buffer; |
+ ASSERT_EQ(MOJO_RESULT_OK, |
+ MojoCreateSharedBuffer(&options, 100, &shared_buffer)); |
- // After we get it, the child should have written something to the shared |
- // buffer. |
- static const char kHello[] = "hello"; |
- void* buffer; |
- CHECK_EQ(MojoMapBuffer(shared_buffer, 0, 100, &buffer, |
- MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE), |
- MOJO_RESULT_OK); |
- ASSERT_EQ(0, memcmp(buffer, kHello, sizeof(kHello))); |
+ // Send the shared buffer. |
+ const std::string go1("go 1"); |
- // Now we'll write some stuff to the shared buffer. |
- static const char kWorld[] = "world!!!"; |
- memcpy(buffer, kWorld, sizeof(kWorld)); |
+ MojoHandle duplicated_shared_buffer; |
+ ASSERT_EQ(MOJO_RESULT_OK, |
+ MojoDuplicateBufferHandle( |
+ shared_buffer, |
+ nullptr, |
+ &duplicated_shared_buffer)); |
+ MojoHandle handles[1]; |
+ handles[0] = duplicated_shared_buffer; |
+ ASSERT_EQ(MOJO_RESULT_OK, |
+ MojoWriteMessage(h, &go1[0], |
+ static_cast<uint32_t>(go1.size()), &handles[0], |
+ MOJO_ARRAYSIZE(handles), |
+ MOJO_WRITE_MESSAGE_FLAG_NONE)); |
- // And send a message to signal that we've written stuff. |
- const std::string go3("go 3"); |
- ASSERT_EQ(MOJO_RESULT_OK, |
- MojoWriteMessage(mp.get().value(), &go3[0], |
- static_cast<uint32_t>(go3.size()), nullptr, 0u, |
- MOJO_WRITE_MESSAGE_FLAG_NONE)); |
+ // Wait for a message from the child. |
+ HandleSignalsState hss; |
+ ASSERT_EQ(MOJO_RESULT_OK, |
+ MojoWait(h, MOJO_HANDLE_SIGNAL_READABLE, |
+ MOJO_DEADLINE_INDEFINITE, &hss)); |
+ EXPECT_TRUE((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE)); |
+ EXPECT_TRUE((hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE)); |
- // Wait for |mp| to become readable, which should fail. |
- hss = HandleSignalsState(); |
- ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION, |
- MojoWait(mp.get().value(), MOJO_HANDLE_SIGNAL_READABLE, |
- MOJO_DEADLINE_INDEFINITE, &hss)); |
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); |
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); |
+ std::string read_buffer(100, '\0'); |
+ uint32_t num_bytes = static_cast<uint32_t>(read_buffer.size()); |
+ ASSERT_EQ(MOJO_RESULT_OK, |
+ MojoReadMessage(h, &read_buffer[0], |
+ &num_bytes, nullptr, 0, |
+ MOJO_READ_MESSAGE_FLAG_NONE)); |
+ read_buffer.resize(num_bytes); |
+ ASSERT_EQ(std::string("go 2"), read_buffer); |
+ |
+ // After we get it, the child should have written something to the shared |
+ // buffer. |
+ static const char kHello[] = "hello"; |
+ void* buffer; |
+ CHECK_EQ(MojoMapBuffer(shared_buffer, 0, 100, &buffer, |
+ MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE), |
+ MOJO_RESULT_OK); |
+ ASSERT_EQ(0, memcmp(buffer, kHello, sizeof(kHello))); |
- MojoClose(mp.release().value()); |
+ // Now we'll write some stuff to the shared buffer. |
+ static const char kWorld[] = "world!!!"; |
+ memcpy(buffer, kWorld, sizeof(kWorld)); |
- ASSERT_EQ(0, helper()->WaitForChildShutdown()); |
+ // And send a message to signal that we've written stuff. |
+ const std::string go3("go 3"); |
+ ASSERT_EQ(MOJO_RESULT_OK, |
+ MojoWriteMessage(h, &go3[0], |
+ static_cast<uint32_t>(go3.size()), nullptr, 0u, |
+ MOJO_WRITE_MESSAGE_FLAG_NONE)); |
+ |
+ // Wait for |h| to become readable, which should fail. |
+ hss = HandleSignalsState(); |
+ ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION, |
+ MojoWait(h, MOJO_HANDLE_SIGNAL_READABLE, |
+ MOJO_DEADLINE_INDEFINITE, &hss)); |
+ ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); |
+ ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); |
+ END_CHILD() |
} |
-MOJO_MULTIPROCESS_TEST_CHILD_MAIN(CheckPlatformHandleFile) { |
- ScopedPlatformHandle client_platform_handle = |
- std::move(test::MultiprocessTestHelper::client_platform_handle); |
- CHECK(client_platform_handle.is_valid()); |
- ScopedMessagePipeHandle mp = |
- CreateMessagePipe(std::move(client_platform_handle)); |
- |
+DEFINE_TEST_CLIENT_WITH_PIPE(CheckPlatformHandleFile, |
+ MultiprocessMessagePipeTest, h) { |
HandleSignalsState hss; |
- CHECK_EQ(MojoWait(mp.get().value(), MOJO_HANDLE_SIGNAL_READABLE, |
- MOJO_DEADLINE_INDEFINITE, &hss), |
+ CHECK_EQ(MojoWait(h, MOJO_HANDLE_SIGNAL_READABLE, |
+ MOJO_DEADLINE_INDEFINITE, &hss), |
MOJO_RESULT_OK); |
CHECK_EQ(hss.satisfied_signals, |
MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE); |
@@ -393,11 +389,10 @@ MOJO_MULTIPROCESS_TEST_CHILD_MAIN(CheckPlatformHandleFile) { |
MojoHandle handles[255]; // Maximum number to receive. |
uint32_t num_handlers = MOJO_ARRAYSIZE(handles); |
- CHECK_EQ(MojoReadMessage(mp.get().value(), &read_buffer[0], |
+ CHECK_EQ(MojoReadMessage(h, &read_buffer[0], |
&num_bytes, &handles[0], |
&num_handlers, MOJO_READ_MESSAGE_FLAG_NONE), |
MOJO_RESULT_OK); |
- MojoClose(mp.release().value()); |
read_buffer.resize(num_bytes); |
char hello[32]; |
@@ -408,9 +403,7 @@ MOJO_MULTIPROCESS_TEST_CHILD_MAIN(CheckPlatformHandleFile) { |
for (int i = 0; i < num_handles; ++i) { |
ScopedPlatformHandle h; |
- CHECK_EQ(PassWrappedPlatformHandle( |
- handles[i], &h), |
- MOJO_RESULT_OK); |
+ CHECK_EQ(PassWrappedPlatformHandle(handles[i], &h), MOJO_RESULT_OK); |
CHECK(h.is_valid()); |
MojoClose(handles[i]); |
@@ -427,77 +420,67 @@ MOJO_MULTIPROCESS_TEST_CHILD_MAIN(CheckPlatformHandleFile) { |
} |
class MultiprocessMessagePipeTestWithPipeCount |
- : public test::MultiprocessMessagePipeTestBase, |
+ : public MultiprocessMessagePipeTest, |
public testing::WithParamInterface<size_t> {}; |
TEST_P(MultiprocessMessagePipeTestWithPipeCount, PlatformHandlePassing) { |
base::ScopedTempDir temp_dir; |
ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
- helper()->StartChild("CheckPlatformHandleFile"); |
- ScopedMessagePipeHandle mp = |
- CreateMessagePipe(std::move(helper()->server_platform_handle)); |
- |
- std::vector<MojoHandle> handles; |
- |
- size_t pipe_count = GetParam(); |
- for (size_t i = 0; i < pipe_count; ++i) { |
- base::FilePath unused; |
- base::ScopedFILE fp( |
- CreateAndOpenTemporaryFileInDir(temp_dir.path(), &unused)); |
- const std::string world("world"); |
- CHECK_EQ(fwrite(&world[0], 1, world.size(), fp.get()), world.size()); |
- fflush(fp.get()); |
- rewind(fp.get()); |
- MojoHandle handle; |
- ASSERT_EQ( |
- CreatePlatformHandleWrapper( |
- ScopedPlatformHandle(test::PlatformHandleFromFILE(std::move(fp))), |
- &handle), |
- MOJO_RESULT_OK); |
- handles.push_back(handle); |
- } |
- |
- char message[128]; |
- sprintf(message, "hello %d", static_cast<int>(pipe_count)); |
- ASSERT_EQ(MOJO_RESULT_OK, |
- MojoWriteMessage(mp.get().value(), message, |
- static_cast<uint32_t>(strlen(message)), |
- &handles[0], static_cast<uint32_t>(handles.size()), |
- MOJO_WRITE_MESSAGE_FLAG_NONE)); |
- |
- // Wait for it to become readable, which should fail. |
- HandleSignalsState hss; |
- ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION, |
- MojoWait(mp.get().value(), MOJO_HANDLE_SIGNAL_READABLE, |
- MOJO_DEADLINE_INDEFINITE, &hss)); |
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); |
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); |
+ RUN_CHILD_ON_PIPE(CheckPlatformHandleFile, h) |
+ std::vector<MojoHandle> handles; |
+ |
+ size_t pipe_count = GetParam(); |
+ for (size_t i = 0; i < pipe_count; ++i) { |
+ base::FilePath unused; |
+ base::ScopedFILE fp( |
+ CreateAndOpenTemporaryFileInDir(temp_dir.path(), &unused)); |
+ const std::string world("world"); |
+ CHECK_EQ(fwrite(&world[0], 1, world.size(), fp.get()), world.size()); |
+ fflush(fp.get()); |
+ rewind(fp.get()); |
+ MojoHandle handle; |
+ ASSERT_EQ( |
+ CreatePlatformHandleWrapper( |
+ ScopedPlatformHandle(test::PlatformHandleFromFILE(std::move(fp))), |
+ &handle), |
+ MOJO_RESULT_OK); |
+ handles.push_back(handle); |
+ } |
- MojoClose(mp.release().value()); |
+ char message[128]; |
+ sprintf(message, "hello %d", static_cast<int>(pipe_count)); |
+ ASSERT_EQ(MOJO_RESULT_OK, |
+ MojoWriteMessage(h, message, |
+ static_cast<uint32_t>(strlen(message)), |
+ &handles[0], |
+ static_cast<uint32_t>(handles.size()), |
+ MOJO_WRITE_MESSAGE_FLAG_NONE)); |
- ASSERT_EQ(0, helper()->WaitForChildShutdown()); |
+ // Wait for it to become readable, which should fail. |
+ HandleSignalsState hss; |
+ ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION, |
+ MojoWait(h, MOJO_HANDLE_SIGNAL_READABLE, |
+ MOJO_DEADLINE_INDEFINITE, &hss)); |
+ ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); |
+ ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); |
+ END_CHILD() |
} |
// Android multi-process tests are not executing the new process. This is flaky. |
#if !defined(OS_ANDROID) |
INSTANTIATE_TEST_CASE_P(PipeCount, |
MultiprocessMessagePipeTestWithPipeCount, |
- testing::Values(1u, 128u, 140u)); |
+ // TODO: Re-enable the 140-pipe case when ChannelPosix |
+ // has support for sending lots of handles. |
+ testing::Values(1u, 128u/*, 140u*/)); |
#endif |
-MOJO_MULTIPROCESS_TEST_CHILD_MAIN(CheckMessagePipe) { |
- ScopedPlatformHandle client_platform_handle = |
- std::move(test::MultiprocessTestHelper::client_platform_handle); |
- CHECK(client_platform_handle.is_valid()); |
- |
- ScopedMessagePipeHandle mp = |
- CreateMessagePipe(std::move(client_platform_handle)); |
- |
+DEFINE_TEST_CLIENT_WITH_PIPE(CheckMessagePipe, MultiprocessMessagePipeTest, h) { |
// Wait for the first message from our parent. |
HandleSignalsState hss; |
- CHECK_EQ(MojoWait(mp.get().value(), MOJO_HANDLE_SIGNAL_READABLE, |
- MOJO_DEADLINE_INDEFINITE, &hss), |
+ CHECK_EQ(MojoWait(h, MOJO_HANDLE_SIGNAL_READABLE, |
+ MOJO_DEADLINE_INDEFINITE, &hss), |
MOJO_RESULT_OK); |
// In this test, the parent definitely doesn't close its end of the message |
// pipe before we do. |
@@ -510,7 +493,7 @@ MOJO_MULTIPROCESS_TEST_CHILD_MAIN(CheckMessagePipe) { |
// It should have a message pipe. |
MojoHandle handles[10]; |
uint32_t num_handlers = MOJO_ARRAYSIZE(handles); |
- CHECK_EQ(MojoReadMessage(mp.get().value(), nullptr, |
+ CHECK_EQ(MojoReadMessage(h, nullptr, |
nullptr, &handles[0], |
&num_handlers, MOJO_READ_MESSAGE_FLAG_NONE), |
MOJO_RESULT_OK); |
@@ -552,49 +535,45 @@ MOJO_MULTIPROCESS_TEST_CHILD_MAIN(CheckMessagePipe) { |
#define MAYBE_MessagePipePassing MessagePipePassing |
#endif |
TEST_F(MultiprocessMessagePipeTest, MAYBE_MessagePipePassing) { |
- helper()->StartChild("CheckMessagePipe"); |
- |
- ScopedMessagePipeHandle mp = |
- CreateMessagePipe(std::move(helper()->server_platform_handle)); |
- MojoCreateSharedBufferOptions options; |
- options.struct_size = sizeof(options); |
- options.flags = MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE; |
- |
- MojoHandle mp1, mp2; |
- ASSERT_EQ(MOJO_RESULT_OK, |
- MojoCreateMessagePipe(nullptr, &mp1, &mp2)); |
- |
- // Write a string into one end of the new message pipe and send the other end. |
- const std::string hello("hello"); |
- ASSERT_EQ(MOJO_RESULT_OK, |
- MojoWriteMessage(mp1, &hello[0], |
- static_cast<uint32_t>(hello.size()), nullptr, 0, |
- MOJO_WRITE_MESSAGE_FLAG_NONE)); |
- ASSERT_EQ(MOJO_RESULT_OK, |
- MojoWriteMessage(mp.get().value(), nullptr, 0, &mp2, 1, |
- MOJO_WRITE_MESSAGE_FLAG_NONE)); |
- |
- // Wait for a message from the child. |
- HandleSignalsState hss; |
- ASSERT_EQ(MOJO_RESULT_OK, |
- MojoWait(mp1, MOJO_HANDLE_SIGNAL_READABLE, |
- MOJO_DEADLINE_INDEFINITE, &hss)); |
- EXPECT_TRUE((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE)); |
- EXPECT_TRUE((hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE)); |
+ RUN_CHILD_ON_PIPE(CheckMessagePipe, h) |
+ MojoCreateSharedBufferOptions options; |
+ options.struct_size = sizeof(options); |
+ options.flags = MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE; |
- std::string read_buffer(100, '\0'); |
- uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size()); |
- CHECK_EQ(MojoReadMessage(mp1, &read_buffer[0], |
- &read_buffer_size, nullptr, |
- 0, MOJO_READ_MESSAGE_FLAG_NONE), |
- MOJO_RESULT_OK); |
- read_buffer.resize(read_buffer_size); |
- CHECK_EQ(read_buffer, std::string("world")); |
+ MojoHandle mp1, mp2; |
+ ASSERT_EQ(MOJO_RESULT_OK, |
+ MojoCreateMessagePipe(nullptr, &mp1, &mp2)); |
+ |
+ // Write a string into one end of the new message pipe and send the other |
+ // end. |
+ const std::string hello("hello"); |
+ ASSERT_EQ(MOJO_RESULT_OK, |
+ MojoWriteMessage(mp1, &hello[0], |
+ static_cast<uint32_t>(hello.size()), nullptr, 0, |
+ MOJO_WRITE_MESSAGE_FLAG_NONE)); |
+ ASSERT_EQ(MOJO_RESULT_OK, |
+ MojoWriteMessage(h, nullptr, 0, &mp2, 1, |
+ MOJO_WRITE_MESSAGE_FLAG_NONE)); |
- MojoClose(mp1); |
- MojoClose(mp.release().value()); |
+ // Wait for a message from the child. |
+ HandleSignalsState hss; |
+ ASSERT_EQ(MOJO_RESULT_OK, |
+ MojoWait(mp1, MOJO_HANDLE_SIGNAL_READABLE, |
+ MOJO_DEADLINE_INDEFINITE, &hss)); |
+ EXPECT_TRUE((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE)); |
+ EXPECT_TRUE((hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE)); |
- ASSERT_EQ(0, helper()->WaitForChildShutdown()); |
+ std::string read_buffer(100, '\0'); |
+ uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size()); |
+ CHECK_EQ(MojoReadMessage(mp1, &read_buffer[0], |
+ &read_buffer_size, nullptr, |
+ 0, MOJO_READ_MESSAGE_FLAG_NONE), |
+ MOJO_RESULT_OK); |
+ read_buffer.resize(read_buffer_size); |
+ CHECK_EQ(read_buffer, std::string("world")); |
+ |
+ MojoClose(mp1); |
+ END_CHILD() |
} |
// Like above test, but verifies passing the other MP handle works as well. |
@@ -605,59 +584,46 @@ TEST_F(MultiprocessMessagePipeTest, MAYBE_MessagePipePassing) { |
#define MAYBE_MessagePipeTwoPassing MessagePipeTwoPassing |
#endif |
TEST_F(MultiprocessMessagePipeTest, MAYBE_MessagePipeTwoPassing) { |
- helper()->StartChild("CheckMessagePipe"); |
- |
- ScopedMessagePipeHandle mp = |
- CreateMessagePipe(std::move(helper()->server_platform_handle)); |
- |
- MojoHandle mp1, mp2; |
- ASSERT_EQ(MOJO_RESULT_OK, |
- MojoCreateMessagePipe(nullptr, &mp2, &mp1)); |
- |
- // Write a string into one end of the new message pipe and send the other end. |
- const std::string hello("hello"); |
- ASSERT_EQ(MOJO_RESULT_OK, |
- MojoWriteMessage(mp1, &hello[0], |
- static_cast<uint32_t>(hello.size()), nullptr, 0u, |
- MOJO_WRITE_MESSAGE_FLAG_NONE)); |
- ASSERT_EQ(MOJO_RESULT_OK, |
- MojoWriteMessage(mp.get().value(), nullptr, 0u, &mp2, 1u, |
- MOJO_WRITE_MESSAGE_FLAG_NONE)); |
- |
- // Wait for a message from the child. |
- HandleSignalsState hss; |
- ASSERT_EQ(MOJO_RESULT_OK, |
- MojoWait(mp1, MOJO_HANDLE_SIGNAL_READABLE, |
- MOJO_DEADLINE_INDEFINITE, &hss)); |
- EXPECT_TRUE((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE)); |
- EXPECT_TRUE((hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE)); |
+ RUN_CHILD_ON_PIPE(CheckMessagePipe, h) |
+ MojoHandle mp1, mp2; |
+ ASSERT_EQ(MOJO_RESULT_OK, |
+ MojoCreateMessagePipe(nullptr, &mp2, &mp1)); |
- std::string read_buffer(100, '\0'); |
- uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size()); |
- CHECK_EQ(MojoReadMessage(mp1, &read_buffer[0], |
- &read_buffer_size, nullptr, |
- 0, MOJO_READ_MESSAGE_FLAG_NONE), |
- MOJO_RESULT_OK); |
- read_buffer.resize(read_buffer_size); |
- CHECK_EQ(read_buffer, std::string("world")); |
+ // Write a string into one end of the new message pipe and send the other |
+ // end. |
+ const std::string hello("hello"); |
+ ASSERT_EQ(MOJO_RESULT_OK, |
+ MojoWriteMessage(mp1, &hello[0], |
+ static_cast<uint32_t>(hello.size()), nullptr, 0u, |
+ MOJO_WRITE_MESSAGE_FLAG_NONE)); |
+ ASSERT_EQ(MOJO_RESULT_OK, |
+ MojoWriteMessage(h, nullptr, 0u, &mp2, 1u, |
+ MOJO_WRITE_MESSAGE_FLAG_NONE)); |
- MojoClose(mp.release().value()); |
+ // Wait for a message from the child. |
+ HandleSignalsState hss; |
+ ASSERT_EQ(MOJO_RESULT_OK, |
+ MojoWait(mp1, MOJO_HANDLE_SIGNAL_READABLE, |
+ MOJO_DEADLINE_INDEFINITE, &hss)); |
+ EXPECT_TRUE((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE)); |
+ EXPECT_TRUE((hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE)); |
- ASSERT_EQ(0, helper()->WaitForChildShutdown()); |
+ std::string read_buffer(100, '\0'); |
+ uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size()); |
+ CHECK_EQ(MojoReadMessage(mp1, &read_buffer[0], |
+ &read_buffer_size, nullptr, |
+ 0, MOJO_READ_MESSAGE_FLAG_NONE), |
+ MOJO_RESULT_OK); |
+ read_buffer.resize(read_buffer_size); |
+ CHECK_EQ(read_buffer, std::string("world")); |
+ END_CHILD(); |
} |
-MOJO_MULTIPROCESS_TEST_CHILD_MAIN(DataPipeConsumer) { |
- ScopedPlatformHandle client_platform_handle = |
- std::move(test::MultiprocessTestHelper::client_platform_handle); |
- CHECK(client_platform_handle.is_valid()); |
- |
- ScopedMessagePipeHandle mp = |
- CreateMessagePipe(std::move(client_platform_handle)); |
- |
+DEFINE_TEST_CLIENT_WITH_PIPE(DataPipeConsumer, MultiprocessMessagePipeTest, h) { |
// Wait for the first message from our parent. |
HandleSignalsState hss; |
- CHECK_EQ(MojoWait(mp.get().value(), MOJO_HANDLE_SIGNAL_READABLE, |
- MOJO_DEADLINE_INDEFINITE, &hss), |
+ CHECK_EQ(MojoWait(h, MOJO_HANDLE_SIGNAL_READABLE, |
+ MOJO_DEADLINE_INDEFINITE, &hss), |
MOJO_RESULT_OK); |
// In this test, the parent definitely doesn't close its end of the message |
// pipe before we do. |
@@ -670,7 +636,7 @@ MOJO_MULTIPROCESS_TEST_CHILD_MAIN(DataPipeConsumer) { |
// It should have a message pipe. |
MojoHandle handles[10]; |
uint32_t num_handlers = MOJO_ARRAYSIZE(handles); |
- CHECK_EQ(MojoReadMessage(mp.get().value(), nullptr, |
+ CHECK_EQ(MojoReadMessage(h, nullptr, |
nullptr, &handles[0], |
&num_handlers, MOJO_READ_MESSAGE_FLAG_NONE), |
MOJO_RESULT_OK); |
@@ -712,49 +678,597 @@ MOJO_MULTIPROCESS_TEST_CHILD_MAIN(DataPipeConsumer) { |
#define MAYBE_DataPipeConsumer DataPipeConsumer |
#endif |
TEST_F(MultiprocessMessagePipeTest, MAYBE_DataPipeConsumer) { |
- helper()->StartChild("DataPipeConsumer"); |
- |
- ScopedMessagePipeHandle mp = |
- CreateMessagePipe(std::move(helper()->server_platform_handle)); |
- MojoCreateSharedBufferOptions options; |
- options.struct_size = sizeof(options); |
- options.flags = MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE; |
- |
- MojoHandle mp1, mp2; |
- ASSERT_EQ(MOJO_RESULT_OK, |
- MojoCreateMessagePipe(nullptr, &mp2, &mp1)); |
- |
- // Write a string into one end of the new message pipe and send the other end. |
- const std::string hello("hello"); |
- ASSERT_EQ(MOJO_RESULT_OK, |
- MojoWriteMessage(mp1, &hello[0], |
- static_cast<uint32_t>(hello.size()), nullptr, 0u, |
- MOJO_WRITE_MESSAGE_FLAG_NONE)); |
- ASSERT_EQ(MOJO_RESULT_OK, |
- MojoWriteMessage(mp.get().value(), nullptr, 0, &mp2, 1u, |
- MOJO_WRITE_MESSAGE_FLAG_NONE)); |
- |
- // Wait for a message from the child. |
- HandleSignalsState hss; |
- ASSERT_EQ(MOJO_RESULT_OK, |
- MojoWait(mp1, MOJO_HANDLE_SIGNAL_READABLE, |
- MOJO_DEADLINE_INDEFINITE, &hss)); |
- EXPECT_TRUE((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE)); |
- EXPECT_TRUE((hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE)); |
+ RUN_CHILD_ON_PIPE(DataPipeConsumer, h) |
+ MojoCreateSharedBufferOptions options; |
+ options.struct_size = sizeof(options); |
+ options.flags = MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE; |
- std::string read_buffer(100, '\0'); |
- uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size()); |
- CHECK_EQ(MojoReadMessage(mp1, &read_buffer[0], |
- &read_buffer_size, nullptr, |
- 0, MOJO_READ_MESSAGE_FLAG_NONE), |
- MOJO_RESULT_OK); |
- read_buffer.resize(read_buffer_size); |
- CHECK_EQ(read_buffer, std::string("world")); |
+ MojoHandle mp1, mp2; |
+ ASSERT_EQ(MOJO_RESULT_OK, |
+ MojoCreateMessagePipe(nullptr, &mp2, &mp1)); |
+ |
+ // Write a string into one end of the new message pipe and send the other |
+ // end. |
+ const std::string hello("hello"); |
+ ASSERT_EQ(MOJO_RESULT_OK, |
+ MojoWriteMessage(mp1, &hello[0], |
+ static_cast<uint32_t>(hello.size()), nullptr, 0u, |
+ MOJO_WRITE_MESSAGE_FLAG_NONE)); |
+ ASSERT_EQ(MOJO_RESULT_OK, |
+ MojoWriteMessage(h, nullptr, 0, &mp2, 1u, |
+ MOJO_WRITE_MESSAGE_FLAG_NONE)); |
+ |
+ // Wait for a message from the child. |
+ HandleSignalsState hss; |
+ ASSERT_EQ(MOJO_RESULT_OK, |
+ MojoWait(mp1, MOJO_HANDLE_SIGNAL_READABLE, |
+ MOJO_DEADLINE_INDEFINITE, &hss)); |
+ EXPECT_TRUE((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE)); |
+ EXPECT_TRUE((hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE)); |
+ |
+ std::string read_buffer(100, '\0'); |
+ uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size()); |
+ CHECK_EQ(MojoReadMessage(mp1, &read_buffer[0], |
+ &read_buffer_size, nullptr, |
+ 0, MOJO_READ_MESSAGE_FLAG_NONE), |
+ MOJO_RESULT_OK); |
+ read_buffer.resize(read_buffer_size); |
+ CHECK_EQ(read_buffer, std::string("world")); |
+ |
+ MojoClose(mp1); |
+ END_CHILD(); |
+} |
+ |
+TEST_F(MultiprocessMessagePipeTest, CreateMessagePipe) { |
+ MojoHandle p0, p1; |
+ CreateMessagePipe(&p0, &p1); |
+ VerifyTransmission(p0, p1, "hey man"); |
+ VerifyTransmission(p1, p0, "slow down"); |
+ VerifyTransmission(p0, p1, std::string(10 * 1024 * 1024, 'a')); |
+ VerifyTransmission(p1, p0, std::string(10 * 1024 * 1024, 'e')); |
+ |
+ CloseHandle(p0); |
+ CloseHandle(p1); |
+} |
+ |
+TEST_F(MultiprocessMessagePipeTest, PassMessagePipeLocal) { |
+ MojoHandle p0, p1; |
+ CreateMessagePipe(&p0, &p1); |
+ VerifyTransmission(p0, p1, "testing testing"); |
+ VerifyTransmission(p1, p0, "one two three"); |
+ |
+ MojoHandle p2, p3; |
+ |
+ CreateMessagePipe(&p2, &p3); |
+ VerifyTransmission(p2, p3, "testing testing"); |
+ VerifyTransmission(p3, p2, "one two three"); |
+ |
+ // Pass p2 over p0 to p1. |
+ const std::string message = "ceci n'est pas une pipe"; |
+ WriteMessageWithHandles(p0, message, &p2, 1); |
+ EXPECT_EQ(message, ReadMessageWithHandles(p1, &p2, 1)); |
+ |
+ CloseHandle(p0); |
+ CloseHandle(p1); |
+ |
+ // Verify that the received handle (now in p2) still works. |
+ VerifyTransmission(p2, p3, "Easy come, easy go; will you let me go?"); |
+ VerifyTransmission(p3, p2, "Bismillah! NO! We will not let you go!"); |
+ |
+ CloseHandle(p2); |
+ CloseHandle(p3); |
+} |
+ |
+// Echos the primordial channel until "exit". |
+DEFINE_TEST_CLIENT_WITH_PIPE(ChannelEchoClient, MultiprocessMessagePipeTest, |
+ h) { |
+ for (;;) { |
+ std::string message = ReadMessage(h); |
+ if (message == "exit") |
+ break; |
+ WriteMessage(h, message); |
+ } |
+ return 0; |
+} |
+ |
+TEST_F(MultiprocessMessagePipeTest, MultiprocessChannelPipe) { |
+ RUN_CHILD_ON_PIPE(ChannelEchoClient, h) |
+ VerifyEcho(h, "in an interstellar burst"); |
+ VerifyEcho(h, "i am back to save the universe"); |
+ VerifyEcho(h, std::string(10 * 1024 * 1024, 'o')); |
+ |
+ WriteMessage(h, "exit"); |
+ END_CHILD() |
+} |
+ |
+// Receives a pipe handle from the primordial channel and echos on it until |
+// "exit". Used to test simple pipe transfer across processes via channels. |
+DEFINE_TEST_CLIENT_WITH_PIPE(EchoServiceClient, MultiprocessMessagePipeTest, |
+ h) { |
+ MojoHandle p; |
+ ReadMessageWithHandles(h, &p, 1); |
+ for (;;) { |
+ std::string message = ReadMessage(p); |
+ if (message == "exit") |
+ break; |
+ WriteMessage(p, message); |
+ } |
+ return 0; |
+} |
+ |
+TEST_F(MultiprocessMessagePipeTest, PassMessagePipeCrossProcess) { |
+ MojoHandle p0, p1; |
+ CreateMessagePipe(&p0, &p1); |
+ RUN_CHILD_ON_PIPE(EchoServiceClient, h) |
+ |
+ // Pass one end of the pipe to the other process. |
+ WriteMessageWithHandles(h, "here take this", &p1, 1); |
+ |
+ VerifyEcho(p0, "and you may ask yourself"); |
+ VerifyEcho(p0, "where does that highway go?"); |
+ VerifyEcho(p0, std::string(20 * 1024 * 1024, 'i')); |
+ |
+ WriteMessage(p0, "exit"); |
+ END_CHILD() |
+ CloseHandle(p0); |
+} |
+ |
+// Receives a pipe handle from the primordial channel and reads new handles |
+// from it. Each read handle establishes a new echo channel. |
+DEFINE_TEST_CLIENT_WITH_PIPE(EchoServiceFactoryClient, |
+ MultiprocessMessagePipeTest, h) { |
+ MojoHandle p; |
+ ReadMessageWithHandles(h, &p, 1); |
+ |
+ std::vector<MojoHandle> handles(2); |
+ handles[0] = h; |
+ handles[1] = p; |
+ std::vector<MojoHandleSignals> signals(2, MOJO_HANDLE_SIGNAL_READABLE); |
+ for (;;) { |
+ uint32_t index; |
+ CHECK_EQ(MojoWaitMany(handles.data(), signals.data(), |
+ static_cast<uint32_t>(handles.size()), |
+ MOJO_DEADLINE_INDEFINITE, &index, nullptr), |
+ MOJO_RESULT_OK); |
+ DCHECK_LE(index, handles.size()); |
+ if (index == 0) { |
+ // If data is available on the first pipe, it should be an exit command. |
+ EXPECT_EQ(std::string("exit"), ReadMessage(h)); |
+ break; |
+ } else if (index == 1) { |
+ // If the second pipe, it should be a new handle requesting echo service. |
+ MojoHandle echo_request; |
+ ReadMessageWithHandles(p, &echo_request, 1); |
+ handles.push_back(echo_request); |
+ signals.push_back(MOJO_HANDLE_SIGNAL_READABLE); |
+ } else { |
+ // Otherwise it was one of our established echo pipes. Echo! |
+ WriteMessage(handles[index], ReadMessage(handles[index])); |
+ } |
+ } |
+ |
+ for (size_t i = 1; i < handles.size(); ++i) |
+ CloseHandle(handles[i]); |
+ |
+ return 0; |
+} |
+ |
+TEST_F(MultiprocessMessagePipeTest, PassMoarMessagePipesCrossProcess) { |
+ MojoHandle echo_factory_proxy, echo_factory_request; |
+ CreateMessagePipe(&echo_factory_proxy, &echo_factory_request); |
+ |
+ MojoHandle echo_proxy_a, echo_request_a; |
+ CreateMessagePipe(&echo_proxy_a, &echo_request_a); |
+ |
+ MojoHandle echo_proxy_b, echo_request_b; |
+ CreateMessagePipe(&echo_proxy_b, &echo_request_b); |
+ |
+ MojoHandle echo_proxy_c, echo_request_c; |
+ CreateMessagePipe(&echo_proxy_c, &echo_request_c); |
+ |
+ RUN_CHILD_ON_PIPE(EchoServiceFactoryClient, h) |
+ WriteMessageWithHandles( |
+ h, "gief factory naow plz", &echo_factory_request, 1); |
+ |
+ WriteMessageWithHandles(echo_factory_proxy, "give me an echo service plz!", |
+ &echo_request_a, 1); |
+ WriteMessageWithHandles(echo_factory_proxy, "give me one too!", |
+ &echo_request_b, 1); |
+ |
+ VerifyEcho(echo_proxy_a, "i came here for an argument"); |
+ VerifyEcho(echo_proxy_a, "shut your festering gob"); |
+ VerifyEcho(echo_proxy_a, "mumble mumble mumble"); |
+ |
+ VerifyEcho(echo_proxy_b, "wubalubadubdub"); |
+ VerifyEcho(echo_proxy_b, "wubalubadubdub"); |
+ |
+ WriteMessageWithHandles(echo_factory_proxy, "hook me up also thanks", |
+ &echo_request_c, 1); |
+ |
+ VerifyEcho(echo_proxy_a, "the frobinators taste like frobinators"); |
+ VerifyEcho(echo_proxy_b, "beep bop boop"); |
+ VerifyEcho(echo_proxy_c, "zzzzzzzzzzzzzzzzzzzzzzzzzz"); |
+ |
+ WriteMessage(h, "exit"); |
+ END_CHILD() |
+ |
+ CloseHandle(echo_factory_proxy); |
+ CloseHandle(echo_proxy_a); |
+ CloseHandle(echo_proxy_b); |
+ CloseHandle(echo_proxy_c); |
+} |
+ |
+TEST_F(MultiprocessMessagePipeTest, ChannelPipesWithMultipleChildren) { |
+ RUN_CHILD_ON_PIPE(ChannelEchoClient, a) |
+ RUN_CHILD_ON_PIPE(ChannelEchoClient, b) |
+ VerifyEcho(a, "hello child 0"); |
+ VerifyEcho(b, "hello child 1"); |
+ |
+ WriteMessage(a, "exit"); |
+ WriteMessage(b, "exit"); |
+ END_CHILD() |
+ END_CHILD() |
+} |
+ |
+// Reads and turns a pipe handle some number of times to create lots of |
+// transient proxies. |
+DEFINE_TEST_CLIENT_TEST_WITH_PIPE(PingPongPipeClient, |
+ MultiprocessMessagePipeTest, h) { |
+ const size_t kNumBounces = 50; |
+ MojoHandle p0, p1; |
+ ReadMessageWithHandles(h, &p0, 1); |
+ ReadMessageWithHandles(h, &p1, 1); |
+ for (size_t i = 0; i < kNumBounces; ++i) { |
+ WriteMessageWithHandles(h, "", &p1, 1); |
+ ReadMessageWithHandles(h, &p1, 1); |
+ } |
+ WriteMessageWithHandles(h, "", &p0, 1); |
+ WriteMessage(p1, "bye"); |
+ MojoClose(p1); |
+ EXPECT_EQ("quit", ReadMessage(h)); |
+} |
+ |
+TEST_F(MultiprocessMessagePipeTest, PingPongPipe) { |
+ MojoHandle p0, p1; |
+ CreateMessagePipe(&p0, &p1); |
+ |
+ RUN_CHILD_ON_PIPE(PingPongPipeClient, h) |
+ const size_t kNumBounces = 50; |
+ WriteMessageWithHandles(h, "", &p0, 1); |
+ WriteMessageWithHandles(h, "", &p1, 1); |
+ for (size_t i = 0; i < kNumBounces; ++i) { |
+ ReadMessageWithHandles(h, &p1, 1); |
+ WriteMessageWithHandles(h, "", &p1, 1); |
+ } |
+ ReadMessageWithHandles(h, &p0, 1); |
+ WriteMessage(h, "quit"); |
+ END_CHILD() |
+ |
+ EXPECT_EQ("bye", ReadMessage(p0)); |
+ |
+ // We should still be able to observe peer closure from the other end. |
+ EXPECT_EQ(MOJO_RESULT_OK, |
+ MojoWait(p0, MOJO_HANDLE_SIGNAL_PEER_CLOSED, |
+ MOJO_DEADLINE_INDEFINITE, nullptr)); |
+} |
+ |
+// Parses commands from the parent pipe and does whatever it's asked to do. |
+DEFINE_TEST_CLIENT_WITH_PIPE(CommandDrivenClient, MultiprocessMessagePipeTest, |
+ h) { |
+ base::hash_map<std::string, MojoHandle> named_pipes; |
+ for (;;) { |
+ MojoHandle p; |
+ auto parts = base::SplitString(ReadMessageWithOptionalHandle(h, &p), ":", |
+ base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); |
+ CHECK(!parts.empty()); |
+ std::string command = parts[0]; |
+ if (command == "take") { |
+ // Take a pipe. |
+ CHECK_EQ(parts.size(), 2u); |
+ CHECK_NE(p, MOJO_HANDLE_INVALID); |
+ named_pipes[parts[1]] = p; |
+ WriteMessage(h, "ok"); |
+ } else if (command == "return") { |
+ // Return a pipe. |
+ CHECK_EQ(parts.size(), 2u); |
+ CHECK_EQ(p, MOJO_HANDLE_INVALID); |
+ p = named_pipes[parts[1]]; |
+ CHECK_NE(p, MOJO_HANDLE_INVALID); |
+ named_pipes.erase(parts[1]); |
+ WriteMessageWithHandles(h, "ok", &p, 1); |
+ } else if (command == "say") { |
+ // Say something to a named pipe. |
+ CHECK_EQ(parts.size(), 3u); |
+ CHECK_EQ(p, MOJO_HANDLE_INVALID); |
+ p = named_pipes[parts[1]]; |
+ CHECK_NE(p, MOJO_HANDLE_INVALID); |
+ CHECK(!parts[2].empty()); |
+ WriteMessage(p, parts[2]); |
+ WriteMessage(h, "ok"); |
+ } else if (command == "hear") { |
+ // Expect to read something from a named pipe. |
+ CHECK_EQ(parts.size(), 3u); |
+ CHECK_EQ(p, MOJO_HANDLE_INVALID); |
+ p = named_pipes[parts[1]]; |
+ CHECK_NE(p, MOJO_HANDLE_INVALID); |
+ CHECK(!parts[2].empty()); |
+ CHECK_EQ(parts[2], ReadMessage(p)); |
+ WriteMessage(h, "ok"); |
+ } else if (command == "pass") { |
+ // Pass one named pipe over another named pipe. |
+ CHECK_EQ(parts.size(), 3u); |
+ CHECK_EQ(p, MOJO_HANDLE_INVALID); |
+ p = named_pipes[parts[1]]; |
+ MojoHandle carrier = named_pipes[parts[2]]; |
+ CHECK_NE(p, MOJO_HANDLE_INVALID); |
+ CHECK_NE(carrier, MOJO_HANDLE_INVALID); |
+ named_pipes.erase(parts[1]); |
+ WriteMessageWithHandles(carrier, "got a pipe for ya", &p, 1); |
+ WriteMessage(h, "ok"); |
+ } else if (command == "catch") { |
+ // Expect to receive one named pipe from another named pipe. |
+ CHECK_EQ(parts.size(), 3u); |
+ CHECK_EQ(p, MOJO_HANDLE_INVALID); |
+ MojoHandle carrier = named_pipes[parts[2]]; |
+ CHECK_NE(carrier, MOJO_HANDLE_INVALID); |
+ ReadMessageWithHandles(carrier, &p, 1); |
+ CHECK_NE(p, MOJO_HANDLE_INVALID); |
+ named_pipes[parts[1]] = p; |
+ WriteMessage(h, "ok"); |
+ } else if (command == "exit") { |
+ CHECK_EQ(parts.size(), 1u); |
+ break; |
+ } |
+ } |
+ |
+ for (auto& pipe: named_pipes) |
+ CloseHandle(pipe.second); |
+ |
+ return 0; |
+} |
+ |
+TEST_F(MultiprocessMessagePipeTest, ChildToChildPipes) { |
+ RUN_CHILD_ON_PIPE(CommandDrivenClient, h0) |
+ RUN_CHILD_ON_PIPE(CommandDrivenClient, h1) |
+ CommandDrivenClientController a(h0); |
+ CommandDrivenClientController b(h1); |
+ |
+ // Create a pipe and pass each end to a different client. |
+ MojoHandle p0, p1; |
+ CreateMessagePipe(&p0, &p1); |
+ a.SendHandle("x", p0); |
+ b.SendHandle("y", p1); |
+ |
+ // Make sure they can talk. |
+ a.Send("say:x:hello sir"); |
+ b.Send("hear:y:hello sir"); |
+ |
+ b.Send("say:y:i love multiprocess pipes!"); |
+ a.Send("hear:x:i love multiprocess pipes!"); |
+ |
+ a.Exit(); |
+ b.Exit(); |
+ END_CHILD() |
+ END_CHILD() |
+} |
+ |
+TEST_F(MultiprocessMessagePipeTest, MoreChildToChildPipes) { |
+ RUN_CHILD_ON_PIPE(CommandDrivenClient, h0) |
+ RUN_CHILD_ON_PIPE(CommandDrivenClient, h1) |
+ RUN_CHILD_ON_PIPE(CommandDrivenClient, h2) |
+ RUN_CHILD_ON_PIPE(CommandDrivenClient, h3) |
+ CommandDrivenClientController a(h0), b(h1), c(h2), d(h3); |
+ |
+ // Connect a to b and c to d |
+ |
+ MojoHandle p0, p1; |
+ |
+ CreateMessagePipe(&p0, &p1); |
+ a.SendHandle("b_pipe", p0); |
+ b.SendHandle("a_pipe", p1); |
+ |
+ MojoHandle p2, p3; |
+ |
+ CreateMessagePipe(&p2, &p3); |
+ c.SendHandle("d_pipe", p2); |
+ d.SendHandle("c_pipe", p3); |
+ |
+ // Connect b to c via a and d |
+ MojoHandle p4, p5; |
+ CreateMessagePipe(&p4, &p5); |
+ a.SendHandle("d_pipe", p4); |
+ d.SendHandle("a_pipe", p5); |
+ |
+ // Have |a| pass its new |d|-pipe to |b|. It will eventually connect |
+ // to |c|. |
+ a.Send("pass:d_pipe:b_pipe"); |
+ b.Send("catch:c_pipe:a_pipe"); |
+ |
+ // Have |d| pass its new |a|-pipe to |c|. It will now be connected to |
+ // |b|. |
+ d.Send("pass:a_pipe:c_pipe"); |
+ c.Send("catch:b_pipe:d_pipe"); |
+ |
+ // Make sure b and c and talk. |
+ b.Send("say:c_pipe:it's a beautiful day"); |
+ c.Send("hear:b_pipe:it's a beautiful day"); |
+ |
+ // Create x and y and have b and c exchange them. |
+ MojoHandle x, y; |
+ CreateMessagePipe(&x, &y); |
+ b.SendHandle("x", x); |
+ c.SendHandle("y", y); |
+ b.Send("pass:x:c_pipe"); |
+ c.Send("pass:y:b_pipe"); |
+ b.Send("catch:y:c_pipe"); |
+ c.Send("catch:x:b_pipe"); |
+ |
+ // Make sure the pipe still works in both directions. |
+ b.Send("say:y:hello"); |
+ c.Send("hear:x:hello"); |
+ c.Send("say:x:goodbye"); |
+ b.Send("hear:y:goodbye"); |
+ |
+ // Take both pipes back. |
+ y = c.RetrieveHandle("x"); |
+ x = b.RetrieveHandle("y"); |
+ |
+ VerifyTransmission(x, y, "still works"); |
+ VerifyTransmission(y, x, "in both directions"); |
+ |
+ CloseHandle(x); |
+ CloseHandle(y); |
+ |
+ a.Exit(); |
+ b.Exit(); |
+ c.Exit(); |
+ d.Exit(); |
+ END_CHILD() |
+ END_CHILD() |
+ END_CHILD() |
+ END_CHILD() |
+} |
+ |
+DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReceivePipeWithClosedPeer, |
+ MultiprocessMessagePipeTest, h) { |
+ MojoHandle p; |
+ EXPECT_EQ("foo", ReadMessageWithHandles(h, &p, 1)); |
+ |
+ EXPECT_EQ(MOJO_RESULT_OK, MojoWait(p, MOJO_HANDLE_SIGNAL_PEER_CLOSED, |
+ MOJO_DEADLINE_INDEFINITE, nullptr)); |
+} |
+ |
+TEST_F(MultiprocessMessagePipeTest, SendPipeThenClosePeer) { |
+ RUN_CHILD_ON_PIPE(ReceivePipeWithClosedPeer, h) |
+ MojoHandle a, b; |
+ CreateMessagePipe(&a, &b); |
+ |
+ // Send |a| and immediately close |b|. The child should observe closure. |
+ WriteMessageWithHandles(h, "foo", &a, 1); |
+ MojoClose(b); |
+ END_CHILD() |
+} |
+ |
+DEFINE_TEST_CLIENT_TEST_WITH_PIPE(SendOtherChildPipeWithClosedPeer, |
+ MultiprocessMessagePipeTest, h) { |
+ // Create a new pipe and send one end to the parent, who will connect it to |
+ // a client running ReceivePipeWithClosedPeerFromOtherChild. |
+ MojoHandle application_proxy, application_request; |
+ CreateMessagePipe(&application_proxy, &application_request); |
+ WriteMessageWithHandles(h, "c2a plz", &application_request, 1); |
+ |
+ // Create another pipe and send one end to the remote "application". |
+ MojoHandle service_proxy, service_request; |
+ CreateMessagePipe(&service_proxy, &service_request); |
+ WriteMessageWithHandles(application_proxy, "c2s lol", &service_request, 1); |
+ |
+ // Immediately close the service proxy. The "application" should detect this. |
+ EXPECT_EQ(MOJO_RESULT_OK, MojoClose(service_proxy)); |
+ |
+ // Wait for quit. |
+ EXPECT_EQ("quit", ReadMessage(h)); |
+} |
+ |
+DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReceivePipeWithClosedPeerFromOtherChild, |
+ MultiprocessMessagePipeTest, h) { |
+ // Receive a pipe from the parent. This is akin to an "application request". |
+ MojoHandle application_client; |
+ EXPECT_EQ("c2a", ReadMessageWithHandles(h, &application_client, 1)); |
+ |
+ // Receive a pipe from the "application" "client". |
+ MojoHandle service_client; |
+ EXPECT_EQ("c2s lol", |
+ ReadMessageWithHandles(application_client, &service_client, 1)); |
+ |
+ // Wait for the service client to signal closure. |
+ EXPECT_EQ(MOJO_RESULT_OK, MojoWait(service_client, |
+ MOJO_HANDLE_SIGNAL_PEER_CLOSED, |
+ MOJO_DEADLINE_INDEFINITE, nullptr)); |
+ |
+ EXPECT_EQ(MOJO_RESULT_OK, MojoClose(service_client)); |
+ EXPECT_EQ(MOJO_RESULT_OK, MojoClose(application_client)); |
+} |
+ |
+TEST_F(MultiprocessMessagePipeTest, SendPipeWithClosedPeerBetweenChildren) { |
+ RUN_CHILD_ON_PIPE(SendOtherChildPipeWithClosedPeer, kid_a) |
+ RUN_CHILD_ON_PIPE(ReceivePipeWithClosedPeerFromOtherChild, kid_b) |
+ // Receive an "application request" from the first child and forward it |
+ // to the second child. |
+ MojoHandle application_request; |
+ EXPECT_EQ("c2a plz", |
+ ReadMessageWithHandles(kid_a, &application_request, 1)); |
+ |
+ WriteMessageWithHandles(kid_b, "c2a", &application_request, 1); |
+ END_CHILD() |
+ |
+ WriteMessage(kid_a, "quit"); |
+ END_CHILD() |
+} |
+ |
+TEST_F(MultiprocessMessagePipeTest, SendClosePeerSend) { |
+ MojoHandle a, b; |
+ CreateMessagePipe(&a, &b); |
+ |
+ MojoHandle c, d; |
+ CreateMessagePipe(&c, &d); |
+ |
+ // Send |a| over |c|, immediately close |b|, then send |a| back over |d|. |
+ WriteMessageWithHandles(c, "foo", &a, 1); |
+ EXPECT_EQ("foo", ReadMessageWithHandles(d, &a, 1)); |
+ WriteMessageWithHandles(d, "bar", &a, 1); |
+ EXPECT_EQ("bar", ReadMessageWithHandles(c, &a, 1)); |
+ EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); |
+ |
+ // We should be able to detect peer closure on |a|. |
+ EXPECT_EQ(MOJO_RESULT_OK, MojoWait(a, MOJO_HANDLE_SIGNAL_PEER_CLOSED, |
+ MOJO_DEADLINE_INDEFINITE, nullptr)); |
+} |
+ |
+DEFINE_TEST_CLIENT_TEST_WITH_PIPE(WriteCloseSendPeerClient, |
+ MultiprocessMessagePipeTest, h) { |
+ MojoHandle pipe[2]; |
+ EXPECT_EQ("foo", ReadMessageWithHandles(h, pipe, 2)); |
+ |
+ // Write some messages to the first endpoint and then close it. |
+ WriteMessage(pipe[0], "baz"); |
+ WriteMessage(pipe[0], "qux"); |
+ EXPECT_EQ(MOJO_RESULT_OK, MojoClose(pipe[0])); |
+ |
+ MojoHandle c, d; |
+ CreateMessagePipe(&c, &d); |
+ |
+ // Pass the orphaned endpoint over another pipe before passing it back to |
+ // the parent, just for some extra proxying goodness. |
+ WriteMessageWithHandles(c, "foo", &pipe[1], 1); |
+ EXPECT_EQ("foo", ReadMessageWithHandles(d, &pipe[1], 1)); |
+ |
+ // And finally pass it back to the parent. |
+ WriteMessageWithHandles(h, "bar", &pipe[1], 1); |
+ |
+ EXPECT_EQ("quit", ReadMessage(h)); |
+} |
+ |
+TEST_F(MultiprocessMessagePipeTest, WriteCloseSendPeer) { |
+ MojoHandle pipe[2]; |
+ CreateMessagePipe(&pipe[0], &pipe[1]); |
+ |
+ RUN_CHILD_ON_PIPE(WriteCloseSendPeerClient, h) |
+ // Pass the pipe to the child. |
+ WriteMessageWithHandles(h, "foo", pipe, 2); |
+ |
+ // Read back an endpoint which should have messages on it. |
+ MojoHandle p; |
+ EXPECT_EQ("bar", ReadMessageWithHandles(h, &p, 1)); |
+ |
+ EXPECT_EQ("baz", ReadMessage(p)); |
+ EXPECT_EQ("qux", ReadMessage(p)); |
- MojoClose(mp1); |
- MojoClose(mp.release().value()); |
+ // Expect to have peer closure signaled. |
+ EXPECT_EQ(MOJO_RESULT_OK, MojoWait(p, MOJO_HANDLE_SIGNAL_PEER_CLOSED, |
+ MOJO_DEADLINE_INDEFINITE, nullptr)); |
- ASSERT_EQ(0, helper()->WaitForChildShutdown()); |
+ WriteMessage(h, "quit"); |
+ END_CHILD() |
} |
} // namespace |