Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(49)

Unified Diff: chrome/browser/chromeos/file_system_provider/fileapi/buffering_file_stream_writer_unittest.cc

Issue 502973005: [fsp] Buffer consecutive Write() calls. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixed. Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/chromeos/file_system_provider/fileapi/buffering_file_stream_writer_unittest.cc
diff --git a/chrome/browser/chromeos/file_system_provider/fileapi/buffering_file_stream_writer_unittest.cc b/chrome/browser/chromeos/file_system_provider/fileapi/buffering_file_stream_writer_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..31ede7ae5f8d2a4289f9ca2e9a0cbc8320ffdbc6
--- /dev/null
+++ b/chrome/browser/chromeos/file_system_provider/fileapi/buffering_file_stream_writer_unittest.cc
@@ -0,0 +1,401 @@
+// Copyright 2014 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 <string>
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/run_loop.h"
+#include "base/thread_task_runner_handle.h"
+#include "chrome/browser/chromeos/file_system_provider/fileapi/buffering_file_stream_writer.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+namespace file_system_provider {
+namespace {
+
+// Size of the intermediate buffer in bytes.
+const int kIntermediateBufferLength = 8;
+
+// Testing text to be written. The length must be 5 bytes, to invoke all code
+// paths for buffering.
+const char kShortTextToWrite[] = "Kitty";
+
+// Testing text to be written. The length must be longr than the intermediate
+// buffer length, in order to invoke a direct write.
+const char kLongTextToWrite[] = "Welcome to my world!";
+
+// Pushes a value to the passed log vector.
+template <typename T>
+void LogValue(std::vector<T>* log, T value) {
+ log->push_back(value);
+}
+
+// Fake internal file stream writer.
+class FakeFileStreamWriter : public storage::FileStreamWriter {
+ public:
+ FakeFileStreamWriter(std::vector<std::string>* write_log,
+ std::vector<int>* flush_log,
+ net::Error write_error)
+ : pending_bytes_(0),
+ write_log_(write_log),
+ flush_log_(flush_log),
+ write_error_(write_error) {}
+ virtual ~FakeFileStreamWriter() {}
+
+ // storage::FileStreamWriter overrides.
+ virtual int Write(net::IOBuffer* buf,
+ int buf_len,
+ const net::CompletionCallback& callback) OVERRIDE {
+ DCHECK(write_log_);
+ write_log_->push_back(std::string(buf->data(), buf_len));
+ pending_bytes_ += buf_len;
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(callback, write_error_ == net::OK ? buf_len : write_error_));
+ return net::ERR_IO_PENDING;
+ }
+
+ virtual int Cancel(const net::CompletionCallback& callback) OVERRIDE {
+ DCHECK_EQ(net::OK, write_error_);
+ callback.Run(net::OK);
hashimoto 2014/09/11 07:52:17 nit: Use PostTask?
mtomasz 2014/09/17 04:59:41 Done.
+ return net::ERR_IO_PENDING;
+ }
+
+ virtual int Flush(const net::CompletionCallback& callback) OVERRIDE {
+ DCHECK(flush_log_);
+ flush_log_->push_back(pending_bytes_);
+ pending_bytes_ = 0;
+ callback.Run(net::OK);
hashimoto 2014/09/11 07:52:16 ditto.
mtomasz 2014/09/17 04:59:40 Done.
+ return net::ERR_IO_PENDING;
+ }
+
+ private:
+ int pending_bytes_;
+ std::vector<std::string>* write_log_; // Not owned.
+ std::vector<int>* flush_log_; // Not owned.
+ net::Error write_error_;
+ DISALLOW_COPY_AND_ASSIGN(FakeFileStreamWriter);
+};
+
+} // namespace
+
+class FileSystemProviderBufferingFileStreamWriterTest : public testing::Test {
+ protected:
+ FileSystemProviderBufferingFileStreamWriterTest() {}
+ virtual ~FileSystemProviderBufferingFileStreamWriterTest() {}
+
+ content::TestBrowserThreadBundle thread_bundle_;
+};
+
+TEST_F(FileSystemProviderBufferingFileStreamWriterTest, Write) {
+ std::vector<std::string> inner_write_log;
+ std::vector<int> inner_flush_log;
+ BufferingFileStreamWriter writer(
+ scoped_ptr<storage::FileStreamWriter>(new FakeFileStreamWriter(
+ &inner_write_log, &inner_flush_log, net::OK)),
+ kIntermediateBufferLength);
+
+ scoped_refptr<net::StringIOBuffer> buffer(
hashimoto 2014/09/11 07:52:17 How about having this buffer and a StringBuffer ma
mtomasz 2014/09/17 04:59:41 Good idea. Done.
+ new net::StringIOBuffer(kShortTextToWrite));
+ ASSERT_LT(kIntermediateBufferLength, 2 * buffer->size());
+
+ // Writing for the first time should succeed, but buffer the write without
+ // calling the internal file stream writer.
+ {
+ std::vector<int> write_log;
+ const int result = writer.Write(
+ buffer, buffer->size(), base::Bind(&LogValue<int>, &write_log));
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(buffer->size(), result);
+ EXPECT_EQ(0u, write_log.size());
+ EXPECT_EQ(0u, inner_write_log.size());
+ EXPECT_EQ(0u, inner_flush_log.size());
+ }
+
+ // Writing for the second time should however flush the intermediate buffer,
+ // since it is full.
+ {
+ inner_write_log.clear();
+ inner_flush_log.clear();
+
+ std::vector<int> write_log;
+ const int result = writer.Write(
+ buffer, buffer->size(), base::Bind(&LogValue<int>, &write_log));
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(net::ERR_IO_PENDING, result);
+ const std::string expected_inner_write =
+ (std::string(kShortTextToWrite) + kShortTextToWrite)
+ .substr(0, kIntermediateBufferLength);
+ ASSERT_EQ(1u, inner_write_log.size());
+ EXPECT_EQ(expected_inner_write, inner_write_log[0]);
+ ASSERT_EQ(1u, write_log.size());
+ EXPECT_EQ(buffer->size(), write_log[0]);
+ EXPECT_EQ(0u, inner_flush_log.size());
+ }
+
+ // There should be a remainder in the intermediate buffer. Calling flush
+ // should invoke a write on the internal file stream writer.
+ {
+ inner_write_log.clear();
+ inner_flush_log.clear();
+
+ std::vector<int> flush_log;
+ const int result = writer.Flush(base::Bind(&LogValue<int>, &flush_log));
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(net::ERR_IO_PENDING, result);
+ ASSERT_EQ(1u, flush_log.size());
+ EXPECT_EQ(net::OK, flush_log[0]);
+
+ const std::string expected_inner_write =
+ (std::string(kShortTextToWrite) + kShortTextToWrite)
+ .substr(kIntermediateBufferLength, std::string::npos);
+ ASSERT_EQ(1u, inner_write_log.size());
+ EXPECT_EQ(expected_inner_write, inner_write_log[0]);
+
+ const int expected_inner_flush = 2 * buffer->size();
+ ASSERT_EQ(1u, inner_flush_log.size());
+ EXPECT_EQ(expected_inner_flush, inner_flush_log[0]);
+ }
+}
+
+TEST_F(FileSystemProviderBufferingFileStreamWriterTest, Write_WithError) {
+ std::vector<std::string> inner_write_log;
+ std::vector<int> inner_flush_log;
+ BufferingFileStreamWriter writer(
+ scoped_ptr<storage::FileStreamWriter>(new FakeFileStreamWriter(
+ &inner_write_log, &inner_flush_log, net::ERR_FAILED)),
+ kIntermediateBufferLength);
+
+ scoped_refptr<net::StringIOBuffer> buffer(
+ new net::StringIOBuffer(kShortTextToWrite));
+ ASSERT_LT(kIntermediateBufferLength, 2 * buffer->size());
+
+ // Writing for the first time should succeed, but buffer the write without
+ // calling the internal file stream writer. Because of that, the error will
+ // not be generated unless the intermediate buffer is flushed.
+ {
+ std::vector<int> write_log;
+ const int result = writer.Write(
+ buffer, buffer->size(), base::Bind(&LogValue<int>, &write_log));
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(buffer->size(), result);
+ EXPECT_EQ(0u, write_log.size());
+ EXPECT_EQ(0u, inner_write_log.size());
+ EXPECT_EQ(0u, inner_flush_log.size());
+ }
+
+ // Writing for the second time should however flush the intermediate buffer,
+ // since it is full. That should generate an error.
+ {
+ inner_write_log.clear();
+ inner_flush_log.clear();
+
+ std::vector<int> write_log;
+ const int result = writer.Write(
+ buffer, buffer->size(), base::Bind(&LogValue<int>, &write_log));
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(net::ERR_IO_PENDING, result);
+ const std::string expected_inner_write =
+ (std::string(kShortTextToWrite) + kShortTextToWrite)
+ .substr(0, kIntermediateBufferLength);
+ ASSERT_EQ(1u, inner_write_log.size());
+ EXPECT_EQ(expected_inner_write, inner_write_log[0]);
+ ASSERT_EQ(1u, write_log.size());
+ EXPECT_EQ(net::ERR_FAILED, write_log[0]);
+ EXPECT_EQ(0u, inner_flush_log.size());
+ }
+}
+
+TEST_F(FileSystemProviderBufferingFileStreamWriterTest, Write_Directly) {
+ std::vector<std::string> inner_write_log;
+ std::vector<int> inner_flush_log;
+ BufferingFileStreamWriter writer(
+ scoped_ptr<storage::FileStreamWriter>(new FakeFileStreamWriter(
+ &inner_write_log, &inner_flush_log, net::OK)),
+ kIntermediateBufferLength);
+
+ scoped_refptr<net::StringIOBuffer> short_buffer(
+ new net::StringIOBuffer(kShortTextToWrite));
+ ASSERT_GT(kIntermediateBufferLength, short_buffer->size());
+
+ scoped_refptr<net::StringIOBuffer> long_buffer(
+ new net::StringIOBuffer(kLongTextToWrite));
+ ASSERT_LT(kIntermediateBufferLength, long_buffer->size());
+
+ // Write few bytes first, so the intermediate buffer is not empty.
+ {
+ std::vector<int> write_log;
+ const int result = writer.Write(short_buffer,
+ short_buffer->size(),
+ base::Bind(&LogValue<int>, &write_log));
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(short_buffer->size(), result);
+ EXPECT_EQ(0u, write_log.size());
+ EXPECT_EQ(0u, inner_flush_log.size());
+ }
+
+ // Request writing a long chunk of data, which is longr than size of the
+ // intermediate buffer.
+ {
+ inner_write_log.clear();
+ inner_flush_log.clear();
+
+ std::vector<int> write_log;
+ const int result = writer.Write(long_buffer,
+ long_buffer->size(),
+ base::Bind(&LogValue<int>, &write_log));
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(net::ERR_IO_PENDING, result);
+ ASSERT_EQ(2u, inner_write_log.size());
+ EXPECT_EQ(kShortTextToWrite, inner_write_log[0]);
+ EXPECT_EQ(kLongTextToWrite, inner_write_log[1]);
+ ASSERT_EQ(1u, write_log.size());
+ EXPECT_EQ(long_buffer->size(), write_log[0]);
+ EXPECT_EQ(0u, inner_flush_log.size());
+ }
+
+ // Write a long chunk again, to test the case with an empty intermediate
+ // buffer.
+ {
+ inner_write_log.clear();
+ inner_flush_log.clear();
+
+ std::vector<int> write_log;
+ const int result = writer.Write(long_buffer,
+ long_buffer->size(),
+ base::Bind(&LogValue<int>, &write_log));
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(net::ERR_IO_PENDING, result);
+ ASSERT_EQ(1u, inner_write_log.size());
+ EXPECT_EQ(kLongTextToWrite, inner_write_log[0]);
+ ASSERT_EQ(1u, write_log.size());
+ EXPECT_EQ(long_buffer->size(), write_log[0]);
+ EXPECT_EQ(0u, inner_flush_log.size());
+ }
+}
+
+TEST_F(FileSystemProviderBufferingFileStreamWriterTest, Cancel) {
+ std::vector<std::string> inner_write_log;
+ std::vector<int> inner_flush_log;
+ BufferingFileStreamWriter writer(
+ scoped_ptr<storage::FileStreamWriter>(new FakeFileStreamWriter(
+ &inner_write_log, &inner_flush_log, net::OK)),
+ kIntermediateBufferLength);
+
+ scoped_refptr<net::StringIOBuffer> buffer(
+ new net::StringIOBuffer(kLongTextToWrite));
+
+ // Write directly, so there is something to actually cancel. Note, that
+ // buffered writes which do not invoke flushing the intermediate buffer finish
+ // immediately, so they are not cancellable.
+ std::vector<int> write_log;
+ const int write_result = writer.Write(
+ buffer, buffer->size(), base::Bind(&LogValue<int>, &write_log));
+ EXPECT_EQ(net::ERR_IO_PENDING, write_result);
+
+ std::vector<int> cancel_log;
+ const int cancel_result =
+ writer.Cancel(base::Bind(&LogValue<int>, &cancel_log));
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(net::ERR_IO_PENDING, cancel_result);
+ ASSERT_EQ(1u, cancel_log.size());
+ EXPECT_EQ(net::OK, cancel_log[0]);
hashimoto 2014/09/11 07:52:17 How about counting how many times the fake's Cance
mtomasz 2014/09/17 04:59:41 Done.
+}
+
+TEST_F(FileSystemProviderBufferingFileStreamWriterTest, Flush) {
+ std::vector<std::string> inner_write_log;
+ std::vector<int> inner_flush_log;
+ BufferingFileStreamWriter writer(
+ scoped_ptr<storage::FileStreamWriter>(new FakeFileStreamWriter(
+ &inner_write_log, &inner_flush_log, net::OK)),
+ kIntermediateBufferLength);
+
+ scoped_refptr<net::StringIOBuffer> buffer(
+ new net::StringIOBuffer(kShortTextToWrite));
+
+ // Write less bytes than size of the intermediate buffer.
+ std::vector<int> write_log;
+ const int write_result = writer.Write(
+ buffer, buffer->size(), base::Bind(&LogValue<int>, &write_log));
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(buffer->size(), write_result);
+ EXPECT_EQ(0u, write_log.size());
+ EXPECT_EQ(0u, inner_write_log.size());
+ EXPECT_EQ(0u, inner_flush_log.size());
+
+ // Calling Flush() will force flushing the intermediate buffer before it's
+ // filled out.
+ std::vector<int> flush_log;
+ const int flush_result = writer.Flush(base::Bind(&LogValue<int>, &flush_log));
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(net::ERR_IO_PENDING, flush_result);
+ ASSERT_EQ(1u, flush_log.size());
+ EXPECT_EQ(net::OK, flush_log[0]);
+
+ ASSERT_EQ(1u, inner_write_log.size());
+ EXPECT_EQ(kShortTextToWrite, inner_write_log[0]);
+
+ ASSERT_EQ(1u, inner_flush_log.size());
+ EXPECT_EQ(buffer->size(), inner_flush_log[0]);
+}
+
+TEST_F(FileSystemProviderBufferingFileStreamWriterTest, Flush_AfterWriteError) {
+ std::vector<std::string> inner_write_log;
+ std::vector<int> inner_flush_log;
+ BufferingFileStreamWriter writer(
+ scoped_ptr<storage::FileStreamWriter>(new FakeFileStreamWriter(
+ &inner_write_log, &inner_flush_log, net::ERR_FAILED)),
+ kIntermediateBufferLength);
+
+ scoped_refptr<net::StringIOBuffer> buffer(
+ new net::StringIOBuffer(kShortTextToWrite));
+
+ // Write less bytes than size of the intermediate buffer. This should succeed
+ // since the inner file stream writer is not invoked.
+ std::vector<int> write_log;
+ const int write_result = writer.Write(
+ buffer, buffer->size(), base::Bind(&LogValue<int>, &write_log));
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(buffer->size(), write_result);
+ EXPECT_EQ(0u, write_log.size());
+ EXPECT_EQ(0u, inner_write_log.size());
+ EXPECT_EQ(0u, inner_flush_log.size());
+
+ // Calling Flush() will force flushing the intermediate buffer before it's
+ // filled out. That should cause failing.
+ std::vector<int> flush_log;
+ const int flush_result = writer.Flush(base::Bind(&LogValue<int>, &flush_log));
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(net::ERR_IO_PENDING, flush_result);
+ ASSERT_EQ(1u, flush_log.size());
+ EXPECT_EQ(net::ERR_FAILED, flush_log[0]);
+
+ ASSERT_EQ(1u, inner_write_log.size());
+ EXPECT_EQ(kShortTextToWrite, inner_write_log[0]);
+
+ // Flush of the internal file stream writer is not invoked, since a Write
+ // method invocation fails before it.
+ EXPECT_EQ(0u, inner_flush_log.size());
+}
+
+} // namespace file_system_provider
+} // namespace chromeos

Powered by Google App Engine
This is Rietveld 408576698