diff options
author | viettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-08 00:38:02 +0000 |
---|---|---|
committer | viettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-08 00:38:02 +0000 |
commit | e19f9c06695a69b7b0c92eafe89022ed579889e3 (patch) | |
tree | e35a65a842e5325bf2bfe82198c8e8de041128ae /mojo/system | |
parent | b7bd304456bad53300de565be59fbb09003f5807 (diff) | |
download | chromium_src-e19f9c06695a69b7b0c92eafe89022ed579889e3.zip chromium_src-e19f9c06695a69b7b0c92eafe89022ed579889e3.tar.gz chromium_src-e19f9c06695a69b7b0c92eafe89022ed579889e3.tar.bz2 |
Mojo: DataPipe: Test "all or nothing" mode.
(Except for two-phase read/writes in "may discard" mode, which isn't
supported yet.)
R=davemoore@chromium.org
Review URL: https://codereview.chromium.org/126663003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@243450 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'mojo/system')
-rw-r--r-- | mojo/system/local_data_pipe.cc | 3 | ||||
-rw-r--r-- | mojo/system/local_data_pipe_unittest.cc | 333 |
2 files changed, 334 insertions, 2 deletions
diff --git a/mojo/system/local_data_pipe.cc b/mojo/system/local_data_pipe.cc index 334f597..2e2395a 100644 --- a/mojo/system/local_data_pipe.cc +++ b/mojo/system/local_data_pipe.cc @@ -270,7 +270,8 @@ MojoResult LocalDataPipe::ConsumerBeginReadDataImplNoLock( if (all_or_none && *buffer_num_bytes > max_num_bytes_to_read) { // Don't return "should wait" since you can't wait for a specified amount of // data. - return MOJO_RESULT_OUT_OF_RANGE; + return producer_open_no_lock() ? MOJO_RESULT_OUT_OF_RANGE : + MOJO_RESULT_FAILED_PRECONDITION; } // Don't go into a two-phase read if there's no data. diff --git a/mojo/system/local_data_pipe_unittest.cc b/mojo/system/local_data_pipe_unittest.cc index 98a5ae1..72476eb 100644 --- a/mojo/system/local_data_pipe_unittest.cc +++ b/mojo/system/local_data_pipe_unittest.cc @@ -579,7 +579,338 @@ TEST(LocalDataPipeTest, MayDiscard) { dp->ConsumerClose(); } -// TODO(vtl): More "all or none" tests (without and with "may discard"). +TEST(LocalDataPipeTest, AllOrNone) { + const MojoCreateDataPipeOptions options = { + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. + static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. + 10 * 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)); + + // Try writing way too much. + uint32_t num_bytes = 20u * sizeof(int32_t); + int32_t buffer[100]; + Seq(0, arraysize(buffer), buffer); + EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, + dp->ProducerWriteData(buffer, &num_bytes, true)); + + // Should still be empty. + num_bytes = ~0u; + EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(&num_bytes)); + EXPECT_EQ(0u, num_bytes); + + // Write some data. + num_bytes = 5u * sizeof(int32_t); + Seq(100, arraysize(buffer), buffer); + EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerWriteData(buffer, &num_bytes, true)); + EXPECT_EQ(5u * sizeof(int32_t), num_bytes); + + // Half full. + num_bytes = 0u; + EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(&num_bytes)); + EXPECT_EQ(5u * sizeof(int32_t), num_bytes); + + // Too much. + num_bytes = 6u * sizeof(int32_t); + Seq(200, arraysize(buffer), buffer); + EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, + dp->ProducerWriteData(buffer, &num_bytes, true)); + + // Try reading too much. + num_bytes = 11u * sizeof(int32_t); + memset(buffer, 0xab, sizeof(buffer)); + EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, + dp->ConsumerReadData(buffer, &num_bytes, true)); + int32_t expected_buffer[100]; + memset(expected_buffer, 0xab, sizeof(expected_buffer)); + EXPECT_EQ(0, memcmp(buffer, expected_buffer, sizeof(buffer))); + + // Try discarding too much. + num_bytes = 11u * sizeof(int32_t); + EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, + dp->ConsumerDiscardData(&num_bytes, true)); + + // Just a little. + num_bytes = 2u * sizeof(int32_t); + Seq(300, arraysize(buffer), buffer); + EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerWriteData(buffer, &num_bytes, true)); + EXPECT_EQ(2u * sizeof(int32_t), num_bytes); + + // Just right. + num_bytes = 3u * sizeof(int32_t); + Seq(400, arraysize(buffer), buffer); + EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerWriteData(buffer, &num_bytes, true)); + EXPECT_EQ(3u * sizeof(int32_t), num_bytes); + + // Exactly full. + num_bytes = 0u; + EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(&num_bytes)); + EXPECT_EQ(10u * sizeof(int32_t), num_bytes); + + // Read half. + num_bytes = 5u * sizeof(int32_t); + memset(buffer, 0xab, sizeof(buffer)); + EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerReadData(buffer, &num_bytes, true)); + EXPECT_EQ(5u * sizeof(int32_t), num_bytes); + memset(expected_buffer, 0xab, sizeof(expected_buffer)); + Seq(100, 5, expected_buffer); + EXPECT_EQ(0, memcmp(buffer, expected_buffer, sizeof(buffer))); + + // Try reading too much again. + num_bytes = 6u * sizeof(int32_t); + memset(buffer, 0xab, sizeof(buffer)); + EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, + dp->ConsumerReadData(buffer, &num_bytes, true)); + memset(expected_buffer, 0xab, sizeof(expected_buffer)); + EXPECT_EQ(0, memcmp(buffer, expected_buffer, sizeof(buffer))); + + // Try discarding too much again. + num_bytes = 6u * sizeof(int32_t); + EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, + dp->ConsumerDiscardData(&num_bytes, true)); + + // Discard a little. + num_bytes = 2u * sizeof(int32_t); + EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerDiscardData(&num_bytes, true)); + EXPECT_EQ(2u * sizeof(int32_t), num_bytes); + + // Three left. + num_bytes = 0u; + EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(&num_bytes)); + EXPECT_EQ(3u * sizeof(int32_t), num_bytes); + + // Close the producer, then test producer-closed cases. + dp->ProducerClose(); + + // Try reading too much; "failed precondition" since the producer is closed. + num_bytes = 4u * sizeof(int32_t); + memset(buffer, 0xab, sizeof(buffer)); + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + dp->ConsumerReadData(buffer, &num_bytes, true)); + memset(expected_buffer, 0xab, sizeof(expected_buffer)); + EXPECT_EQ(0, memcmp(buffer, expected_buffer, sizeof(buffer))); + + // Try discarding too much; "failed precondition" again. + num_bytes = 4u * sizeof(int32_t); + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + dp->ConsumerDiscardData(&num_bytes, true)); + + // Read a little. + num_bytes = 2u * sizeof(int32_t); + memset(buffer, 0xab, sizeof(buffer)); + EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerReadData(buffer, &num_bytes, true)); + EXPECT_EQ(2u * sizeof(int32_t), num_bytes); + memset(expected_buffer, 0xab, sizeof(expected_buffer)); + Seq(400, 2, expected_buffer); + EXPECT_EQ(0, memcmp(buffer, expected_buffer, sizeof(buffer))); + + // Discard the remaining element. + num_bytes = 1u * sizeof(int32_t); + EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerDiscardData(&num_bytes, true)); + EXPECT_EQ(1u * sizeof(int32_t), num_bytes); + + // Empty again. + num_bytes = ~0u; + EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(&num_bytes)); + EXPECT_EQ(0u, num_bytes); + + dp->ConsumerClose(); +} + +TEST(LocalDataPipeTest, AllOrNoneMayDiscard) { + 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|. + 10 * 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)); + + // Try writing way too much. + uint32_t num_bytes = 20u * sizeof(int32_t); + int32_t buffer[100]; + Seq(0, arraysize(buffer), buffer); + EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, + dp->ProducerWriteData(buffer, &num_bytes, true)); + + // Write some stuff. + num_bytes = 5u * sizeof(int32_t); + Seq(100, arraysize(buffer), buffer); + EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerWriteData(buffer, &num_bytes, true)); + EXPECT_EQ(5u * sizeof(int32_t), num_bytes); + + // Write lots of stuff (discarding all but "104"). + num_bytes = 9u * sizeof(int32_t); + Seq(200, arraysize(buffer), buffer); + EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerWriteData(buffer, &num_bytes, true)); + EXPECT_EQ(9u * sizeof(int32_t), num_bytes); + + // Read one. + num_bytes = 1u * sizeof(int32_t); + memset(buffer, 0xab, sizeof(buffer)); + EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerReadData(buffer, &num_bytes, true)); + EXPECT_EQ(1u * sizeof(int32_t), num_bytes); + int32_t expected_buffer[100]; + memset(expected_buffer, 0xab, sizeof(expected_buffer)); + expected_buffer[0] = 104; + EXPECT_EQ(0, memcmp(buffer, expected_buffer, sizeof(buffer))); + + // Try reading too many. + num_bytes = 10u * sizeof(int32_t); + memset(buffer, 0xab, sizeof(buffer)); + EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, + dp->ConsumerReadData(buffer, &num_bytes, true)); + memset(expected_buffer, 0xab, sizeof(expected_buffer)); + EXPECT_EQ(0, memcmp(buffer, expected_buffer, sizeof(buffer))); + + // Try discarding too many. + num_bytes = 10u * sizeof(int32_t); + EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, + dp->ConsumerDiscardData(&num_bytes, true)); + + // Discard a bunch. + num_bytes = 4u * sizeof(int32_t); + EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerDiscardData(&num_bytes, true)); + + // Half full. + num_bytes = 0u; + EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(&num_bytes)); + EXPECT_EQ(5u * sizeof(int32_t), num_bytes); + + // Write as much as possible. + num_bytes = 10u * sizeof(int32_t); + Seq(300, arraysize(buffer), buffer); + EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerWriteData(buffer, &num_bytes, true)); + EXPECT_EQ(10u * sizeof(int32_t), num_bytes); + + // Read everything. + num_bytes = 10u * sizeof(int32_t); + memset(buffer, 0xab, sizeof(buffer)); + EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerReadData(buffer, &num_bytes, true)); + memset(expected_buffer, 0xab, sizeof(expected_buffer)); + EXPECT_EQ(10u * sizeof(int32_t), num_bytes); + Seq(300, 10, expected_buffer); + EXPECT_EQ(0, memcmp(buffer, expected_buffer, sizeof(buffer))); + + dp->ProducerClose(); + dp->ConsumerClose(); +} + +TEST(LocalDataPipeTest, TwoPhaseAllOrNone) { + const MojoCreateDataPipeOptions options = { + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. + static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. + 10 * 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)); + + // Try writing way too much (two-phase). + uint32_t num_bytes = 20u * sizeof(int32_t); + void* write_ptr = NULL; + EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, + dp->ProducerBeginWriteData(&write_ptr, &num_bytes, true)); + + // Try reading way too much (two-phase). + num_bytes = 20u * sizeof(int32_t); + const void* read_ptr = NULL; + EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, + dp->ConsumerBeginReadData(&read_ptr, &num_bytes, true)); + + // Write half (two-phase). + num_bytes = 5u * sizeof(int32_t); + write_ptr = NULL; + EXPECT_EQ(MOJO_RESULT_OK, + dp->ProducerBeginWriteData(&write_ptr, &num_bytes, true)); + // May provide more space than requested. + EXPECT_GE(num_bytes, 5u * sizeof(int32_t)); + EXPECT_TRUE(write_ptr != NULL); + Seq(0, 5, static_cast<int32_t*>(write_ptr)); + EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerEndWriteData(5u * sizeof(int32_t))); + + // Read one (two-phase). + num_bytes = 1u * sizeof(int32_t); + read_ptr = NULL; + EXPECT_EQ(MOJO_RESULT_OK, + dp->ConsumerBeginReadData(&read_ptr, &num_bytes, true)); + EXPECT_GE(num_bytes, 1u * sizeof(int32_t)); + EXPECT_EQ(0, static_cast<const int32_t*>(read_ptr)[0]); + EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerEndReadData(1u * sizeof(int32_t))); + + // We should have four left, leaving room for six. + num_bytes = 0u; + EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(&num_bytes)); + EXPECT_EQ(4u * sizeof(int32_t), num_bytes); + + // Assuming a tight circular buffer of the specified capacity, we can't do a + // two-phase write of six now. + num_bytes = 6u * sizeof(int32_t); + write_ptr = NULL; + EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, + dp->ProducerBeginWriteData(&write_ptr, &num_bytes, true)); + + // Write six elements (simple), filling the buffer. + num_bytes = 6u * sizeof(int32_t); + int32_t buffer[100]; + Seq(100, 6, buffer); + EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerWriteData(buffer, &num_bytes, true)); + EXPECT_EQ(6u * sizeof(int32_t), num_bytes); + + // We have ten. + num_bytes = 0u; + EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerQueryData(&num_bytes)); + EXPECT_EQ(10u * sizeof(int32_t), num_bytes); + + // But a two-phase read of ten should fail. + num_bytes = 10u * sizeof(int32_t); + read_ptr = NULL; + EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, + dp->ConsumerBeginReadData(&read_ptr, &num_bytes, true)); + + // Close the producer. + dp->ProducerClose(); + + // A two-phase read of nine should work. + num_bytes = 9u * sizeof(int32_t); + read_ptr = NULL; + EXPECT_EQ(MOJO_RESULT_OK, + dp->ConsumerBeginReadData(&read_ptr, &num_bytes, true)); + EXPECT_GE(num_bytes, 9u * sizeof(int32_t)); + EXPECT_EQ(1, static_cast<const int32_t*>(read_ptr)[0]); + EXPECT_EQ(2, static_cast<const int32_t*>(read_ptr)[1]); + EXPECT_EQ(3, static_cast<const int32_t*>(read_ptr)[2]); + EXPECT_EQ(4, static_cast<const int32_t*>(read_ptr)[3]); + EXPECT_EQ(100, static_cast<const int32_t*>(read_ptr)[4]); + EXPECT_EQ(101, static_cast<const int32_t*>(read_ptr)[5]); + EXPECT_EQ(102, static_cast<const int32_t*>(read_ptr)[6]); + EXPECT_EQ(103, static_cast<const int32_t*>(read_ptr)[7]); + EXPECT_EQ(104, static_cast<const int32_t*>(read_ptr)[8]); + EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerEndReadData(9u * sizeof(int32_t))); + + // A two-phase read of two should fail, with "failed precondition". + num_bytes = 2u * sizeof(int32_t); + read_ptr = NULL; + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + dp->ConsumerBeginReadData(&read_ptr, &num_bytes, true)); + + 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 |