blob: c10c468bfd0d084384c3c7fc925f4310cb58a9b4 [file] [log] [blame]
// Copyright 2016 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.
// This file tests the C message pipe API (the functions declared in
// mojo/public/c/include/mojo/system/message_pipe.h).
#include <mojo/system/message_pipe.h>
#include <mojo/result.h>
#include <mojo/system/buffer.h>
#include <mojo/system/handle.h>
#include <mojo/system/wait.h>
#include "gtest/gtest.h"
namespace {
const MojoHandleRights kDefaultMessagePipeHandleRights =
MOJO_HANDLE_RIGHT_TRANSFER | MOJO_HANDLE_RIGHT_READ |
MOJO_HANDLE_RIGHT_WRITE | MOJO_HANDLE_RIGHT_GET_OPTIONS |
MOJO_HANDLE_RIGHT_SET_OPTIONS;
TEST(MessagePipeTest, InvalidHandle) {
char buffer[10] = {};
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
MojoWriteMessage(MOJO_HANDLE_INVALID, buffer, 0u, nullptr, 0u,
MOJO_WRITE_MESSAGE_FLAG_NONE));
uint32_t buffer_size = static_cast<uint32_t>(sizeof(buffer));
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
MojoReadMessage(MOJO_HANDLE_INVALID, buffer, &buffer_size, nullptr,
nullptr, MOJO_READ_MESSAGE_FLAG_NONE));
}
TEST(MessagePipeTest, Basic) {
MojoHandle h0 = MOJO_HANDLE_INVALID;
MojoHandle h1 = MOJO_HANDLE_INVALID;
EXPECT_EQ(MOJO_RESULT_OK, MojoCreateMessagePipe(nullptr, &h0, &h1));
EXPECT_NE(h0, MOJO_HANDLE_INVALID);
EXPECT_NE(h1, MOJO_HANDLE_INVALID);
EXPECT_NE(h0, h1);
// Both handles should have the correct rights.
MojoHandleRights rights = MOJO_HANDLE_RIGHT_NONE;
EXPECT_EQ(MOJO_RESULT_OK, MojoGetRights(h0, &rights));
EXPECT_EQ(kDefaultMessagePipeHandleRights, rights);
rights = MOJO_HANDLE_RIGHT_NONE;
EXPECT_EQ(MOJO_RESULT_OK, MojoGetRights(h1, &rights));
EXPECT_EQ(kDefaultMessagePipeHandleRights, rights);
// Shouldn't be able to duplicate either handle (just test "with reduced
// rights" on one, and without on the other).
MojoHandle handle_denied = MOJO_HANDLE_INVALID;
EXPECT_EQ(MOJO_RESULT_PERMISSION_DENIED,
MojoDuplicateHandleWithReducedRights(
h0, MOJO_HANDLE_RIGHT_DUPLICATE, &handle_denied));
EXPECT_EQ(MOJO_HANDLE_INVALID, handle_denied);
handle_denied = MOJO_HANDLE_INVALID;
EXPECT_EQ(MOJO_RESULT_PERMISSION_DENIED,
MojoDuplicateHandle(h1, &handle_denied));
EXPECT_EQ(MOJO_HANDLE_INVALID, handle_denied);
// Shouldn't be readable, we haven't written anything.
MojoHandleSignalsState state;
EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED,
MojoWait(h0, MOJO_HANDLE_SIGNAL_READABLE, 0, &state));
EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, state.satisfied_signals);
EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE |
MOJO_HANDLE_SIGNAL_PEER_CLOSED,
state.satisfiable_signals);
// Should be writable.
EXPECT_EQ(MOJO_RESULT_OK,
MojoWait(h0, MOJO_HANDLE_SIGNAL_WRITABLE, 0, &state));
EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, state.satisfied_signals);
EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE |
MOJO_HANDLE_SIGNAL_PEER_CLOSED,
state.satisfiable_signals);
// Last parameter is optional.
EXPECT_EQ(MOJO_RESULT_OK,
MojoWait(h0, MOJO_HANDLE_SIGNAL_WRITABLE, 0, nullptr));
// Try to read.
char buffer[10] = {};
uint32_t buffer_size = static_cast<uint32_t>(sizeof(buffer));
EXPECT_EQ(MOJO_RESULT_SHOULD_WAIT,
MojoReadMessage(h0, buffer, &buffer_size, nullptr, nullptr,
MOJO_READ_MESSAGE_FLAG_NONE));
// Write to |h1|.
static const char kHello[] = "hello";
buffer_size = static_cast<uint32_t>(sizeof(kHello));
EXPECT_EQ(MOJO_RESULT_OK, MojoWriteMessage(h1, kHello, buffer_size, nullptr,
0, MOJO_WRITE_MESSAGE_FLAG_NONE));
// |h0| should be readable.
MojoHandleSignals sig = MOJO_HANDLE_SIGNAL_READABLE;
MojoHandleSignalsState states[1] = {};
uint32_t result_index = 1;
EXPECT_EQ(MOJO_RESULT_OK, MojoWaitMany(&h0, &sig, 1, MOJO_DEADLINE_INDEFINITE,
&result_index, states));
EXPECT_EQ(0u, result_index);
EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
states[0].satisfied_signals);
EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE |
MOJO_HANDLE_SIGNAL_PEER_CLOSED,
states[0].satisfiable_signals);
// Read from |h0|.
buffer_size = static_cast<uint32_t>(sizeof(buffer));
EXPECT_EQ(MOJO_RESULT_OK,
MojoReadMessage(h0, buffer, &buffer_size, nullptr, nullptr,
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(static_cast<uint32_t>(sizeof(kHello)), buffer_size);
EXPECT_STREQ(kHello, buffer);
// |h0| should no longer be readable.
EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED,
MojoWait(h0, MOJO_HANDLE_SIGNAL_READABLE, 10, &state));
EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, state.satisfied_signals);
EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE |
MOJO_HANDLE_SIGNAL_PEER_CLOSED,
state.satisfiable_signals);
// Close |h0|.
EXPECT_EQ(MOJO_RESULT_OK, MojoClose(h0));
// |h1| should no longer be readable or writable.
EXPECT_EQ(
MOJO_RESULT_FAILED_PRECONDITION,
MojoWait(h1, MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
1000, &state));
EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfied_signals);
EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfiable_signals);
EXPECT_EQ(MOJO_RESULT_OK, MojoClose(h1));
}
TEST(MessagePipeTest, ChecksTransferRight) {
MojoHandle h0 = MOJO_HANDLE_INVALID;
MojoHandle h1 = MOJO_HANDLE_INVALID;
EXPECT_EQ(MOJO_RESULT_OK, MojoCreateMessagePipe(nullptr, &h0, &h1));
// Create a shared buffer (which is transferrable and duplicatable).
MojoHandle h_transferrable = MOJO_HANDLE_INVALID;
EXPECT_EQ(MOJO_RESULT_OK,
MojoCreateSharedBuffer(nullptr, 100, &h_transferrable));
// Make a non-transferrable duplicate handle.
MojoHandle h_not_transferrable = MOJO_HANDLE_INVALID;
EXPECT_EQ(MOJO_RESULT_OK, MojoDuplicateHandleWithReducedRights(
h_transferrable, MOJO_HANDLE_RIGHT_TRANSFER,
&h_not_transferrable));
// |h_transferrable| can be transferred.
EXPECT_EQ(MOJO_RESULT_OK, MojoWriteMessage(h0, nullptr, 0u, &h_transferrable,
1u, MOJO_WRITE_MESSAGE_FLAG_NONE));
// |h_not_transferrable| can be transferred.
EXPECT_EQ(MOJO_RESULT_PERMISSION_DENIED,
MojoWriteMessage(h0, nullptr, 0u, &h_not_transferrable, 1u,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(MOJO_RESULT_OK, MojoClose(h0));
EXPECT_EQ(MOJO_RESULT_OK, MojoClose(h1));
EXPECT_EQ(MOJO_RESULT_OK, MojoClose(h_not_transferrable));
}
// TODO(vtl): Add multi-threaded tests.
} // namespace