// 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/core/core.h"
|
|
#include <stdint.h>
|
|
#include <limits>
|
|
#include "base/bind.h"
|
#include "build/build_config.h"
|
#include "mojo/core/core_test_base.h"
|
#include "mojo/core/test_utils.h"
|
#include "mojo/public/cpp/system/wait.h"
|
|
#if defined(OS_WIN)
|
#include "base/win/windows_version.h"
|
#endif
|
|
namespace mojo {
|
namespace core {
|
namespace {
|
|
const MojoHandleSignalsState kEmptyMojoHandleSignalsState = {0u, 0u};
|
const MojoHandleSignalsState kFullMojoHandleSignalsState = {~0u, ~0u};
|
const MojoHandleSignals kAllSignals =
|
MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE |
|
MOJO_HANDLE_SIGNAL_PEER_CLOSED | MOJO_HANDLE_SIGNAL_PEER_REMOTE |
|
MOJO_HANDLE_SIGNAL_QUOTA_EXCEEDED;
|
|
using CoreTest = test::CoreTestBase;
|
|
TEST_F(CoreTest, GetTimeTicksNow) {
|
const MojoTimeTicks start = core()->GetTimeTicksNow();
|
ASSERT_NE(static_cast<MojoTimeTicks>(0), start)
|
<< "GetTimeTicksNow should return nonzero value";
|
test::Sleep(test::DeadlineFromMilliseconds(15));
|
const MojoTimeTicks finish = core()->GetTimeTicksNow();
|
// Allow for some fuzz in sleep.
|
ASSERT_GE((finish - start), static_cast<MojoTimeTicks>(8000))
|
<< "Sleeping should result in increasing time ticks";
|
}
|
|
TEST_F(CoreTest, Basic) {
|
MockHandleInfo info;
|
|
ASSERT_EQ(0u, info.GetCtorCallCount());
|
MojoHandle h = CreateMockHandle(&info);
|
ASSERT_EQ(1u, info.GetCtorCallCount());
|
ASSERT_NE(h, MOJO_HANDLE_INVALID);
|
|
ASSERT_EQ(0u, info.GetWriteMessageCallCount());
|
MojoMessageHandle message;
|
ASSERT_EQ(MOJO_RESULT_OK, core()->CreateMessage(nullptr, &message));
|
ASSERT_EQ(MOJO_RESULT_OK, core()->WriteMessage(h, message, nullptr));
|
ASSERT_EQ(1u, info.GetWriteMessageCallCount());
|
|
ASSERT_EQ(0u, info.GetReadMessageCallCount());
|
ASSERT_EQ(MOJO_RESULT_OK, core()->ReadMessage(h, nullptr, &message));
|
ASSERT_EQ(1u, info.GetReadMessageCallCount());
|
ASSERT_EQ(MOJO_RESULT_OK, core()->ReadMessage(h, nullptr, &message));
|
ASSERT_EQ(2u, info.GetReadMessageCallCount());
|
|
ASSERT_EQ(0u, info.GetWriteDataCallCount());
|
ASSERT_EQ(MOJO_RESULT_UNIMPLEMENTED,
|
core()->WriteData(h, nullptr, nullptr, nullptr));
|
ASSERT_EQ(1u, info.GetWriteDataCallCount());
|
|
ASSERT_EQ(0u, info.GetBeginWriteDataCallCount());
|
ASSERT_EQ(MOJO_RESULT_UNIMPLEMENTED,
|
core()->BeginWriteData(h, nullptr, nullptr, nullptr));
|
ASSERT_EQ(1u, info.GetBeginWriteDataCallCount());
|
|
ASSERT_EQ(0u, info.GetEndWriteDataCallCount());
|
ASSERT_EQ(MOJO_RESULT_UNIMPLEMENTED, core()->EndWriteData(h, 0, nullptr));
|
ASSERT_EQ(1u, info.GetEndWriteDataCallCount());
|
|
ASSERT_EQ(0u, info.GetReadDataCallCount());
|
ASSERT_EQ(MOJO_RESULT_UNIMPLEMENTED,
|
core()->ReadData(h, nullptr, nullptr, nullptr));
|
ASSERT_EQ(1u, info.GetReadDataCallCount());
|
|
ASSERT_EQ(0u, info.GetBeginReadDataCallCount());
|
ASSERT_EQ(MOJO_RESULT_UNIMPLEMENTED,
|
core()->BeginReadData(h, nullptr, nullptr, nullptr));
|
ASSERT_EQ(1u, info.GetBeginReadDataCallCount());
|
|
ASSERT_EQ(0u, info.GetEndReadDataCallCount());
|
ASSERT_EQ(MOJO_RESULT_UNIMPLEMENTED, core()->EndReadData(h, 0, nullptr));
|
ASSERT_EQ(1u, info.GetEndReadDataCallCount());
|
|
ASSERT_EQ(0u, info.GetDtorCallCount());
|
ASSERT_EQ(0u, info.GetCloseCallCount());
|
ASSERT_EQ(MOJO_RESULT_OK, core()->Close(h));
|
ASSERT_EQ(1u, info.GetCloseCallCount());
|
ASSERT_EQ(1u, info.GetDtorCallCount());
|
}
|
|
TEST_F(CoreTest, InvalidArguments) {
|
// |Close()|:
|
{
|
ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Close(MOJO_HANDLE_INVALID));
|
ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Close(10));
|
ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Close(1000000000));
|
|
// Test a double-close.
|
MockHandleInfo info;
|
MojoHandle h = CreateMockHandle(&info);
|
ASSERT_EQ(MOJO_RESULT_OK, core()->Close(h));
|
ASSERT_EQ(1u, info.GetCloseCallCount());
|
ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Close(h));
|
ASSERT_EQ(1u, info.GetCloseCallCount());
|
}
|
|
// |CreateMessagePipe()|: Nothing to check (apart from things that cause
|
// death).
|
|
// |WriteMessageNew()|:
|
// Only check arguments checked by |Core|, namely |handle|, |handles|, and
|
// |num_handles|.
|
ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
|
core()->WriteMessage(MOJO_HANDLE_INVALID, 0, nullptr));
|
|
// |ReadMessageNew()|:
|
// Only check arguments checked by |Core|, namely |handle|, |handles|, and
|
// |num_handles|.
|
{
|
ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
|
core()->ReadMessage(MOJO_HANDLE_INVALID, nullptr, nullptr));
|
|
MockHandleInfo info;
|
MojoHandle h = CreateMockHandle(&info);
|
ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
|
core()->ReadMessage(h, nullptr, nullptr));
|
// Checked by |Core|, shouldn't go through to the dispatcher.
|
ASSERT_EQ(0u, info.GetReadMessageCallCount());
|
ASSERT_EQ(MOJO_RESULT_OK, core()->Close(h));
|
}
|
}
|
|
TEST_F(CoreTest, MessagePipe) {
|
MojoHandle h[2];
|
MojoHandleSignalsState hss[2];
|
|
ASSERT_EQ(MOJO_RESULT_OK, core()->CreateMessagePipe(nullptr, &h[0], &h[1]));
|
// Should get two distinct, valid handles.
|
ASSERT_NE(h[0], MOJO_HANDLE_INVALID);
|
ASSERT_NE(h[1], MOJO_HANDLE_INVALID);
|
ASSERT_NE(h[0], h[1]);
|
|
// Neither should be readable.
|
hss[0] = kEmptyMojoHandleSignalsState;
|
hss[1] = kEmptyMojoHandleSignalsState;
|
EXPECT_EQ(MOJO_RESULT_OK, core()->QueryHandleSignalsState(h[0], &hss[0]));
|
EXPECT_EQ(MOJO_RESULT_OK, core()->QueryHandleSignalsState(h[1], &hss[1]));
|
ASSERT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[0].satisfied_signals);
|
ASSERT_EQ(kAllSignals, hss[0].satisfiable_signals);
|
ASSERT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[1].satisfied_signals);
|
ASSERT_EQ(kAllSignals, hss[1].satisfiable_signals);
|
|
// Try to read anyway.
|
MojoMessageHandle message;
|
ASSERT_EQ(MOJO_RESULT_SHOULD_WAIT,
|
core()->ReadMessage(h[0], nullptr, &message));
|
|
// Write to |h[1]|.
|
const uintptr_t kTestMessageContext = 123;
|
ASSERT_EQ(MOJO_RESULT_OK, core()->CreateMessage(nullptr, &message));
|
ASSERT_EQ(MOJO_RESULT_OK,
|
core()->SetMessageContext(message, kTestMessageContext, nullptr,
|
nullptr, nullptr));
|
ASSERT_EQ(MOJO_RESULT_OK, core()->WriteMessage(h[1], message, nullptr));
|
|
// Wait for |h[0]| to become readable.
|
EXPECT_EQ(MOJO_RESULT_OK, mojo::Wait(mojo::Handle(h[0]),
|
MOJO_HANDLE_SIGNAL_READABLE, &hss[0]));
|
|
// Read from |h[0]|.
|
ASSERT_EQ(MOJO_RESULT_OK, core()->ReadMessage(h[0], nullptr, &message));
|
uintptr_t context;
|
ASSERT_EQ(MOJO_RESULT_OK,
|
core()->GetMessageContext(message, nullptr, &context));
|
ASSERT_EQ(MOJO_RESULT_OK,
|
core()->SetMessageContext(message, 0, nullptr, nullptr, nullptr));
|
ASSERT_EQ(kTestMessageContext, context);
|
ASSERT_EQ(MOJO_RESULT_OK, core()->DestroyMessage(message));
|
|
// |h[0]| should no longer be readable.
|
hss[0] = kEmptyMojoHandleSignalsState;
|
EXPECT_EQ(MOJO_RESULT_OK, core()->QueryHandleSignalsState(h[0], &hss[0]));
|
ASSERT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[0].satisfied_signals);
|
ASSERT_EQ(kAllSignals, hss[0].satisfiable_signals);
|
|
// Write to |h[0]|.
|
ASSERT_EQ(MOJO_RESULT_OK, core()->CreateMessage(nullptr, &message));
|
ASSERT_EQ(MOJO_RESULT_OK,
|
core()->SetMessageContext(message, kTestMessageContext, nullptr,
|
nullptr, nullptr));
|
ASSERT_EQ(MOJO_RESULT_OK, core()->WriteMessage(h[0], message, nullptr));
|
|
// Close |h[0]|.
|
ASSERT_EQ(MOJO_RESULT_OK, core()->Close(h[0]));
|
|
// Wait for |h[1]| to learn about the other end's closure.
|
EXPECT_EQ(
|
MOJO_RESULT_OK,
|
mojo::Wait(mojo::Handle(h[1]), MOJO_HANDLE_SIGNAL_PEER_CLOSED, &hss[1]));
|
|
// Check that |h[1]| is no longer writable (and will never be).
|
EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
|
hss[1].satisfied_signals);
|
EXPECT_FALSE(hss[1].satisfiable_signals & MOJO_HANDLE_SIGNAL_WRITABLE);
|
|
// Check that |h[1]| is still readable (for the moment).
|
EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
|
hss[1].satisfied_signals);
|
EXPECT_TRUE(hss[1].satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE);
|
|
// Discard a message from |h[1]|.
|
ASSERT_EQ(MOJO_RESULT_OK, core()->ReadMessage(h[1], nullptr, &message));
|
ASSERT_EQ(MOJO_RESULT_OK, core()->DestroyMessage(message));
|
|
// |h[1]| is no longer readable (and will never be).
|
hss[1] = kFullMojoHandleSignalsState;
|
EXPECT_EQ(MOJO_RESULT_OK, core()->QueryHandleSignalsState(h[1], &hss[1]));
|
EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss[1].satisfied_signals);
|
EXPECT_FALSE(hss[1].satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE);
|
|
// Try writing to |h[1]|.
|
ASSERT_EQ(MOJO_RESULT_OK, core()->CreateMessage(nullptr, &message));
|
ASSERT_EQ(MOJO_RESULT_OK,
|
core()->SetMessageContext(message, kTestMessageContext, nullptr,
|
nullptr, nullptr));
|
ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
|
core()->WriteMessage(h[1], message, nullptr));
|
|
ASSERT_EQ(MOJO_RESULT_OK, core()->Close(h[1]));
|
}
|
|
// Tests passing a message pipe handle.
|
TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing1) {
|
MojoHandleSignalsState hss;
|
MojoHandle h_passing[2];
|
ASSERT_EQ(MOJO_RESULT_OK,
|
core()->CreateMessagePipe(nullptr, &h_passing[0], &h_passing[1]));
|
|
// Make sure that |h_passing[]| work properly.
|
const uintptr_t kTestMessageContext = 42;
|
MojoMessageHandle message;
|
ASSERT_EQ(MOJO_RESULT_OK, core()->CreateMessage(nullptr, &message));
|
ASSERT_EQ(MOJO_RESULT_OK,
|
core()->SetMessageContext(message, kTestMessageContext, nullptr,
|
nullptr, nullptr));
|
ASSERT_EQ(MOJO_RESULT_OK,
|
core()->WriteMessage(h_passing[0], message, nullptr));
|
hss = kEmptyMojoHandleSignalsState;
|
EXPECT_EQ(MOJO_RESULT_OK, mojo::Wait(mojo::Handle(h_passing[1]),
|
MOJO_HANDLE_SIGNAL_READABLE, &hss));
|
ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
|
hss.satisfied_signals);
|
ASSERT_EQ(kAllSignals, hss.satisfiable_signals);
|
MojoMessageHandle message_handle;
|
ASSERT_EQ(MOJO_RESULT_OK,
|
core()->ReadMessage(h_passing[1], nullptr, &message_handle));
|
uintptr_t context;
|
ASSERT_EQ(MOJO_RESULT_OK,
|
core()->GetMessageContext(message_handle, nullptr, &context));
|
ASSERT_EQ(MOJO_RESULT_OK,
|
core()->SetMessageContext(message, 0, nullptr, nullptr, nullptr));
|
ASSERT_EQ(kTestMessageContext, context);
|
ASSERT_EQ(MOJO_RESULT_OK, MojoDestroyMessage(message_handle));
|
|
ASSERT_EQ(MOJO_RESULT_OK, core()->Close(h_passing[0]));
|
ASSERT_EQ(MOJO_RESULT_OK, core()->Close(h_passing[1]));
|
}
|
|
TEST_F(CoreTest, DataPipe) {
|
MojoHandle ph, ch; // p is for producer and c is for consumer.
|
MojoHandleSignalsState hss;
|
|
ASSERT_EQ(MOJO_RESULT_OK, core()->CreateDataPipe(nullptr, &ph, &ch));
|
// Should get two distinct, valid handles.
|
ASSERT_NE(ph, MOJO_HANDLE_INVALID);
|
ASSERT_NE(ch, MOJO_HANDLE_INVALID);
|
ASSERT_NE(ph, ch);
|
|
// Producer should be never-readable, but already writable.
|
hss = kEmptyMojoHandleSignalsState;
|
EXPECT_EQ(MOJO_RESULT_OK, core()->QueryHandleSignalsState(ph, &hss));
|
ASSERT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals);
|
ASSERT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
|
MOJO_HANDLE_SIGNAL_PEER_REMOTE,
|
hss.satisfiable_signals);
|
|
// Consumer should be never-writable, and not yet readable.
|
hss = kFullMojoHandleSignalsState;
|
EXPECT_EQ(MOJO_RESULT_OK, core()->QueryHandleSignalsState(ch, &hss));
|
EXPECT_EQ(0u, hss.satisfied_signals);
|
EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
|
MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE |
|
MOJO_HANDLE_SIGNAL_PEER_REMOTE,
|
hss.satisfiable_signals);
|
|
// Write.
|
signed char elements[2] = {'A', 'B'};
|
uint32_t num_bytes = 2u;
|
ASSERT_EQ(MOJO_RESULT_OK,
|
core()->WriteData(ph, elements, &num_bytes, nullptr));
|
ASSERT_EQ(2u, num_bytes);
|
|
// Wait for the data to arrive to the consumer.
|
EXPECT_EQ(MOJO_RESULT_OK,
|
mojo::Wait(mojo::Handle(ch), MOJO_HANDLE_SIGNAL_READABLE, &hss));
|
|
// Consumer should now be readable.
|
hss = kEmptyMojoHandleSignalsState;
|
EXPECT_EQ(MOJO_RESULT_OK, core()->QueryHandleSignalsState(ch, &hss));
|
EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
|
hss.satisfied_signals);
|
EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
|
MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE |
|
MOJO_HANDLE_SIGNAL_PEER_REMOTE,
|
hss.satisfiable_signals);
|
|
// Peek one character.
|
elements[0] = -1;
|
elements[1] = -1;
|
num_bytes = 1u;
|
MojoReadDataOptions read_options;
|
read_options.struct_size = sizeof(read_options);
|
read_options.flags = MOJO_READ_DATA_FLAG_NONE | MOJO_READ_DATA_FLAG_PEEK;
|
ASSERT_EQ(MOJO_RESULT_OK,
|
core()->ReadData(ch, &read_options, elements, &num_bytes));
|
ASSERT_EQ('A', elements[0]);
|
ASSERT_EQ(-1, elements[1]);
|
|
// Read one character.
|
elements[0] = -1;
|
elements[1] = -1;
|
num_bytes = 1u;
|
read_options.flags = MOJO_READ_DATA_FLAG_NONE;
|
ASSERT_EQ(MOJO_RESULT_OK,
|
core()->ReadData(ch, &read_options, elements, &num_bytes));
|
ASSERT_EQ('A', elements[0]);
|
ASSERT_EQ(-1, elements[1]);
|
|
// Two-phase write.
|
void* write_ptr = nullptr;
|
num_bytes = 0u;
|
ASSERT_EQ(MOJO_RESULT_OK,
|
core()->BeginWriteData(ph, nullptr, &write_ptr, &num_bytes));
|
// 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;
|
ASSERT_EQ(MOJO_RESULT_BUSY,
|
core()->WriteData(ph, elements, &num_bytes, nullptr));
|
|
// 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';
|
ASSERT_EQ(MOJO_RESULT_OK, core()->EndWriteData(ph, 3u, nullptr));
|
|
// Wait for the data to arrive to the consumer.
|
ASSERT_EQ(MOJO_RESULT_OK,
|
mojo::Wait(mojo::Handle(ch), MOJO_HANDLE_SIGNAL_READABLE, &hss));
|
|
// Query how much data we have.
|
num_bytes = 0;
|
read_options.flags = MOJO_READ_DATA_FLAG_QUERY;
|
ASSERT_EQ(MOJO_RESULT_OK,
|
core()->ReadData(ch, &read_options, nullptr, &num_bytes));
|
ASSERT_GE(num_bytes, 1u);
|
|
// Try to query with peek. Should fail.
|
num_bytes = 0;
|
read_options.flags = MOJO_READ_DATA_FLAG_QUERY | MOJO_READ_DATA_FLAG_PEEK;
|
ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
|
core()->ReadData(ch, &read_options, nullptr, &num_bytes));
|
ASSERT_EQ(0u, num_bytes);
|
|
// Try to discard ten characters, in all-or-none mode. Should fail.
|
num_bytes = 10;
|
read_options.flags =
|
MOJO_READ_DATA_FLAG_DISCARD | MOJO_READ_DATA_FLAG_ALL_OR_NONE;
|
ASSERT_EQ(MOJO_RESULT_OUT_OF_RANGE,
|
core()->ReadData(ch, &read_options, nullptr, &num_bytes));
|
|
// Try to discard two characters, in peek mode. Should fail.
|
num_bytes = 2;
|
read_options.flags = MOJO_READ_DATA_FLAG_DISCARD | MOJO_READ_DATA_FLAG_PEEK;
|
ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
|
core()->ReadData(ch, &read_options, nullptr, &num_bytes));
|
|
// Discard a character.
|
num_bytes = 1;
|
read_options.flags =
|
MOJO_READ_DATA_FLAG_DISCARD | MOJO_READ_DATA_FLAG_ALL_OR_NONE;
|
ASSERT_EQ(MOJO_RESULT_OK,
|
core()->ReadData(ch, &read_options, nullptr, &num_bytes));
|
|
// Ensure the 3 bytes were read.
|
ASSERT_EQ(MOJO_RESULT_OK,
|
mojo::Wait(mojo::Handle(ch), MOJO_HANDLE_SIGNAL_READABLE, &hss));
|
|
// Read the remaining three characters, in two-phase mode.
|
const void* read_ptr = nullptr;
|
num_bytes = 3;
|
ASSERT_EQ(MOJO_RESULT_OK,
|
core()->BeginReadData(ch, nullptr, &read_ptr, &num_bytes));
|
// Note: Count on still being able to do the contiguous read here.
|
ASSERT_EQ(3u, num_bytes);
|
|
// Discarding right now should fail.
|
num_bytes = 1;
|
read_options.flags = MOJO_READ_DATA_FLAG_DISCARD;
|
ASSERT_EQ(MOJO_RESULT_BUSY,
|
core()->ReadData(ch, &read_options, nullptr, &num_bytes));
|
|
// Actually check our data and end the two-phase read.
|
ASSERT_EQ('C', static_cast<const char*>(read_ptr)[0]);
|
ASSERT_EQ('D', static_cast<const char*>(read_ptr)[1]);
|
ASSERT_EQ('E', static_cast<const char*>(read_ptr)[2]);
|
ASSERT_EQ(MOJO_RESULT_OK, core()->EndReadData(ch, 3u, nullptr));
|
|
// Consumer should now be no longer readable.
|
hss = kFullMojoHandleSignalsState;
|
EXPECT_EQ(MOJO_RESULT_OK, core()->QueryHandleSignalsState(ch, &hss));
|
EXPECT_EQ(0u, hss.satisfied_signals);
|
EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
|
MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE |
|
MOJO_HANDLE_SIGNAL_PEER_REMOTE,
|
hss.satisfiable_signals);
|
|
// TODO(vtl): More.
|
|
// Close the producer.
|
ASSERT_EQ(MOJO_RESULT_OK, core()->Close(ph));
|
|
// Wait for this to get to the consumer.
|
EXPECT_EQ(MOJO_RESULT_OK,
|
mojo::Wait(mojo::Handle(ch), MOJO_HANDLE_SIGNAL_PEER_CLOSED, &hss));
|
|
// The consumer should now be never-readable.
|
hss = kFullMojoHandleSignalsState;
|
EXPECT_EQ(MOJO_RESULT_OK, core()->QueryHandleSignalsState(ch, &hss));
|
ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
|
ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals);
|
|
ASSERT_EQ(MOJO_RESULT_OK, core()->Close(ch));
|
}
|
|
} // namespace
|
} // namespace core
|
} // namespace mojo
|