summaryrefslogtreecommitdiffstats
path: root/chromium/mojo/system/core_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/mojo/system/core_unittest.cc')
-rw-r--r--chromium/mojo/system/core_unittest.cc888
1 files changed, 888 insertions, 0 deletions
diff --git a/chromium/mojo/system/core_unittest.cc b/chromium/mojo/system/core_unittest.cc
new file mode 100644
index 00000000000..af3d0c13451
--- /dev/null
+++ b/chromium/mojo/system/core_unittest.cc
@@ -0,0 +1,888 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "mojo/system/core.h"
+
+#include <limits>
+
+#include "base/basictypes.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+#include "mojo/system/core_test_base.h"
+
+namespace mojo {
+namespace system {
+namespace {
+
+typedef test::CoreTestBase CoreTest;
+
+TEST_F(CoreTest, GetTimeTicksNow) {
+ const MojoTimeTicks start = core()->GetTimeTicksNow();
+ EXPECT_NE(static_cast<MojoTimeTicks>(0), start)
+ << "GetTimeTicksNow should return nonzero value";
+ base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(15));
+ const MojoTimeTicks finish = core()->GetTimeTicksNow();
+ // Allow for some fuzz in sleep.
+ EXPECT_GE((finish - start), static_cast<MojoTimeTicks>(8000))
+ << "Sleeping should result in increasing time ticks";
+}
+
+TEST_F(CoreTest, Basic) {
+ MockHandleInfo info;
+
+ EXPECT_EQ(0u, info.GetCtorCallCount());
+ MojoHandle h = CreateMockHandle(&info);
+ EXPECT_EQ(1u, info.GetCtorCallCount());
+ EXPECT_NE(h, MOJO_HANDLE_INVALID);
+
+ EXPECT_EQ(0u, info.GetWriteMessageCallCount());
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->WriteMessage(h, NULL, 0, NULL, 0,
+ MOJO_WRITE_MESSAGE_FLAG_NONE));
+ EXPECT_EQ(1u, info.GetWriteMessageCallCount());
+ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+ core()->WriteMessage(h, NULL, 1, NULL, 0,
+ MOJO_WRITE_MESSAGE_FLAG_NONE));
+ EXPECT_EQ(2u, info.GetWriteMessageCallCount());
+
+ EXPECT_EQ(0u, info.GetReadMessageCallCount());
+ uint32_t num_bytes = 0;
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->ReadMessage(h, NULL, &num_bytes, NULL, NULL,
+ MOJO_READ_MESSAGE_FLAG_NONE));
+ EXPECT_EQ(1u, info.GetReadMessageCallCount());
+ num_bytes = 1;
+ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+ core()->ReadMessage(h, NULL, &num_bytes, NULL, NULL,
+ MOJO_READ_MESSAGE_FLAG_NONE));
+ EXPECT_EQ(2u, info.GetReadMessageCallCount());
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->ReadMessage(h, NULL, NULL, NULL, NULL,
+ MOJO_READ_MESSAGE_FLAG_NONE));
+ EXPECT_EQ(3u, info.GetReadMessageCallCount());
+
+ EXPECT_EQ(0u, info.GetWriteDataCallCount());
+ EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED,
+ core()->WriteData(h, NULL, NULL, MOJO_WRITE_DATA_FLAG_NONE));
+ EXPECT_EQ(1u, info.GetWriteDataCallCount());
+
+ EXPECT_EQ(0u, info.GetBeginWriteDataCallCount());
+ EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED,
+ core()->BeginWriteData(h, NULL, NULL, MOJO_WRITE_DATA_FLAG_NONE));
+ EXPECT_EQ(1u, info.GetBeginWriteDataCallCount());
+
+ EXPECT_EQ(0u, info.GetEndWriteDataCallCount());
+ EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED,
+ core()->EndWriteData(h, 0));
+ EXPECT_EQ(1u, info.GetEndWriteDataCallCount());
+
+ EXPECT_EQ(0u, info.GetReadDataCallCount());
+ EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED,
+ core()->ReadData(h, NULL, NULL, MOJO_READ_DATA_FLAG_NONE));
+ EXPECT_EQ(1u, info.GetReadDataCallCount());
+
+ EXPECT_EQ(0u, info.GetBeginReadDataCallCount());
+ EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED,
+ core()->BeginReadData(h, NULL, NULL, MOJO_READ_DATA_FLAG_NONE));
+ EXPECT_EQ(1u, info.GetBeginReadDataCallCount());
+
+ EXPECT_EQ(0u, info.GetEndReadDataCallCount());
+ EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED,
+ core()->EndReadData(h, 0));
+ EXPECT_EQ(1u, info.GetEndReadDataCallCount());
+
+ EXPECT_EQ(0u, info.GetAddWaiterCallCount());
+ EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
+ core()->Wait(h, ~MOJO_HANDLE_SIGNAL_NONE,
+ MOJO_DEADLINE_INDEFINITE));
+ EXPECT_EQ(1u, info.GetAddWaiterCallCount());
+ EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
+ core()->Wait(h, ~MOJO_HANDLE_SIGNAL_NONE, 0));
+ EXPECT_EQ(2u, info.GetAddWaiterCallCount());
+ EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
+ core()->Wait(h, ~MOJO_HANDLE_SIGNAL_NONE, 10 * 1000));
+ EXPECT_EQ(3u, info.GetAddWaiterCallCount());
+ MojoHandleSignals handle_signals = ~MOJO_HANDLE_SIGNAL_NONE;
+ EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
+ core()->WaitMany(&h, &handle_signals, 1, MOJO_DEADLINE_INDEFINITE));
+ EXPECT_EQ(4u, info.GetAddWaiterCallCount());
+
+ EXPECT_EQ(0u, info.GetDtorCallCount());
+ EXPECT_EQ(0u, info.GetCloseCallCount());
+ EXPECT_EQ(0u, info.GetCancelAllWaitersCallCount());
+ EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h));
+ EXPECT_EQ(1u, info.GetCancelAllWaitersCallCount());
+ EXPECT_EQ(1u, info.GetCloseCallCount());
+ EXPECT_EQ(1u, info.GetDtorCallCount());
+
+ // No waiters should ever have ever been added.
+ EXPECT_EQ(0u, info.GetRemoveWaiterCallCount());
+}
+
+TEST_F(CoreTest, InvalidArguments) {
+ // |Close()|:
+ {
+ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Close(MOJO_HANDLE_INVALID));
+ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Close(10));
+ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Close(1000000000));
+
+ // Test a double-close.
+ MockHandleInfo info;
+ MojoHandle h = CreateMockHandle(&info);
+ EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h));
+ EXPECT_EQ(1u, info.GetCloseCallCount());
+ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Close(h));
+ EXPECT_EQ(1u, info.GetCloseCallCount());
+ }
+
+ // |Wait()|:
+ {
+ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+ core()->Wait(MOJO_HANDLE_INVALID, ~MOJO_HANDLE_SIGNAL_NONE,
+ MOJO_DEADLINE_INDEFINITE));
+ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+ core()->Wait(10, ~MOJO_HANDLE_SIGNAL_NONE,
+ MOJO_DEADLINE_INDEFINITE));
+ }
+
+ // |WaitMany()|:
+ {
+ MojoHandle handles[2] = {MOJO_HANDLE_INVALID, MOJO_HANDLE_INVALID};
+ MojoHandleSignals signals[2] = {~MOJO_HANDLE_SIGNAL_NONE,
+ ~MOJO_HANDLE_SIGNAL_NONE};
+ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+ core()->WaitMany(handles, signals, 0, MOJO_DEADLINE_INDEFINITE));
+ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+ core()->WaitMany(NULL, signals, 0, MOJO_DEADLINE_INDEFINITE));
+ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+ core()->WaitMany(handles, NULL, 0, MOJO_DEADLINE_INDEFINITE));
+
+ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+ core()->WaitMany(NULL, signals, 1, MOJO_DEADLINE_INDEFINITE));
+ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+ core()->WaitMany(handles, NULL, 1, MOJO_DEADLINE_INDEFINITE));
+ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+ core()->WaitMany(handles, signals, 1, MOJO_DEADLINE_INDEFINITE));
+
+ MockHandleInfo info[2];
+ handles[0] = CreateMockHandle(&info[0]);
+
+ EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
+ core()->WaitMany(handles, signals, 1, MOJO_DEADLINE_INDEFINITE));
+ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+ core()->WaitMany(handles, signals, 2, MOJO_DEADLINE_INDEFINITE));
+ handles[1] = handles[0] + 1; // Invalid handle.
+ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+ core()->WaitMany(handles, signals, 2, MOJO_DEADLINE_INDEFINITE));
+ handles[1] = CreateMockHandle(&info[1]);
+ EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
+ core()->WaitMany(handles, signals, 2, MOJO_DEADLINE_INDEFINITE));
+
+ EXPECT_EQ(MOJO_RESULT_OK, core()->Close(handles[0]));
+ EXPECT_EQ(MOJO_RESULT_OK, core()->Close(handles[1]));
+ }
+
+ // |CreateMessagePipe()|:
+ {
+ MojoHandle h;
+ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+ core()->CreateMessagePipe(NULL, NULL, NULL));
+ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+ core()->CreateMessagePipe(NULL, &h, NULL));
+ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+ core()->CreateMessagePipe(NULL, NULL, &h));
+ }
+
+ // |WriteMessage()|:
+ // Only check arguments checked by |Core|, namely |handle|, |handles|, and
+ // |num_handles|.
+ {
+ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+ core()->WriteMessage(MOJO_HANDLE_INVALID, NULL, 0, NULL, 0,
+ MOJO_WRITE_MESSAGE_FLAG_NONE));
+
+ MockHandleInfo info;
+ MojoHandle h = CreateMockHandle(&info);
+ MojoHandle handles[2] = {MOJO_HANDLE_INVALID, MOJO_HANDLE_INVALID};
+
+ // Null |handles| with nonzero |num_handles|.
+ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+ core()->WriteMessage(h, NULL, 0, NULL, 1,
+ MOJO_WRITE_MESSAGE_FLAG_NONE));
+ // Checked by |Core|, shouldn't go through to the dispatcher.
+ EXPECT_EQ(0u, info.GetWriteMessageCallCount());
+
+ // Huge handle count (implausibly big on some systems -- more than can be
+ // stored in a 32-bit address space).
+ // Note: This may return either |MOJO_RESULT_INVALID_ARGUMENT| or
+ // |MOJO_RESULT_RESOURCE_EXHAUSTED|, depending on whether it's plausible or
+ // not.
+ EXPECT_NE(MOJO_RESULT_OK,
+ core()->WriteMessage(h, NULL, 0, handles,
+ std::numeric_limits<uint32_t>::max(),
+ MOJO_WRITE_MESSAGE_FLAG_NONE));
+ EXPECT_EQ(0u, info.GetWriteMessageCallCount());
+
+ // Huge handle count (plausibly big).
+ EXPECT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED,
+ core()->WriteMessage(h, NULL, 0, handles,
+ std::numeric_limits<uint32_t>::max() /
+ sizeof(handles[0]),
+ MOJO_WRITE_MESSAGE_FLAG_NONE));
+ EXPECT_EQ(0u, info.GetWriteMessageCallCount());
+
+ // Invalid handle in |handles|.
+ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+ core()->WriteMessage(h, NULL, 0, handles, 1,
+ MOJO_WRITE_MESSAGE_FLAG_NONE));
+ EXPECT_EQ(0u, info.GetWriteMessageCallCount());
+
+ // Two invalid handles in |handles|.
+ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+ core()->WriteMessage(h, NULL, 0, handles, 2,
+ MOJO_WRITE_MESSAGE_FLAG_NONE));
+ EXPECT_EQ(0u, info.GetWriteMessageCallCount());
+
+ // Can't send a handle over itself.
+ handles[0] = h;
+ EXPECT_EQ(MOJO_RESULT_BUSY,
+ core()->WriteMessage(h, NULL, 0, handles, 1,
+ MOJO_WRITE_MESSAGE_FLAG_NONE));
+ EXPECT_EQ(0u, info.GetWriteMessageCallCount());
+
+ MockHandleInfo info2;
+ MojoHandle h2 = CreateMockHandle(&info2);
+
+ // This is "okay", but |MockDispatcher| doesn't implement it.
+ handles[0] = h2;
+ EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED,
+ core()->WriteMessage(h, NULL, 0, handles, 1,
+ MOJO_WRITE_MESSAGE_FLAG_NONE));
+ EXPECT_EQ(1u, info.GetWriteMessageCallCount());
+
+ // One of the |handles| is still invalid.
+ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+ core()->WriteMessage(h, NULL, 0, handles, 2,
+ MOJO_WRITE_MESSAGE_FLAG_NONE));
+ EXPECT_EQ(1u, info.GetWriteMessageCallCount());
+
+ // One of the |handles| is the same as |handle|.
+ handles[1] = h;
+ EXPECT_EQ(MOJO_RESULT_BUSY,
+ core()->WriteMessage(h, NULL, 0, handles, 2,
+ MOJO_WRITE_MESSAGE_FLAG_NONE));
+ EXPECT_EQ(1u, info.GetWriteMessageCallCount());
+
+ // Can't send a handle twice in the same message.
+ handles[1] = h2;
+ EXPECT_EQ(MOJO_RESULT_BUSY,
+ core()->WriteMessage(h, NULL, 0, handles, 2,
+ MOJO_WRITE_MESSAGE_FLAG_NONE));
+ EXPECT_EQ(1u, info.GetWriteMessageCallCount());
+
+ // Note: Since we never successfully sent anything with it, |h2| should
+ // still be valid.
+ EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h2));
+
+ EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h));
+ }
+
+ // |ReadMessage()|:
+ // Only check arguments checked by |Core|, namely |handle|, |handles|, and
+ // |num_handles|.
+ {
+ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+ core()->ReadMessage(MOJO_HANDLE_INVALID, NULL, NULL, NULL, NULL,
+ MOJO_READ_MESSAGE_FLAG_NONE));
+
+ MockHandleInfo info;
+ MojoHandle h = CreateMockHandle(&info);
+
+ uint32_t handle_count = 1;
+ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+ core()->ReadMessage(h, NULL, NULL, NULL, &handle_count,
+ MOJO_READ_MESSAGE_FLAG_NONE));
+ // Checked by |Core|, shouldn't go through to the dispatcher.
+ EXPECT_EQ(0u, info.GetReadMessageCallCount());
+
+ // Okay.
+ handle_count = 0;
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->ReadMessage(h, NULL, NULL, NULL, &handle_count,
+ MOJO_READ_MESSAGE_FLAG_NONE));
+ // Checked by |Core|, shouldn't go through to the dispatcher.
+ EXPECT_EQ(1u, info.GetReadMessageCallCount());
+
+ EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h));
+ }
+}
+
+// TODO(vtl): test |Wait()| and |WaitMany()| properly
+// - including |WaitMany()| with the same handle more than once (with
+// same/different signals)
+
+TEST_F(CoreTest, MessagePipe) {
+ MojoHandle h[2];
+
+ EXPECT_EQ(MOJO_RESULT_OK, core()->CreateMessagePipe(NULL, &h[0], &h[1]));
+ // Should get two distinct, valid handles.
+ EXPECT_NE(h[0], MOJO_HANDLE_INVALID);
+ EXPECT_NE(h[1], MOJO_HANDLE_INVALID);
+ EXPECT_NE(h[0], h[1]);
+
+ // Neither should be readable.
+ MojoHandleSignals signals[2] = {MOJO_HANDLE_SIGNAL_READABLE,
+ MOJO_HANDLE_SIGNAL_READABLE};
+ EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED,
+ core()->WaitMany(h, signals, 2, 0));
+
+ // Try to read anyway.
+ char buffer[1] = {'a'};
+ uint32_t buffer_size = 1;
+ EXPECT_EQ(MOJO_RESULT_SHOULD_WAIT,
+ core()->ReadMessage(h[0], buffer, &buffer_size, NULL, NULL,
+ MOJO_READ_MESSAGE_FLAG_NONE));
+ // Check that it left its inputs alone.
+ EXPECT_EQ('a', buffer[0]);
+ EXPECT_EQ(1u, buffer_size);
+
+ // Both should be writable.
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->Wait(h[0], MOJO_HANDLE_SIGNAL_WRITABLE, 1000000000));
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->Wait(h[1], MOJO_HANDLE_SIGNAL_WRITABLE, 1000000000));
+
+ // Also check that |h[1]| is writable using |WaitMany()|.
+ signals[0] = MOJO_HANDLE_SIGNAL_READABLE;
+ signals[1] = MOJO_HANDLE_SIGNAL_WRITABLE;
+ EXPECT_EQ(1, core()->WaitMany(h, signals, 2, MOJO_DEADLINE_INDEFINITE));
+
+ // Write to |h[1]|.
+ buffer[0] = 'b';
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->WriteMessage(h[1], buffer, 1, NULL, 0,
+ MOJO_WRITE_MESSAGE_FLAG_NONE));
+
+ // Check that |h[0]| is now readable.
+ signals[0] = MOJO_HANDLE_SIGNAL_READABLE;
+ signals[1] = MOJO_HANDLE_SIGNAL_READABLE;
+ EXPECT_EQ(0, core()->WaitMany(h, signals, 2, MOJO_DEADLINE_INDEFINITE));
+
+ // Read from |h[0]|.
+ // First, get only the size.
+ buffer_size = 0;
+ EXPECT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED,
+ core()->ReadMessage(h[0], NULL, &buffer_size, NULL, NULL,
+ MOJO_READ_MESSAGE_FLAG_NONE));
+ EXPECT_EQ(1u, buffer_size);
+ // Then actually read it.
+ buffer[0] = 'c';
+ buffer_size = 1;
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->ReadMessage(h[0], buffer, &buffer_size, NULL, NULL,
+ MOJO_READ_MESSAGE_FLAG_NONE));
+ EXPECT_EQ('b', buffer[0]);
+ EXPECT_EQ(1u, buffer_size);
+
+ // |h[0]| should no longer be readable.
+ EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED,
+ core()->Wait(h[0], MOJO_HANDLE_SIGNAL_READABLE, 0));
+
+ // Write to |h[0]|.
+ buffer[0] = 'd';
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->WriteMessage(h[0], buffer, 1, NULL, 0,
+ MOJO_WRITE_MESSAGE_FLAG_NONE));
+
+ // Close |h[0]|.
+ EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h[0]));
+
+ // Check that |h[1]| is no longer writable (and will never be).
+ EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
+ core()->Wait(h[1], MOJO_HANDLE_SIGNAL_WRITABLE, 1000000000));
+
+ // Check that |h[1]| is still readable (for the moment).
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->Wait(h[1], MOJO_HANDLE_SIGNAL_READABLE, 1000000000));
+
+ // Discard a message from |h[1]|.
+ EXPECT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED,
+ core()->ReadMessage(h[1], NULL, NULL, NULL, NULL,
+ MOJO_READ_MESSAGE_FLAG_MAY_DISCARD));
+
+ // |h[1]| is no longer readable (and will never be).
+ EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
+ core()->Wait(h[1], MOJO_HANDLE_SIGNAL_READABLE, 1000000000));
+
+ // Try writing to |h[1]|.
+ buffer[0] = 'e';
+ EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
+ core()->WriteMessage(h[1], buffer, 1, NULL, 0,
+ MOJO_WRITE_MESSAGE_FLAG_NONE));
+
+ EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h[1]));
+}
+
+// Tests passing a message pipe handle.
+TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing1) {
+ const char kHello[] = "hello";
+ const uint32_t kHelloSize = static_cast<uint32_t>(sizeof(kHello));
+ const char kWorld[] = "world!!!";
+ const uint32_t kWorldSize = static_cast<uint32_t>(sizeof(kWorld));
+ char buffer[100];
+ const uint32_t kBufferSize = static_cast<uint32_t>(sizeof(buffer));
+ uint32_t num_bytes;
+ MojoHandle handles[10];
+ uint32_t num_handles;
+ MojoHandle h_received;
+
+ MojoHandle h_passing[2];
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->CreateMessagePipe(NULL, &h_passing[0], &h_passing[1]));
+
+ // Make sure that |h_passing[]| work properly.
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->WriteMessage(h_passing[0],
+ kHello, kHelloSize,
+ NULL, 0,
+ MOJO_WRITE_MESSAGE_FLAG_NONE));
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->Wait(h_passing[1], MOJO_HANDLE_SIGNAL_READABLE,
+ 1000000000));
+ num_bytes = kBufferSize;
+ num_handles = arraysize(handles);
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->ReadMessage(h_passing[1],
+ buffer, &num_bytes,
+ handles, &num_handles,
+ MOJO_READ_MESSAGE_FLAG_NONE));
+ EXPECT_EQ(kHelloSize, num_bytes);
+ EXPECT_STREQ(kHello, buffer);
+ EXPECT_EQ(0u, num_handles);
+
+ // Make sure that you can't pass either of the message pipe's handles over
+ // itself.
+ EXPECT_EQ(MOJO_RESULT_BUSY,
+ core()->WriteMessage(h_passing[0],
+ kHello, kHelloSize,
+ &h_passing[0], 1,
+ MOJO_WRITE_MESSAGE_FLAG_NONE));
+ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
+ core()->WriteMessage(h_passing[0],
+ kHello, kHelloSize,
+ &h_passing[1], 1,
+ MOJO_WRITE_MESSAGE_FLAG_NONE));
+
+ MojoHandle h_passed[2];
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->CreateMessagePipe(NULL, &h_passed[0], &h_passed[1]));
+
+ // Make sure that |h_passed[]| work properly.
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->WriteMessage(h_passed[0],
+ kHello, kHelloSize,
+ NULL, 0,
+ MOJO_WRITE_MESSAGE_FLAG_NONE));
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->Wait(h_passed[1], MOJO_HANDLE_SIGNAL_READABLE, 1000000000));
+ num_bytes = kBufferSize;
+ num_handles = arraysize(handles);
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->ReadMessage(h_passed[1],
+ buffer, &num_bytes,
+ handles, &num_handles,
+ MOJO_READ_MESSAGE_FLAG_NONE));
+ EXPECT_EQ(kHelloSize, num_bytes);
+ EXPECT_STREQ(kHello, buffer);
+ EXPECT_EQ(0u, num_handles);
+
+ // Send |h_passed[1]| from |h_passing[0]| to |h_passing[1]|.
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->WriteMessage(h_passing[0],
+ kWorld, kWorldSize,
+ &h_passed[1], 1,
+ MOJO_WRITE_MESSAGE_FLAG_NONE));
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->Wait(h_passing[1], MOJO_HANDLE_SIGNAL_READABLE,
+ 1000000000));
+ num_bytes = kBufferSize;
+ num_handles = arraysize(handles);
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->ReadMessage(h_passing[1],
+ buffer, &num_bytes,
+ handles, &num_handles,
+ MOJO_READ_MESSAGE_FLAG_NONE));
+ EXPECT_EQ(kWorldSize, num_bytes);
+ EXPECT_STREQ(kWorld, buffer);
+ EXPECT_EQ(1u, num_handles);
+ h_received = handles[0];
+ EXPECT_NE(h_received, MOJO_HANDLE_INVALID);
+ EXPECT_NE(h_received, h_passing[0]);
+ EXPECT_NE(h_received, h_passing[1]);
+ EXPECT_NE(h_received, h_passed[0]);
+
+ // Note: We rely on the Mojo system not re-using handle values very often.
+ EXPECT_NE(h_received, h_passed[1]);
+
+ // |h_passed[1]| should no longer be valid; check that trying to close it
+ // fails. See above note.
+ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Close(h_passed[1]));
+
+ // Write to |h_passed[0]|. Should receive on |h_received|.
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->WriteMessage(h_passed[0],
+ kHello, kHelloSize,
+ NULL, 0,
+ MOJO_WRITE_MESSAGE_FLAG_NONE));
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->Wait(h_received, MOJO_HANDLE_SIGNAL_READABLE, 1000000000));
+ num_bytes = kBufferSize;
+ num_handles = arraysize(handles);
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->ReadMessage(h_received,
+ buffer, &num_bytes,
+ handles, &num_handles,
+ MOJO_READ_MESSAGE_FLAG_NONE));
+ EXPECT_EQ(kHelloSize, num_bytes);
+ EXPECT_STREQ(kHello, buffer);
+ EXPECT_EQ(0u, num_handles);
+
+ EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h_passing[0]));
+ EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h_passing[1]));
+ EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h_passed[0]));
+ EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h_received));
+}
+
+TEST_F(CoreTest, DataPipe) {
+ MojoHandle ph, ch; // p is for producer and c is for consumer.
+
+ EXPECT_EQ(MOJO_RESULT_OK, core()->CreateDataPipe(NULL, &ph, &ch));
+ // Should get two distinct, valid handles.
+ EXPECT_NE(ph, MOJO_HANDLE_INVALID);
+ EXPECT_NE(ch, MOJO_HANDLE_INVALID);
+ EXPECT_NE(ph, ch);
+
+ // Producer should be never-readable, but already writable.
+ EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
+ core()->Wait(ph, MOJO_HANDLE_SIGNAL_READABLE, 0));
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->Wait(ph, MOJO_HANDLE_SIGNAL_WRITABLE, 0));
+
+ // Consumer should be never-writable, and not yet readable.
+ EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
+ core()->Wait(ch, MOJO_HANDLE_SIGNAL_WRITABLE, 0));
+ EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED,
+ core()->Wait(ch, MOJO_HANDLE_SIGNAL_READABLE, 0));
+
+ // Write.
+ char elements[2] = {'A', 'B'};
+ uint32_t num_bytes = 2u;
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->WriteData(ph, elements, &num_bytes,
+ MOJO_WRITE_DATA_FLAG_NONE));
+ EXPECT_EQ(2u, num_bytes);
+
+ // Consumer should now be readable.
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->Wait(ch, MOJO_HANDLE_SIGNAL_READABLE, 0));
+
+ // Read one character.
+ elements[0] = -1;
+ elements[1] = -1;
+ num_bytes = 1u;
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->ReadData(ch, elements, &num_bytes,
+ MOJO_READ_DATA_FLAG_NONE));
+ EXPECT_EQ('A', elements[0]);
+ EXPECT_EQ(-1, elements[1]);
+
+ // Two-phase write.
+ void* write_ptr = NULL;
+ num_bytes = 0u;
+ ASSERT_EQ(MOJO_RESULT_OK,
+ core()->BeginWriteData(ph, &write_ptr, &num_bytes,
+ MOJO_WRITE_DATA_FLAG_NONE));
+ // We count on the default options providing a decent buffer size.
+ ASSERT_GE(num_bytes, 3u);
+
+ // Trying to do a normal write during a two-phase write should fail.
+ elements[0] = 'X';
+ num_bytes = 1u;
+ EXPECT_EQ(MOJO_RESULT_BUSY,
+ core()->WriteData(ph, elements, &num_bytes,
+ MOJO_WRITE_DATA_FLAG_NONE));
+
+ // Actually write the data, and complete it now.
+ static_cast<char*>(write_ptr)[0] = 'C';
+ static_cast<char*>(write_ptr)[1] = 'D';
+ static_cast<char*>(write_ptr)[2] = 'E';
+ EXPECT_EQ(MOJO_RESULT_OK, core()->EndWriteData(ph, 3u));
+
+ // Query how much data we have.
+ num_bytes = 0;
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->ReadData(ch, NULL, &num_bytes, MOJO_READ_DATA_FLAG_QUERY));
+ EXPECT_EQ(4u, num_bytes);
+
+ // Try to discard ten characters, in all-or-none mode. Should fail.
+ num_bytes = 10;
+ EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE,
+ core()->ReadData(ch, NULL, &num_bytes,
+ MOJO_READ_DATA_FLAG_DISCARD |
+ MOJO_READ_DATA_FLAG_ALL_OR_NONE));
+
+ // Discard two characters.
+ num_bytes = 2;
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->ReadData(ch, NULL, &num_bytes,
+ MOJO_READ_DATA_FLAG_DISCARD |
+ MOJO_READ_DATA_FLAG_ALL_OR_NONE));
+
+ // Read the remaining two characters, in two-phase mode (all-or-none).
+ const void* read_ptr = NULL;
+ num_bytes = 2;
+ ASSERT_EQ(MOJO_RESULT_OK,
+ core()->BeginReadData(ch, &read_ptr, &num_bytes,
+ MOJO_READ_DATA_FLAG_ALL_OR_NONE));
+ // Note: Count on still being able to do the contiguous read here.
+ ASSERT_EQ(2u, num_bytes);
+
+ // Discarding right now should fail.
+ num_bytes = 1;
+ EXPECT_EQ(MOJO_RESULT_BUSY,
+ core()->ReadData(ch, NULL, &num_bytes,
+ MOJO_READ_DATA_FLAG_DISCARD));
+
+ // Actually check our data and end the two-phase read.
+ EXPECT_EQ('D', static_cast<const char*>(read_ptr)[0]);
+ EXPECT_EQ('E', static_cast<const char*>(read_ptr)[1]);
+ EXPECT_EQ(MOJO_RESULT_OK, core()->EndReadData(ch, 2u));
+
+ // Consumer should now be no longer readable.
+ EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED,
+ core()->Wait(ch, MOJO_HANDLE_SIGNAL_READABLE, 0));
+
+ // TODO(vtl): More.
+
+ // Close the producer.
+ EXPECT_EQ(MOJO_RESULT_OK, core()->Close(ph));
+
+ // The consumer should now be never-readable.
+ EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
+ core()->Wait(ch, MOJO_HANDLE_SIGNAL_READABLE, 0));
+
+ EXPECT_EQ(MOJO_RESULT_OK, core()->Close(ch));
+}
+
+// Tests passing data pipe producer and consumer handles.
+TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) {
+ const char kHello[] = "hello";
+ const uint32_t kHelloSize = static_cast<uint32_t>(sizeof(kHello));
+ const char kWorld[] = "world!!!";
+ const uint32_t kWorldSize = static_cast<uint32_t>(sizeof(kWorld));
+ char buffer[100];
+ const uint32_t kBufferSize = static_cast<uint32_t>(sizeof(buffer));
+ uint32_t num_bytes;
+ MojoHandle handles[10];
+ uint32_t num_handles;
+
+ MojoHandle h_passing[2];
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->CreateMessagePipe(NULL, &h_passing[0], &h_passing[1]));
+
+ MojoHandle ph, ch;
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->CreateDataPipe(NULL, &ph, &ch));
+
+ // Send |ch| from |h_passing[0]| to |h_passing[1]|.
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->WriteMessage(h_passing[0],
+ kHello, kHelloSize,
+ &ch, 1,
+ MOJO_WRITE_MESSAGE_FLAG_NONE));
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->Wait(h_passing[1], MOJO_HANDLE_SIGNAL_READABLE,
+ 1000000000));
+ num_bytes = kBufferSize;
+ num_handles = arraysize(handles);
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->ReadMessage(h_passing[1],
+ buffer, &num_bytes,
+ handles, &num_handles,
+ MOJO_READ_MESSAGE_FLAG_NONE));
+ EXPECT_EQ(kHelloSize, num_bytes);
+ EXPECT_STREQ(kHello, buffer);
+ EXPECT_EQ(1u, num_handles);
+ MojoHandle ch_received = handles[0];
+ EXPECT_NE(ch_received, MOJO_HANDLE_INVALID);
+ EXPECT_NE(ch_received, h_passing[0]);
+ EXPECT_NE(ch_received, h_passing[1]);
+ EXPECT_NE(ch_received, ph);
+
+ // Note: We rely on the Mojo system not re-using handle values very often.
+ EXPECT_NE(ch_received, ch);
+
+ // |ch| should no longer be valid; check that trying to close it fails. See
+ // above note.
+ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Close(ch));
+
+ // Write to |ph|. Should receive on |ch_received|.
+ num_bytes = kWorldSize;
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->WriteData(ph, kWorld, &num_bytes,
+ MOJO_WRITE_DATA_FLAG_ALL_OR_NONE));
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->Wait(ch_received, MOJO_HANDLE_SIGNAL_READABLE, 1000000000));
+ num_bytes = kBufferSize;
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->ReadData(ch_received, buffer, &num_bytes,
+ MOJO_READ_MESSAGE_FLAG_NONE));
+ EXPECT_EQ(kWorldSize, num_bytes);
+ EXPECT_STREQ(kWorld, buffer);
+
+ // Now pass |ph| in the same direction.
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->WriteMessage(h_passing[0],
+ kWorld, kWorldSize,
+ &ph, 1,
+ MOJO_WRITE_MESSAGE_FLAG_NONE));
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->Wait(h_passing[1], MOJO_HANDLE_SIGNAL_READABLE,
+ 1000000000));
+ num_bytes = kBufferSize;
+ num_handles = arraysize(handles);
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->ReadMessage(h_passing[1],
+ buffer, &num_bytes,
+ handles, &num_handles,
+ MOJO_READ_MESSAGE_FLAG_NONE));
+ EXPECT_EQ(kWorldSize, num_bytes);
+ EXPECT_STREQ(kWorld, buffer);
+ EXPECT_EQ(1u, num_handles);
+ MojoHandle ph_received = handles[0];
+ EXPECT_NE(ph_received, MOJO_HANDLE_INVALID);
+ EXPECT_NE(ph_received, h_passing[0]);
+ EXPECT_NE(ph_received, h_passing[1]);
+ EXPECT_NE(ph_received, ch_received);
+
+ // Again, rely on the Mojo system not re-using handle values very often.
+ EXPECT_NE(ph_received, ph);
+
+ // |ph| should no longer be valid; check that trying to close it fails. See
+ // above note.
+ EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Close(ph));
+
+ // Write to |ph_received|. Should receive on |ch_received|.
+ num_bytes = kHelloSize;
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->WriteData(ph_received, kHello, &num_bytes,
+ MOJO_WRITE_DATA_FLAG_ALL_OR_NONE));
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->Wait(ch_received, MOJO_HANDLE_SIGNAL_READABLE, 1000000000));
+ num_bytes = kBufferSize;
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->ReadData(ch_received, buffer, &num_bytes,
+ MOJO_READ_MESSAGE_FLAG_NONE));
+ EXPECT_EQ(kHelloSize, num_bytes);
+ EXPECT_STREQ(kHello, buffer);
+
+ ph = ph_received;
+ ph_received = MOJO_HANDLE_INVALID;
+ ch = ch_received;
+ ch_received = MOJO_HANDLE_INVALID;
+
+ // Make sure that |ph| can't be sent if it's in a two-phase write.
+ void* write_ptr = NULL;
+ num_bytes = 0;
+ ASSERT_EQ(MOJO_RESULT_OK,
+ core()->BeginWriteData(ph, &write_ptr, &num_bytes,
+ MOJO_WRITE_DATA_FLAG_NONE));
+ ASSERT_GE(num_bytes, 1u);
+ EXPECT_EQ(MOJO_RESULT_BUSY,
+ core()->WriteMessage(h_passing[0],
+ kHello, kHelloSize,
+ &ph, 1,
+ MOJO_WRITE_MESSAGE_FLAG_NONE));
+
+ // But |ch| can, even if |ph| is in a two-phase write.
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->WriteMessage(h_passing[0],
+ kHello, kHelloSize,
+ &ch, 1,
+ MOJO_WRITE_MESSAGE_FLAG_NONE));
+ ch = MOJO_HANDLE_INVALID;
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->Wait(h_passing[1], MOJO_HANDLE_SIGNAL_READABLE,
+ 1000000000));
+ num_bytes = kBufferSize;
+ num_handles = arraysize(handles);
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->ReadMessage(h_passing[1],
+ buffer, &num_bytes,
+ handles, &num_handles,
+ MOJO_READ_MESSAGE_FLAG_NONE));
+ EXPECT_EQ(kHelloSize, num_bytes);
+ EXPECT_STREQ(kHello, buffer);
+ EXPECT_EQ(1u, num_handles);
+ ch = handles[0];
+ EXPECT_NE(ch, MOJO_HANDLE_INVALID);
+
+ // Complete the two-phase write.
+ static_cast<char*>(write_ptr)[0] = 'x';
+ EXPECT_EQ(MOJO_RESULT_OK, core()->EndWriteData(ph, 1));
+
+ // Wait for |ch| to be readable.
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->Wait(ch, MOJO_HANDLE_SIGNAL_READABLE, 1000000000));
+
+ // Make sure that |ch| can't be sent if it's in a two-phase read.
+ const void* read_ptr = NULL;
+ num_bytes = 1;
+ ASSERT_EQ(MOJO_RESULT_OK,
+ core()->BeginReadData(ch, &read_ptr, &num_bytes,
+ MOJO_READ_DATA_FLAG_ALL_OR_NONE));
+ EXPECT_EQ(MOJO_RESULT_BUSY,
+ core()->WriteMessage(h_passing[0],
+ kHello, kHelloSize,
+ &ch, 1,
+ MOJO_WRITE_MESSAGE_FLAG_NONE));
+
+ // But |ph| can, even if |ch| is in a two-phase read.
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->WriteMessage(h_passing[0],
+ kWorld, kWorldSize,
+ &ph, 1,
+ MOJO_WRITE_MESSAGE_FLAG_NONE));
+ ph = MOJO_HANDLE_INVALID;
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->Wait(h_passing[1], MOJO_HANDLE_SIGNAL_READABLE,
+ 1000000000));
+ num_bytes = kBufferSize;
+ num_handles = arraysize(handles);
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->ReadMessage(h_passing[1],
+ buffer, &num_bytes,
+ handles, &num_handles,
+ MOJO_READ_MESSAGE_FLAG_NONE));
+ EXPECT_EQ(kWorldSize, num_bytes);
+ EXPECT_STREQ(kWorld, buffer);
+ EXPECT_EQ(1u, num_handles);
+ ph = handles[0];
+ EXPECT_NE(ph, MOJO_HANDLE_INVALID);
+
+ // Complete the two-phase read.
+ EXPECT_EQ('x', static_cast<const char*>(read_ptr)[0]);
+ EXPECT_EQ(MOJO_RESULT_OK, core()->EndReadData(ch, 1));
+
+ EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h_passing[0]));
+ EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h_passing[1]));
+ EXPECT_EQ(MOJO_RESULT_OK, core()->Close(ph));
+ EXPECT_EQ(MOJO_RESULT_OK, core()->Close(ch));
+}
+
+// TODO(vtl): Test |DuplicateBufferHandle()| and |MapBuffer()|.
+
+} // namespace
+} // namespace system
+} // namespace mojo