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

Unified Diff: mojo/edk/system/multiprocess_message_pipe_unittest.cc

Issue 1585493002: [mojo] Ports EDK (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 11 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/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

Powered by Google App Engine
This is Rietveld 408576698