| Index: mojo/system/local_data_pipe_unittest.cc
|
| diff --git a/mojo/system/local_data_pipe_unittest.cc b/mojo/system/local_data_pipe_unittest.cc
|
| index 72476ebf01c62f9d63b257093cc410198717c1b9..37babdfb53c5dee8032d4bbabe84072115cfd881 100644
|
| --- a/mojo/system/local_data_pipe_unittest.cc
|
| +++ b/mojo/system/local_data_pipe_unittest.cc
|
| @@ -182,6 +182,9 @@ TEST(LocalDataPipeTest, SimpleReadWrite) {
|
| dp->ConsumerClose();
|
| }
|
|
|
| +// Note: The "basic" waiting tests test that the "wait states" are correct in
|
| +// various situations; they don't test that waiters are properly awoken on state
|
| +// changes. (For that, we need to use multiple threads.)
|
| TEST(LocalDataPipeTest, BasicProducerWaiting) {
|
| // Note: We take advantage of the fact that for |LocalDataPipe|, capacities
|
| // are strict maximums. This is not guaranteed by the API.
|
| @@ -196,110 +199,107 @@ TEST(LocalDataPipeTest, BasicProducerWaiting) {
|
| EXPECT_EQ(MOJO_RESULT_OK,
|
| DataPipe::ValidateOptions(&options, &validated_options));
|
|
|
| - {
|
| - scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options));
|
| - Waiter waiter;
|
| + scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options));
|
| + Waiter waiter;
|
|
|
| - // Never readable.
|
| - waiter.Init();
|
| - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
|
| - dp->ProducerAddWaiter(&waiter, MOJO_WAIT_FLAG_READABLE, 12));
|
| + // Never readable.
|
| + waiter.Init();
|
| + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
|
| + dp->ProducerAddWaiter(&waiter, MOJO_WAIT_FLAG_READABLE, 12));
|
|
|
| - // Already writable.
|
| - waiter.Init();
|
| - EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
|
| - dp->ProducerAddWaiter(&waiter, MOJO_WAIT_FLAG_WRITABLE, 34));
|
| + // Already writable.
|
| + waiter.Init();
|
| + EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
|
| + dp->ProducerAddWaiter(&waiter, MOJO_WAIT_FLAG_WRITABLE, 34));
|
|
|
| - // Write two elements.
|
| - int32_t elements[2] = { 123, 456 };
|
| - uint32_t num_bytes = static_cast<uint32_t>(2u * sizeof(elements[0]));
|
| - EXPECT_EQ(MOJO_RESULT_OK,
|
| - dp->ProducerWriteData(elements, &num_bytes, true));
|
| - EXPECT_EQ(static_cast<uint32_t>(2u * sizeof(elements[0])), num_bytes);
|
| + // Write two elements.
|
| + int32_t elements[2] = { 123, 456 };
|
| + uint32_t num_bytes = static_cast<uint32_t>(2u * sizeof(elements[0]));
|
| + EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerWriteData(elements, &num_bytes, true));
|
| + EXPECT_EQ(static_cast<uint32_t>(2u * sizeof(elements[0])), num_bytes);
|
|
|
| - // Adding a waiter should now succeed.
|
| - waiter.Init();
|
| - EXPECT_EQ(MOJO_RESULT_OK,
|
| - dp->ProducerAddWaiter(&waiter, MOJO_WAIT_FLAG_WRITABLE, 56));
|
| - // And it shouldn't be writable yet.
|
| - EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0));
|
| - dp->ProducerRemoveWaiter(&waiter);
|
| + // Adding a waiter should now succeed.
|
| + waiter.Init();
|
| + EXPECT_EQ(MOJO_RESULT_OK,
|
| + dp->ProducerAddWaiter(&waiter, MOJO_WAIT_FLAG_WRITABLE, 56));
|
| + // And it shouldn't be writable yet.
|
| + EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0));
|
| + dp->ProducerRemoveWaiter(&waiter);
|
|
|
| - // Do it again.
|
| - waiter.Init();
|
| - EXPECT_EQ(MOJO_RESULT_OK,
|
| - dp->ProducerAddWaiter(&waiter, MOJO_WAIT_FLAG_WRITABLE, 78));
|
| + // Do it again.
|
| + waiter.Init();
|
| + EXPECT_EQ(MOJO_RESULT_OK,
|
| + dp->ProducerAddWaiter(&waiter, MOJO_WAIT_FLAG_WRITABLE, 78));
|
|
|
| - // Read one element.
|
| - elements[0] = -1;
|
| - elements[1] = -1;
|
| - num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0]));
|
| - EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerReadData(elements, &num_bytes, true));
|
| - EXPECT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes);
|
| - EXPECT_EQ(123, elements[0]);
|
| - EXPECT_EQ(-1, elements[1]);
|
| + // Read one element.
|
| + elements[0] = -1;
|
| + elements[1] = -1;
|
| + num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0]));
|
| + EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerReadData(elements, &num_bytes, true));
|
| + EXPECT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes);
|
| + EXPECT_EQ(123, elements[0]);
|
| + EXPECT_EQ(-1, elements[1]);
|
|
|
| - // Waiting should now succeed.
|
| - EXPECT_EQ(78, waiter.Wait(1000));
|
| - dp->ProducerRemoveWaiter(&waiter);
|
| + // Waiting should now succeed.
|
| + EXPECT_EQ(78, waiter.Wait(1000));
|
| + dp->ProducerRemoveWaiter(&waiter);
|
|
|
| - // Try writing, using a two-phase write.
|
| - void* buffer = NULL;
|
| - num_bytes = static_cast<uint32_t>(3u * sizeof(elements[0]));
|
| - EXPECT_EQ(MOJO_RESULT_OK,
|
| - dp->ProducerBeginWriteData(&buffer, &num_bytes, false));
|
| - EXPECT_TRUE(buffer != NULL);
|
| - EXPECT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes);
|
| - static_cast<int32_t*>(buffer)[0] = 789;
|
| - EXPECT_EQ(MOJO_RESULT_OK,
|
| - dp->ProducerEndWriteData(
|
| - static_cast<uint32_t>(1u * sizeof(elements[0]))));
|
| + // Try writing, using a two-phase write.
|
| + void* buffer = NULL;
|
| + num_bytes = static_cast<uint32_t>(3u * sizeof(elements[0]));
|
| + EXPECT_EQ(MOJO_RESULT_OK,
|
| + dp->ProducerBeginWriteData(&buffer, &num_bytes, false));
|
| + EXPECT_TRUE(buffer != NULL);
|
| + EXPECT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes);
|
|
|
| - // Add a waiter.
|
| - waiter.Init();
|
| - EXPECT_EQ(MOJO_RESULT_OK,
|
| - dp->ProducerAddWaiter(&waiter, MOJO_WAIT_FLAG_WRITABLE, 90));
|
| + static_cast<int32_t*>(buffer)[0] = 789;
|
| + EXPECT_EQ(MOJO_RESULT_OK,
|
| + dp->ProducerEndWriteData(
|
| + static_cast<uint32_t>(1u * sizeof(elements[0]))));
|
|
|
| - // Read one element, using a two-phase read.
|
| - const void* read_buffer = NULL;
|
| - num_bytes = 0u;
|
| - EXPECT_EQ(MOJO_RESULT_OK,
|
| - dp->ConsumerBeginReadData(&read_buffer, &num_bytes, false));
|
| - EXPECT_TRUE(read_buffer != NULL);
|
| - // Since we only read one element (after having written three in all), the
|
| - // two-phase read should only allow us to read one. This checks an
|
| - // implementation detail!
|
| - EXPECT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes);
|
| - EXPECT_EQ(456, static_cast<const int32_t*>(read_buffer)[0]);
|
| - EXPECT_EQ(MOJO_RESULT_OK,
|
| - dp->ConsumerEndReadData(
|
| - static_cast<uint32_t>(1u * sizeof(elements[0]))));
|
| + // Add a waiter.
|
| + waiter.Init();
|
| + EXPECT_EQ(MOJO_RESULT_OK,
|
| + dp->ProducerAddWaiter(&waiter, MOJO_WAIT_FLAG_WRITABLE, 90));
|
|
|
| - // Waiting should succeed.
|
| - EXPECT_EQ(90, waiter.Wait(1000));
|
| - dp->ProducerRemoveWaiter(&waiter);
|
| + // Read one element, using a two-phase read.
|
| + const void* read_buffer = NULL;
|
| + num_bytes = 0u;
|
| + EXPECT_EQ(MOJO_RESULT_OK,
|
| + dp->ConsumerBeginReadData(&read_buffer, &num_bytes, false));
|
| + EXPECT_TRUE(read_buffer != NULL);
|
| + // Since we only read one element (after having written three in all), the
|
| + // two-phase read should only allow us to read one. This checks an
|
| + // implementation detail!
|
| + EXPECT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes);
|
| + EXPECT_EQ(456, static_cast<const int32_t*>(read_buffer)[0]);
|
| + EXPECT_EQ(MOJO_RESULT_OK,
|
| + dp->ConsumerEndReadData(
|
| + static_cast<uint32_t>(1u * sizeof(elements[0]))));
|
|
|
| - // Write one element.
|
| - elements[0] = 123;
|
| - num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0]));
|
| - EXPECT_EQ(MOJO_RESULT_OK,
|
| - dp->ProducerWriteData(elements, &num_bytes, false));
|
| - EXPECT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes);
|
| + // Waiting should succeed.
|
| + EXPECT_EQ(90, waiter.Wait(1000));
|
| + dp->ProducerRemoveWaiter(&waiter);
|
|
|
| - // Add a waiter.
|
| - waiter.Init();
|
| - EXPECT_EQ(MOJO_RESULT_OK,
|
| - dp->ProducerAddWaiter(&waiter, MOJO_WAIT_FLAG_WRITABLE, 12));
|
| + // Write one element.
|
| + elements[0] = 123;
|
| + num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0]));
|
| + EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerWriteData(elements, &num_bytes, false));
|
| + EXPECT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes);
|
|
|
| - // Close the consumer.
|
| - dp->ConsumerClose();
|
| + // Add a waiter.
|
| + waiter.Init();
|
| + EXPECT_EQ(MOJO_RESULT_OK,
|
| + dp->ProducerAddWaiter(&waiter, MOJO_WAIT_FLAG_WRITABLE, 12));
|
|
|
| - // It should now be never-writable.
|
| - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, waiter.Wait(1000));
|
| - dp->ProducerRemoveWaiter(&waiter);
|
| + // Close the consumer.
|
| + dp->ConsumerClose();
|
|
|
| - dp->ProducerClose();
|
| - }
|
| + // It should now be never-writable.
|
| + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, waiter.Wait(1000));
|
| + dp->ProducerRemoveWaiter(&waiter);
|
| +
|
| + dp->ProducerClose();
|
| }
|
|
|
| TEST(LocalDataPipeTest, BasicConsumerWaiting) {
|
| @@ -476,6 +476,195 @@ TEST(LocalDataPipeTest, BasicConsumerWaiting) {
|
| }
|
| }
|
|
|
| +// Tests that data pipes aren't writable/readable during two-phase writes/reads.
|
| +TEST(LocalDataPipeTest, BasicTwoPhaseWaiting) {
|
| + const MojoCreateDataPipeOptions options = {
|
| + kSizeOfOptions, // |struct_size|.
|
| + MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|.
|
| + static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|.
|
| + 1000 * sizeof(int32_t) // |capacity_num_bytes|.
|
| + };
|
| + MojoCreateDataPipeOptions validated_options = { 0 };
|
| + EXPECT_EQ(MOJO_RESULT_OK,
|
| + DataPipe::ValidateOptions(&options, &validated_options));
|
| +
|
| + scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options));
|
| + Waiter waiter;
|
| +
|
| + // It should be writable.
|
| + waiter.Init();
|
| + EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
|
| + dp->ProducerAddWaiter(&waiter, MOJO_WAIT_FLAG_WRITABLE, 0));
|
| +
|
| + uint32_t num_bytes = static_cast<uint32_t>(1u * sizeof(int32_t));
|
| + void* write_ptr = NULL;
|
| + EXPECT_EQ(MOJO_RESULT_OK,
|
| + dp->ProducerBeginWriteData(&write_ptr, &num_bytes, false));
|
| + EXPECT_TRUE(write_ptr != NULL);
|
| + EXPECT_GE(num_bytes, static_cast<uint32_t>(1u * sizeof(int32_t)));
|
| +
|
| + // At this point, it shouldn't be writable.
|
| + waiter.Init();
|
| + EXPECT_EQ(MOJO_RESULT_OK,
|
| + dp->ProducerAddWaiter(&waiter, MOJO_WAIT_FLAG_WRITABLE, 1));
|
| + EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0));
|
| + dp->ProducerRemoveWaiter(&waiter);
|
| +
|
| + // It shouldn't be readable yet either.
|
| + waiter.Init();
|
| + EXPECT_EQ(MOJO_RESULT_OK,
|
| + dp->ConsumerAddWaiter(&waiter, MOJO_WAIT_FLAG_READABLE, 2));
|
| + EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0));
|
| + dp->ConsumerRemoveWaiter(&waiter);
|
| +
|
| + static_cast<int32_t*>(write_ptr)[0] = 123;
|
| + EXPECT_EQ(MOJO_RESULT_OK,
|
| + dp->ProducerEndWriteData(
|
| + static_cast<uint32_t>(1u * sizeof(int32_t))));
|
| +
|
| + // It should be writable again.
|
| + waiter.Init();
|
| + EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
|
| + dp->ProducerAddWaiter(&waiter, MOJO_WAIT_FLAG_WRITABLE, 3));
|
| +
|
| + // And readable.
|
| + waiter.Init();
|
| + EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
|
| + dp->ConsumerAddWaiter(&waiter, MOJO_WAIT_FLAG_READABLE, 4));
|
| +
|
| + // Start another two-phase write and check that it's readable even in the
|
| + // middle of it.
|
| + num_bytes = static_cast<uint32_t>(1u * sizeof(int32_t));
|
| + write_ptr = NULL;
|
| + EXPECT_EQ(MOJO_RESULT_OK,
|
| + dp->ProducerBeginWriteData(&write_ptr, &num_bytes, false));
|
| + EXPECT_TRUE(write_ptr != NULL);
|
| + EXPECT_GE(num_bytes, static_cast<uint32_t>(1u * sizeof(int32_t)));
|
| +
|
| + // It should be readable.
|
| + waiter.Init();
|
| + EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
|
| + dp->ConsumerAddWaiter(&waiter, MOJO_WAIT_FLAG_READABLE, 5));
|
| +
|
| + // End the two-phase write without writing anything.
|
| + EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerEndWriteData(0u));
|
| +
|
| + // Start a two-phase read.
|
| + num_bytes = static_cast<uint32_t>(1u * sizeof(int32_t));
|
| + const void* read_ptr = NULL;
|
| + EXPECT_EQ(MOJO_RESULT_OK,
|
| + dp->ConsumerBeginReadData(&read_ptr, &num_bytes, false));
|
| + EXPECT_TRUE(read_ptr != NULL);
|
| + EXPECT_EQ(static_cast<uint32_t>(1u * sizeof(int32_t)), num_bytes);
|
| +
|
| + // At this point, it should still be writable.
|
| + waiter.Init();
|
| + EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
|
| + dp->ProducerAddWaiter(&waiter, MOJO_WAIT_FLAG_WRITABLE, 6));
|
| +
|
| + // But not readable.
|
| + waiter.Init();
|
| + EXPECT_EQ(MOJO_RESULT_OK,
|
| + dp->ConsumerAddWaiter(&waiter, MOJO_WAIT_FLAG_READABLE, 7));
|
| + EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0));
|
| + dp->ConsumerRemoveWaiter(&waiter);
|
| +
|
| + // End the two-phase read without reading anything.
|
| + EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerEndReadData(0u));
|
| +
|
| + // It should be readable again.
|
| + waiter.Init();
|
| + EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
|
| + dp->ConsumerAddWaiter(&waiter, MOJO_WAIT_FLAG_READABLE, 8));
|
| +
|
| + dp->ProducerClose();
|
| + dp->ConsumerClose();
|
| +}
|
| +
|
| +// Test that a "may discard" data pipe is writable even when it's full.
|
| +TEST(LocalDataPipeTest, BasicMayDiscardWaiting) {
|
| + const MojoCreateDataPipeOptions options = {
|
| + kSizeOfOptions, // |struct_size|.
|
| + MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD, // |flags|.
|
| + static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|.
|
| + 1 * sizeof(int32_t) // |capacity_num_bytes|.
|
| + };
|
| + MojoCreateDataPipeOptions validated_options = { 0 };
|
| + EXPECT_EQ(MOJO_RESULT_OK,
|
| + DataPipe::ValidateOptions(&options, &validated_options));
|
| +
|
| + scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options));
|
| + Waiter waiter;
|
| +
|
| + // Writable.
|
| + waiter.Init();
|
| + EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
|
| + dp->ProducerAddWaiter(&waiter, MOJO_WAIT_FLAG_WRITABLE, 0));
|
| +
|
| + // Not readable.
|
| + waiter.Init();
|
| + EXPECT_EQ(MOJO_RESULT_OK,
|
| + dp->ConsumerAddWaiter(&waiter, MOJO_WAIT_FLAG_READABLE, 1));
|
| + EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0));
|
| + dp->ConsumerRemoveWaiter(&waiter);
|
| +
|
| + uint32_t num_bytes = static_cast<uint32_t>(sizeof(int32_t));
|
| + int32_t element = 123;
|
| + EXPECT_EQ(MOJO_RESULT_OK,
|
| + dp->ProducerWriteData(&element, &num_bytes, false));
|
| + EXPECT_EQ(static_cast<uint32_t>(sizeof(int32_t)), num_bytes);
|
| +
|
| + // Still writable (even though it's full.
|
| + waiter.Init();
|
| + EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
|
| + dp->ProducerAddWaiter(&waiter, MOJO_WAIT_FLAG_WRITABLE, 2));
|
| +
|
| + // Now readable.
|
| + waiter.Init();
|
| + EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
|
| + dp->ConsumerAddWaiter(&waiter, MOJO_WAIT_FLAG_READABLE, 3));
|
| +
|
| + // Overwrite that element.
|
| + num_bytes = static_cast<uint32_t>(sizeof(int32_t));
|
| + element = 456;
|
| + EXPECT_EQ(MOJO_RESULT_OK,
|
| + dp->ProducerWriteData(&element, &num_bytes, false));
|
| + EXPECT_EQ(static_cast<uint32_t>(sizeof(int32_t)), num_bytes);
|
| +
|
| + // Still writable.
|
| + waiter.Init();
|
| + EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
|
| + dp->ProducerAddWaiter(&waiter, MOJO_WAIT_FLAG_WRITABLE, 4));
|
| +
|
| + // And still readable.
|
| + waiter.Init();
|
| + EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
|
| + dp->ConsumerAddWaiter(&waiter, MOJO_WAIT_FLAG_READABLE, 5));
|
| +
|
| + // Read that element.
|
| + num_bytes = static_cast<uint32_t>(sizeof(int32_t));
|
| + element = 0;
|
| + EXPECT_EQ(MOJO_RESULT_OK,
|
| + dp->ConsumerReadData(&element, &num_bytes, false));
|
| + EXPECT_EQ(static_cast<uint32_t>(sizeof(int32_t)), num_bytes);
|
| + EXPECT_EQ(456, element);
|
| +
|
| + // Still writable.
|
| + waiter.Init();
|
| + EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
|
| + dp->ProducerAddWaiter(&waiter, MOJO_WAIT_FLAG_WRITABLE, 6));
|
| +
|
| + // No longer readable.
|
| + waiter.Init();
|
| + EXPECT_EQ(MOJO_RESULT_OK,
|
| + dp->ConsumerAddWaiter(&waiter, MOJO_WAIT_FLAG_READABLE, 7));
|
| + EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0));
|
| + dp->ConsumerRemoveWaiter(&waiter);
|
| +
|
| + dp->ProducerClose();
|
| + dp->ConsumerClose();
|
| +}
|
| +
|
| void Seq(int32_t start, size_t count, int32_t* out) {
|
| for (size_t i = 0; i < count; i++)
|
| out[i] = start + static_cast<int32_t>(i);
|
| @@ -573,7 +762,81 @@ TEST(LocalDataPipeTest, MayDiscard) {
|
| expected_buffer[9] = 304;
|
| EXPECT_EQ(0, memcmp(buffer, expected_buffer, sizeof(buffer)));
|
|
|
| - // TODO(vtl): Test two-phase write when it supports "may discard".
|
| + // Test two-phase writes, including in all-or-none mode.
|
| + // Note: Again, the following depends on an implementation detail -- namely
|
| + // that the write pointer will point at the 5th element of the buffer (and the
|
| + // buffer has exactly the capacity requested).
|
| +
|
| + num_bytes = 0u;
|
| + void* write_ptr = NULL;
|
| + EXPECT_EQ(MOJO_RESULT_OK,
|
| + dp->ProducerBeginWriteData(&write_ptr, &num_bytes, false));
|
| + EXPECT_TRUE(write_ptr != NULL);
|
| + EXPECT_EQ(6u * sizeof(int32_t), num_bytes);
|
| + Seq(400, 6, static_cast<int32_t*>(write_ptr));
|
| + EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerEndWriteData(6u * sizeof(int32_t)));
|
| + // Internally, a circular buffer would now look like:
|
| + // -, -, -, -, 400, 401, 402, 403, 404, 405
|
| +
|
| + // |ProducerBeginWriteData()| ignores |*num_bytes| except in "all-or-none"
|
| + // mode.
|
| + num_bytes = 6u * sizeof(int32_t);
|
| + write_ptr = NULL;
|
| + EXPECT_EQ(MOJO_RESULT_OK,
|
| + dp->ProducerBeginWriteData(&write_ptr, &num_bytes, false));
|
| + EXPECT_EQ(4u * sizeof(int32_t), num_bytes);
|
| + static_cast<int32_t*>(write_ptr)[0] = 500;
|
| + EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerEndWriteData(1u * sizeof(int32_t)));
|
| + // Internally, a circular buffer would now look like:
|
| + // 500, -, -, -, 400, 401, 402, 403, 404, 405
|
| +
|
| + // Requesting a 10-element buffer in all-or-none mode fails at this point.
|
| + num_bytes = 10u * sizeof(int32_t);
|
| + write_ptr = NULL;
|
| + EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE,
|
| + dp->ProducerBeginWriteData(&write_ptr, &num_bytes, true));
|
| +
|
| + // But requesting, say, a 5-element (up to 9, really) buffer should be okay.
|
| + // It will discard two elements.
|
| + num_bytes = 5u * sizeof(int32_t);
|
| + write_ptr = NULL;
|
| + EXPECT_EQ(MOJO_RESULT_OK,
|
| + dp->ProducerBeginWriteData(&write_ptr, &num_bytes, true));
|
| + EXPECT_EQ(5u * sizeof(int32_t), num_bytes);
|
| + // Only write 4 elements though.
|
| + Seq(600, 4, static_cast<int32_t*>(write_ptr));
|
| + EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerEndWriteData(4u * sizeof(int32_t)));
|
| + // Internally, a circular buffer would now look like:
|
| + // 500, 600, 601, 602, 603, -, 402, 403, 404, 405
|
| +
|
| + // Do this again. Make sure we can get a buffer all the way out to the end of
|
| + // the internal buffer.
|
| + num_bytes = 5u * sizeof(int32_t);
|
| + write_ptr = NULL;
|
| + EXPECT_EQ(MOJO_RESULT_OK,
|
| + dp->ProducerBeginWriteData(&write_ptr, &num_bytes, true));
|
| + EXPECT_EQ(5u * sizeof(int32_t), num_bytes);
|
| + // Only write 3 elements though.
|
| + Seq(700, 3, static_cast<int32_t*>(write_ptr));
|
| + EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerEndWriteData(3u * sizeof(int32_t)));
|
| + // Internally, a circular buffer would now look like:
|
| + // 500, 600, 601, 602, 603, 700, 701, 702, -, -
|
| +
|
| + // Read everything.
|
| + num_bytes = sizeof(buffer);
|
| + memset(buffer, 0xab, sizeof(buffer));
|
| + EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerReadData(buffer, &num_bytes, false));
|
| + EXPECT_EQ(8u * sizeof(int32_t), num_bytes);
|
| + memset(expected_buffer, 0xab, sizeof(expected_buffer));
|
| + expected_buffer[0] = 500;
|
| + expected_buffer[1] = 600;
|
| + expected_buffer[2] = 601;
|
| + expected_buffer[3] = 602;
|
| + expected_buffer[4] = 603;
|
| + expected_buffer[5] = 700;
|
| + expected_buffer[6] = 701;
|
| + expected_buffer[7] = 702;
|
| + EXPECT_EQ(0, memcmp(buffer, expected_buffer, sizeof(buffer)));
|
|
|
| dp->ProducerClose();
|
| dp->ConsumerClose();
|
| @@ -801,6 +1064,9 @@ TEST(LocalDataPipeTest, AllOrNoneMayDiscard) {
|
| Seq(300, 10, expected_buffer);
|
| EXPECT_EQ(0, memcmp(buffer, expected_buffer, sizeof(buffer)));
|
|
|
| + // Note: All-or-none two-phase writes on a "may discard" data pipe are tested
|
| + // in LocalDataPipeTest.MayDiscard.
|
| +
|
| dp->ProducerClose();
|
| dp->ConsumerClose();
|
| }
|
| @@ -909,9 +1175,6 @@ TEST(LocalDataPipeTest, TwoPhaseAllOrNone) {
|
| dp->ConsumerClose();
|
| }
|
|
|
| -// TODO(vtl): Test two-phase read/write with "all or none" and "may discard",
|
| -// once that's supported.
|
| -
|
| // Tests that |ProducerWriteData()| and |ConsumerReadData()| writes and reads,
|
| // respectively, as much as possible, even if it has to "wrap around" the
|
| // internal circular buffer. (Note that the two-phase write and read do not do
|
| @@ -1168,8 +1431,6 @@ TEST(LocalDataPipeTest, CloseWriteRead) {
|
| }
|
| }
|
|
|
| -// TODO(vtl): More.
|
| -
|
| } // namespace
|
| } // namespace system
|
| } // namespace mojo
|
|
|