summaryrefslogtreecommitdiffstats
path: root/mojo/system
diff options
context:
space:
mode:
authorviettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-01-08 00:38:02 +0000
committerviettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-01-08 00:38:02 +0000
commite19f9c06695a69b7b0c92eafe89022ed579889e3 (patch)
treee35a65a842e5325bf2bfe82198c8e8de041128ae /mojo/system
parentb7bd304456bad53300de565be59fbb09003f5807 (diff)
downloadchromium_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.cc3
-rw-r--r--mojo/system/local_data_pipe_unittest.cc333
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