| Index: content/browser/fileapi/blob_reader_unittest.cc
|
| diff --git a/content/browser/fileapi/blob_reader_unittest.cc b/content/browser/fileapi/blob_reader_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..1efe4ead74b44e5797936ccc6f75f34ca86c1908
|
| --- /dev/null
|
| +++ b/content/browser/fileapi/blob_reader_unittest.cc
|
| @@ -0,0 +1,1104 @@
|
| +// Copyright 2015 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 "storage/browser/blob/blob_reader.h"
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/bind_helpers.h"
|
| +#include "base/callback.h"
|
| +#include "base/files/file_path.h"
|
| +#include "base/location.h"
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "base/message_loop/message_loop.h"
|
| +#include "base/run_loop.h"
|
| +#include "base/strings/stringprintf.h"
|
| +#include "base/task_runner.h"
|
| +#include "base/time/time.h"
|
| +#include "content/public/test/async_file_test_helper.h"
|
| +#include "content/public/test/test_file_system_context.h"
|
| +#include "net/base/completion_callback.h"
|
| +#include "net/base/io_buffer.h"
|
| +#include "net/base/net_errors.h"
|
| +#include "net/base/test_completion_callback.h"
|
| +#include "net/disk_cache/disk_cache.h"
|
| +#include "storage/browser/blob/blob_data_builder.h"
|
| +#include "storage/browser/blob/blob_data_handle.h"
|
| +#include "storage/browser/blob/blob_storage_context.h"
|
| +#include "storage/browser/fileapi/file_stream_reader.h"
|
| +#include "storage/browser/fileapi/file_system_context.h"
|
| +#include "storage/browser/fileapi/file_system_file_util.h"
|
| +#include "testing/gmock/include/gmock/gmock.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +#include "url/gurl.h"
|
| +
|
| +using base::FilePath;
|
| +using content::AsyncFileTestHelper;
|
| +using net::DrainableIOBuffer;
|
| +using net::IOBuffer;
|
| +
|
| +namespace storage {
|
| +namespace {
|
| +
|
| +const int kTestDiskCacheStreamIndex = 0;
|
| +
|
| +// Our disk cache tests don't need a real data handle since the tests themselves
|
| +// scope the disk cache and entries.
|
| +class EmptyDataHandle : public storage::BlobDataBuilder::DataHandle {
|
| + private:
|
| + ~EmptyDataHandle() override {}
|
| +};
|
| +
|
| +// A disk_cache::Entry that arbitrarily delays the completion of a read
|
| +// operation to allow testing some races without flake. This is particularly
|
| +// relevant in this unit test, which uses the always-synchronous MEMORY_CACHE.
|
| +class DelayedReadEntry : public disk_cache::Entry {
|
| + public:
|
| + explicit DelayedReadEntry(disk_cache::ScopedEntryPtr entry)
|
| + : entry_(entry.Pass()) {}
|
| + ~DelayedReadEntry() override { EXPECT_FALSE(HasPendingReadCallbacks()); }
|
| +
|
| + bool HasPendingReadCallbacks() { return !pending_read_callbacks_.empty(); }
|
| +
|
| + void RunPendingReadCallbacks() {
|
| + std::vector<base::Callback<void(void)>> callbacks;
|
| + pending_read_callbacks_.swap(callbacks);
|
| + for (const auto& callback : callbacks)
|
| + callback.Run();
|
| + }
|
| +
|
| + // From disk_cache::Entry:
|
| + void Doom() override { entry_->Doom(); }
|
| +
|
| + void Close() override { delete this; } // Note this is required by the API.
|
| +
|
| + std::string GetKey() const override { return entry_->GetKey(); }
|
| +
|
| + base::Time GetLastUsed() const override { return entry_->GetLastUsed(); }
|
| +
|
| + base::Time GetLastModified() const override {
|
| + return entry_->GetLastModified();
|
| + }
|
| +
|
| + int32 GetDataSize(int index) const override {
|
| + return entry_->GetDataSize(index);
|
| + }
|
| +
|
| + int ReadData(int index,
|
| + int offset,
|
| + IOBuffer* buf,
|
| + int buf_len,
|
| + const CompletionCallback& original_callback) override {
|
| + net::TestCompletionCallback callback;
|
| + int rv = entry_->ReadData(index, offset, buf, buf_len, callback.callback());
|
| + DCHECK_NE(rv, net::ERR_IO_PENDING)
|
| + << "Test expects to use a MEMORY_CACHE instance, which is synchronous.";
|
| + pending_read_callbacks_.push_back(base::Bind(original_callback, rv));
|
| + return net::ERR_IO_PENDING;
|
| + }
|
| +
|
| + int WriteData(int index,
|
| + int offset,
|
| + IOBuffer* buf,
|
| + int buf_len,
|
| + const CompletionCallback& callback,
|
| + bool truncate) override {
|
| + return entry_->WriteData(index, offset, buf, buf_len, callback, truncate);
|
| + }
|
| +
|
| + int ReadSparseData(int64 offset,
|
| + IOBuffer* buf,
|
| + int buf_len,
|
| + const CompletionCallback& callback) override {
|
| + return entry_->ReadSparseData(offset, buf, buf_len, callback);
|
| + }
|
| +
|
| + int WriteSparseData(int64 offset,
|
| + IOBuffer* buf,
|
| + int buf_len,
|
| + const CompletionCallback& callback) override {
|
| + return entry_->WriteSparseData(offset, buf, buf_len, callback);
|
| + }
|
| +
|
| + int GetAvailableRange(int64 offset,
|
| + int len,
|
| + int64* start,
|
| + const CompletionCallback& callback) override {
|
| + return entry_->GetAvailableRange(offset, len, start, callback);
|
| + }
|
| +
|
| + bool CouldBeSparse() const override { return entry_->CouldBeSparse(); }
|
| +
|
| + void CancelSparseIO() override { entry_->CancelSparseIO(); }
|
| +
|
| + int ReadyForSparseIO(const CompletionCallback& callback) override {
|
| + return entry_->ReadyForSparseIO(callback);
|
| + }
|
| +
|
| + private:
|
| + disk_cache::ScopedEntryPtr entry_;
|
| + std::vector<base::Callback<void(void)>> pending_read_callbacks_;
|
| +};
|
| +
|
| +scoped_ptr<disk_cache::Backend> CreateInMemoryDiskCache(
|
| + const scoped_refptr<base::SingleThreadTaskRunner>& thread) {
|
| + scoped_ptr<disk_cache::Backend> cache;
|
| + net::TestCompletionCallback callback;
|
| + int rv = disk_cache::CreateCacheBackend(
|
| + net::MEMORY_CACHE, net::CACHE_BACKEND_DEFAULT, FilePath(), 0, false,
|
| + thread, nullptr, &cache, callback.callback());
|
| + EXPECT_EQ(net::OK, callback.GetResult(rv));
|
| +
|
| + return cache.Pass();
|
| +}
|
| +
|
| +disk_cache::ScopedEntryPtr CreateDiskCacheEntry(disk_cache::Backend* cache,
|
| + const char* key,
|
| + const std::string& data) {
|
| + disk_cache::Entry* temp_entry = nullptr;
|
| + net::TestCompletionCallback callback;
|
| + int rv = cache->CreateEntry(key, &temp_entry, callback.callback());
|
| + if (callback.GetResult(rv) != net::OK)
|
| + return nullptr;
|
| + disk_cache::ScopedEntryPtr entry(temp_entry);
|
| +
|
| + scoped_refptr<net::StringIOBuffer> iobuffer = new net::StringIOBuffer(data);
|
| + rv = entry->WriteData(kTestDiskCacheStreamIndex, 0, iobuffer.get(),
|
| + iobuffer->size(), callback.callback(), false);
|
| + EXPECT_EQ(static_cast<int>(data.size()), callback.GetResult(rv));
|
| + return entry.Pass();
|
| +}
|
| +
|
| +template <typename T>
|
| +void SetValue(T* address, T value) {
|
| + *address = value;
|
| +}
|
| +
|
| +class FakeFileStreamReader : public FileStreamReader {
|
| + public:
|
| + explicit FakeFileStreamReader(const std::string& contents)
|
| + : buffer_(new DrainableIOBuffer(
|
| + new net::StringIOBuffer(
|
| + scoped_ptr<std::string>(new std::string(contents))),
|
| + contents.size())),
|
| + net_error_(net::OK),
|
| + size_(contents.size()) {}
|
| + FakeFileStreamReader(const std::string& contents, uint64_t size)
|
| + : buffer_(new DrainableIOBuffer(
|
| + new net::StringIOBuffer(
|
| + scoped_ptr<std::string>(new std::string(contents))),
|
| + contents.size())),
|
| + net_error_(net::OK),
|
| + size_(size) {}
|
| +
|
| + void ReturnError(int net_error) { net_error_ = net_error; }
|
| +
|
| + void DoAsync(base::SingleThreadTaskRunner* runner) {
|
| + async_task_runner_ = runner;
|
| + }
|
| +
|
| + ~FakeFileStreamReader() override {}
|
| +
|
| + int Read(net::IOBuffer* buf,
|
| + int buf_length,
|
| + const net::CompletionCallback& done) override {
|
| + if (net_error_ == net::OK) {
|
| + if (async_task_runner_.get()) {
|
| + async_task_runner_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(base::IgnoreResult(&FakeFileStreamReader::ReadImpl),
|
| + base::Unretained(this), scoped_refptr<IOBuffer>(buf),
|
| + buf_length, done));
|
| + return net::ERR_IO_PENDING;
|
| + } else {
|
| + return ReadImpl(buf, buf_length, net::CompletionCallback());
|
| + }
|
| + }
|
| + if (async_task_runner_.get()) {
|
| + async_task_runner_->PostTask(FROM_HERE, base::Bind(done, net_error_));
|
| + return net::ERR_IO_PENDING;
|
| + }
|
| + return net_error_;
|
| + }
|
| +
|
| + int64 GetLength(const net::Int64CompletionCallback& size_callback) override {
|
| + if (net_error_ == net::OK) {
|
| + if (async_task_runner_.get()) {
|
| + async_task_runner_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(base::IgnoreResult(&FakeFileStreamReader::GetLengthImpl),
|
| + base::Unretained(this), size_callback));
|
| + return net::ERR_IO_PENDING;
|
| + } else {
|
| + return GetLengthImpl(net::Int64CompletionCallback());
|
| + }
|
| + }
|
| + if (async_task_runner_.get()) {
|
| + async_task_runner_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(size_callback, static_cast<int64_t>(net_error_)));
|
| + return net::ERR_IO_PENDING;
|
| + }
|
| + return net_error_;
|
| + }
|
| +
|
| + private:
|
| + int ReadImpl(scoped_refptr<net::IOBuffer> buf,
|
| + int buf_length,
|
| + const net::CompletionCallback& done) {
|
| + CHECK_GE(buf_length, 0);
|
| + int length = std::min(buf_length, buffer_->BytesRemaining());
|
| + memcpy(buf->data(), buffer_->data(), length);
|
| + buffer_->DidConsume(length);
|
| + if (done.is_null()) {
|
| + return length;
|
| + }
|
| + done.Run(length);
|
| + return net::ERR_IO_PENDING;
|
| + }
|
| +
|
| + int64 GetLengthImpl(const net::Int64CompletionCallback& size_callback) {
|
| + if (size_callback.is_null()) {
|
| + return size_;
|
| + }
|
| + size_callback.Run(size_);
|
| + return net::ERR_IO_PENDING;
|
| + }
|
| +
|
| + scoped_refptr<net::DrainableIOBuffer> buffer_;
|
| + scoped_refptr<base::SingleThreadTaskRunner> async_task_runner_;
|
| + int net_error_;
|
| + uint64_t size_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(FakeFileStreamReader);
|
| +};
|
| +
|
| +class MockFileStreamReaderProvider
|
| + : public BlobReader::FileStreamReaderProvider {
|
| + public:
|
| + ~MockFileStreamReaderProvider() override {}
|
| +
|
| + MOCK_METHOD4(CreateForLocalFile,
|
| + FileStreamReader*(base::TaskRunner* task_runner,
|
| + const FilePath& file_path,
|
| + int64_t initial_offset,
|
| + const base::Time& expected_modification_time));
|
| + MOCK_METHOD4(CreateFileStreamReader,
|
| + FileStreamReader*(const GURL& filesystem_url,
|
| + int64_t offset,
|
| + int64_t max_bytes_to_read,
|
| + const base::Time& expected_modification_time));
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +class BlobReaderTest : public ::testing::Test {
|
| + public:
|
| + BlobReaderTest() {}
|
| + ~BlobReaderTest() override {}
|
| +
|
| + void TearDown() override { base::RunLoop().RunUntilIdle(); }
|
| +
|
| + protected:
|
| + void InitializeReader(BlobDataBuilder* builder) {
|
| + blob_handle_ = builder ? context_.AddFinishedBlob(builder).Pass() : nullptr;
|
| + provider_ = new MockFileStreamReaderProvider();
|
| + scoped_ptr<BlobReader::FileStreamReaderProvider> temp_ptr(provider_);
|
| + reader_.reset(new BlobReader(blob_handle_.get(), temp_ptr.Pass(),
|
| + message_loop_.task_runner().get()));
|
| + }
|
| +
|
| + // Takes ownership of the file reader (the blob reader takes ownership).
|
| + void ExpectLocalFileCall(const FilePath& file_path,
|
| + base::Time modification_time,
|
| + uint64_t initial_offset,
|
| + FakeFileStreamReader* reader) {
|
| + EXPECT_CALL(*provider_,
|
| + CreateForLocalFile(message_loop_.task_runner().get(), file_path,
|
| + initial_offset, modification_time))
|
| + .WillOnce(testing::Return(reader));
|
| + }
|
| +
|
| + // Takes ownership of the file reader (the blob reader takes ownership).
|
| + void ExpectFileSystemCall(const GURL& filesystem_url,
|
| + int64_t offset,
|
| + int64_t max_bytes_to_read,
|
| + base::Time expected_modification_time,
|
| + FakeFileStreamReader* reader) {
|
| + EXPECT_CALL(*provider_, CreateFileStreamReader(filesystem_url, offset,
|
| + max_bytes_to_read,
|
| + expected_modification_time))
|
| + .WillOnce(testing::Return(reader));
|
| + }
|
| +
|
| + void CheckSizeCalculatedSynchronously(size_t expected_size, int async_size) {
|
| + EXPECT_EQ(-1, async_size);
|
| + EXPECT_EQ(net::OK, reader_->net_error());
|
| + EXPECT_EQ(expected_size, reader_->total_size());
|
| + EXPECT_TRUE(reader_->total_size_calculated());
|
| + }
|
| +
|
| + void CheckSizeNotCalculatedYet(int async_size) {
|
| + EXPECT_EQ(-1, async_size);
|
| + EXPECT_EQ(net::OK, reader_->net_error());
|
| + EXPECT_FALSE(reader_->total_size_calculated());
|
| + }
|
| +
|
| + void CheckSizeCalculatedAsynchronously(size_t expected_size, int async_size) {
|
| + EXPECT_EQ(expected_size, static_cast<size_t>(async_size));
|
| + EXPECT_EQ(net::OK, reader_->net_error());
|
| + EXPECT_EQ(expected_size, reader_->total_size());
|
| + EXPECT_TRUE(reader_->total_size_calculated());
|
| + }
|
| +
|
| + scoped_refptr<net::IOBuffer> CreateBuffer(uint64_t size) {
|
| + return scoped_refptr<net::IOBuffer>(
|
| + new net::IOBuffer(static_cast<size_t>(size)));
|
| + }
|
| +
|
| + bool IsReaderTotalSizeCalculated() {
|
| + return reader_->total_size_calculated();
|
| + }
|
| +
|
| + BlobStorageContext context_;
|
| + scoped_ptr<BlobDataHandle> blob_handle_;
|
| + MockFileStreamReaderProvider* provider_ = nullptr;
|
| + base::MessageLoop message_loop_;
|
| + scoped_ptr<BlobReader> reader_;
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(BlobReaderTest);
|
| +};
|
| +
|
| +namespace {
|
| +
|
| +TEST_F(BlobReaderTest, BasicMemory) {
|
| + BlobDataBuilder b("uuid");
|
| + const std::string kData("Hello!!!");
|
| + const size_t kDataSize = 8ul;
|
| + b.AppendData(kData);
|
| + this->InitializeReader(&b);
|
| +
|
| + int calculated_size = -1;
|
| + EXPECT_FALSE(IsReaderTotalSizeCalculated());
|
| + EXPECT_EQ(BlobReader::Status::DONE, reader_->CalculateSize(base::Bind(
|
| + &SetValue<int>, &calculated_size)));
|
| + CheckSizeCalculatedSynchronously(kDataSize, calculated_size);
|
| +
|
| + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kDataSize));
|
| +
|
| + int bytes_read = 0;
|
| + int async_bytes_read = 0;
|
| + EXPECT_EQ(BlobReader::Status::DONE,
|
| + reader_->Read(buffer.get(), kDataSize, &bytes_read,
|
| + base::Bind(&SetValue<int>, &async_bytes_read)));
|
| + EXPECT_EQ(net::OK, reader_->net_error());
|
| + EXPECT_EQ(kDataSize, static_cast<size_t>(bytes_read));
|
| + EXPECT_EQ(0, async_bytes_read);
|
| + EXPECT_EQ(0, memcmp(buffer->data(), "Hello!!!", kDataSize));
|
| +}
|
| +
|
| +TEST_F(BlobReaderTest, BasicFile) {
|
| + BlobDataBuilder b("uuid");
|
| + const FilePath kPath = FilePath::FromUTF8Unsafe("/fake/file.txt");
|
| + const std::string kData = "FileData!!!";
|
| + const base::Time kTime = base::Time::Now();
|
| + b.AppendFile(kPath, 0, kData.size(), kTime);
|
| + this->InitializeReader(&b);
|
| +
|
| + // Non-async reader.
|
| + ExpectLocalFileCall(kPath, kTime, 0, new FakeFileStreamReader(kData));
|
| +
|
| + int calculated_size = -1;
|
| + EXPECT_FALSE(IsReaderTotalSizeCalculated());
|
| + EXPECT_EQ(BlobReader::Status::DONE, reader_->CalculateSize(base::Bind(
|
| + &SetValue<int>, &calculated_size)));
|
| + CheckSizeCalculatedSynchronously(kData.size(), calculated_size);
|
| +
|
| + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kData.size()));
|
| +
|
| + int bytes_read = 0;
|
| + int async_bytes_read = 0;
|
| + EXPECT_EQ(BlobReader::Status::DONE,
|
| + reader_->Read(buffer.get(), kData.size(), &bytes_read,
|
| + base::Bind(&SetValue<int>, &async_bytes_read)));
|
| + EXPECT_EQ(net::OK, reader_->net_error());
|
| + EXPECT_EQ(kData.size(), static_cast<size_t>(bytes_read));
|
| + EXPECT_EQ(0, async_bytes_read);
|
| + EXPECT_EQ(0, memcmp(buffer->data(), "FileData!!!", kData.size()));
|
| +}
|
| +
|
| +TEST_F(BlobReaderTest, BasicFileSystem) {
|
| + BlobDataBuilder b("uuid");
|
| + const GURL kURL("file://test_file/here.txt");
|
| + const std::string kData = "FileData!!!";
|
| + const base::Time kTime = base::Time::Now();
|
| + b.AppendFileSystemFile(kURL, 0, kData.size(), kTime);
|
| + this->InitializeReader(&b);
|
| +
|
| + // Non-async reader.
|
| + ExpectFileSystemCall(kURL, 0, kData.size(), kTime,
|
| + new FakeFileStreamReader(kData));
|
| +
|
| + int calculated_size = -1;
|
| + EXPECT_FALSE(IsReaderTotalSizeCalculated());
|
| + EXPECT_EQ(BlobReader::Status::DONE, reader_->CalculateSize(base::Bind(
|
| + &SetValue<int>, &calculated_size)));
|
| + CheckSizeCalculatedSynchronously(kData.size(), calculated_size);
|
| +
|
| + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kData.size()));
|
| +
|
| + int bytes_read = 0;
|
| + int async_bytes_read = 0;
|
| + EXPECT_EQ(BlobReader::Status::DONE,
|
| + reader_->Read(buffer.get(), kData.size(), &bytes_read,
|
| + base::Bind(&SetValue<int>, &async_bytes_read)));
|
| + EXPECT_EQ(net::OK, reader_->net_error());
|
| + EXPECT_EQ(kData.size(), static_cast<size_t>(bytes_read));
|
| + EXPECT_EQ(0, async_bytes_read);
|
| + EXPECT_EQ(0, memcmp(buffer->data(), "FileData!!!", kData.size()));
|
| +}
|
| +
|
| +TEST_F(BlobReaderTest, BasicDiskCache) {
|
| + scoped_ptr<disk_cache::Backend> cache =
|
| + CreateInMemoryDiskCache(message_loop_.task_runner());
|
| + ASSERT_TRUE(cache);
|
| +
|
| + BlobDataBuilder b("uuid");
|
| + const std::string kData = "Test Blob Data";
|
| + scoped_refptr<BlobDataBuilder::DataHandle> data_handle =
|
| + new EmptyDataHandle();
|
| + disk_cache::ScopedEntryPtr entry =
|
| + CreateDiskCacheEntry(cache.get(), "test entry", kData);
|
| + b.AppendDiskCacheEntry(data_handle, entry.get(), kTestDiskCacheStreamIndex);
|
| + this->InitializeReader(&b);
|
| +
|
| + int calculated_size = -1;
|
| + EXPECT_FALSE(IsReaderTotalSizeCalculated());
|
| + EXPECT_EQ(BlobReader::Status::DONE, reader_->CalculateSize(base::Bind(
|
| + &SetValue<int>, &calculated_size)));
|
| + CheckSizeCalculatedSynchronously(kData.size(), calculated_size);
|
| +
|
| + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kData.size()));
|
| +
|
| + int bytes_read = 0;
|
| + int async_bytes_read = 0;
|
| + EXPECT_EQ(BlobReader::Status::DONE,
|
| + reader_->Read(buffer.get(), kData.size(), &bytes_read,
|
| + base::Bind(&SetValue<int>, &async_bytes_read)));
|
| + EXPECT_EQ(net::OK, reader_->net_error());
|
| + EXPECT_EQ(kData.size(), static_cast<size_t>(bytes_read));
|
| + EXPECT_EQ(0, async_bytes_read);
|
| + EXPECT_EQ(0, memcmp(buffer->data(), "Test Blob Data", kData.size()));
|
| +}
|
| +
|
| +TEST_F(BlobReaderTest, BufferLargerThanMemory) {
|
| + BlobDataBuilder b("uuid");
|
| + const std::string kData("Hello!!!");
|
| + const size_t kDataSize = 8ul;
|
| + const size_t kBufferSize = 10ul;
|
| + b.AppendData(kData);
|
| + this->InitializeReader(&b);
|
| +
|
| + int calculated_size = -1;
|
| + EXPECT_FALSE(IsReaderTotalSizeCalculated());
|
| + EXPECT_EQ(BlobReader::Status::DONE, reader_->CalculateSize(base::Bind(
|
| + &SetValue<int>, &calculated_size)));
|
| + CheckSizeCalculatedSynchronously(kData.size(), calculated_size);
|
| +
|
| + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize));
|
| +
|
| + int bytes_read = 0;
|
| + int async_bytes_read = 0;
|
| + EXPECT_EQ(BlobReader::Status::DONE,
|
| + reader_->Read(buffer.get(), kBufferSize, &bytes_read,
|
| + base::Bind(&SetValue<int>, &async_bytes_read)));
|
| + EXPECT_EQ(net::OK, reader_->net_error());
|
| + EXPECT_EQ(kDataSize, static_cast<size_t>(bytes_read));
|
| + EXPECT_EQ(0, async_bytes_read);
|
| + EXPECT_EQ(0, memcmp(buffer->data(), "Hello!!!", kDataSize));
|
| +}
|
| +
|
| +TEST_F(BlobReaderTest, MemoryRange) {
|
| + BlobDataBuilder b("uuid");
|
| + const std::string kData("Hello!!!");
|
| + const size_t kDataSize = 8ul;
|
| + const size_t kSeekOffset = 2ul;
|
| + const uint64_t kReadLength = 4ull;
|
| + b.AppendData(kData);
|
| + this->InitializeReader(&b);
|
| +
|
| + int calculated_size = -1;
|
| + EXPECT_FALSE(IsReaderTotalSizeCalculated());
|
| + EXPECT_EQ(BlobReader::Status::DONE, reader_->CalculateSize(base::Bind(
|
| + &SetValue<int>, &calculated_size)));
|
| + CheckSizeCalculatedSynchronously(kData.size(), calculated_size);
|
| +
|
| + scoped_refptr<net::IOBuffer> buffer = CreateBuffer(kReadLength);
|
| +
|
| + reader_->SetReadRange(kSeekOffset, kReadLength);
|
| + int bytes_read = 0;
|
| + int async_bytes_read = 0;
|
| + EXPECT_EQ(BlobReader::Status::DONE,
|
| + reader_->Read(buffer.get(), kDataSize - kSeekOffset, &bytes_read,
|
| + base::Bind(&SetValue<int>, &async_bytes_read)));
|
| + EXPECT_EQ(net::OK, reader_->net_error());
|
| + EXPECT_EQ(kReadLength, static_cast<size_t>(bytes_read));
|
| + EXPECT_EQ(0, async_bytes_read);
|
| + EXPECT_EQ(0, memcmp(buffer->data(), "llo!", kReadLength));
|
| +}
|
| +
|
| +TEST_F(BlobReaderTest, BufferSmallerThanMemory) {
|
| + BlobDataBuilder b("uuid");
|
| + const std::string kData("Hello!!!");
|
| + const size_t kBufferSize = 4ul;
|
| + b.AppendData(kData);
|
| + this->InitializeReader(&b);
|
| +
|
| + int calculated_size = -1;
|
| + EXPECT_FALSE(IsReaderTotalSizeCalculated());
|
| + EXPECT_EQ(BlobReader::Status::DONE, reader_->CalculateSize(base::Bind(
|
| + &SetValue<int>, &calculated_size)));
|
| + CheckSizeCalculatedSynchronously(kData.size(), calculated_size);
|
| +
|
| + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize));
|
| +
|
| + int bytes_read = 0;
|
| + int async_bytes_read = 0;
|
| + EXPECT_EQ(BlobReader::Status::DONE,
|
| + reader_->Read(buffer.get(), kBufferSize, &bytes_read,
|
| + base::Bind(&SetValue<int>, &async_bytes_read)));
|
| + EXPECT_EQ(net::OK, reader_->net_error());
|
| + EXPECT_EQ(kBufferSize, static_cast<size_t>(bytes_read));
|
| + EXPECT_EQ(0, async_bytes_read);
|
| + EXPECT_EQ(0, memcmp(buffer->data(), "Hell", kBufferSize));
|
| +
|
| + bytes_read = 0;
|
| + EXPECT_EQ(BlobReader::Status::DONE,
|
| + reader_->Read(buffer.get(), kBufferSize, &bytes_read,
|
| + base::Bind(&SetValue<int>, &async_bytes_read)));
|
| + EXPECT_EQ(net::OK, reader_->net_error());
|
| + EXPECT_EQ(kBufferSize, static_cast<size_t>(bytes_read));
|
| + EXPECT_EQ(0, async_bytes_read);
|
| + EXPECT_EQ(0, memcmp(buffer->data(), "o!!!", kBufferSize));
|
| +}
|
| +
|
| +TEST_F(BlobReaderTest, SegmentedBufferAndMemory) {
|
| + BlobDataBuilder b("uuid");
|
| + const size_t kNumItems = 10;
|
| + const size_t kItemSize = 6;
|
| + const size_t kBufferSize = 10;
|
| + const size_t kTotalSize = kNumItems * kItemSize;
|
| + char current_value = 0;
|
| + for (size_t i = 0; i < kNumItems; i++) {
|
| + char buf[kItemSize];
|
| + for (size_t j = 0; j < kItemSize; j++) {
|
| + buf[j] = current_value++;
|
| + }
|
| + b.AppendData(buf, kItemSize);
|
| + }
|
| + this->InitializeReader(&b);
|
| +
|
| + int calculated_size = -1;
|
| + EXPECT_FALSE(IsReaderTotalSizeCalculated());
|
| + EXPECT_EQ(BlobReader::Status::DONE, reader_->CalculateSize(base::Bind(
|
| + &SetValue<int>, &calculated_size)));
|
| + CheckSizeCalculatedSynchronously(kTotalSize, calculated_size);
|
| +
|
| + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize));
|
| +
|
| + current_value = 0;
|
| + for (size_t i = 0; i < kTotalSize / kBufferSize; i++) {
|
| + int bytes_read = 0;
|
| + int async_bytes_read = 0;
|
| + EXPECT_EQ(BlobReader::Status::DONE,
|
| + reader_->Read(buffer.get(), kBufferSize, &bytes_read,
|
| + base::Bind(&SetValue<int>, &async_bytes_read)));
|
| + EXPECT_EQ(net::OK, reader_->net_error());
|
| + EXPECT_EQ(kBufferSize, static_cast<size_t>(bytes_read));
|
| + EXPECT_EQ(0, async_bytes_read);
|
| + for (size_t j = 0; j < kBufferSize; j++) {
|
| + EXPECT_EQ(current_value, buffer->data()[j]);
|
| + current_value++;
|
| + }
|
| + }
|
| +}
|
| +
|
| +TEST_F(BlobReaderTest, FileAsync) {
|
| + BlobDataBuilder b("uuid");
|
| + const FilePath kPath = FilePath::FromUTF8Unsafe("/fake/file.txt");
|
| + const std::string kData = "FileData!!!";
|
| + const base::Time kTime = base::Time::Now();
|
| + b.AppendFile(kPath, 0, kData.size(), kTime);
|
| + this->InitializeReader(&b);
|
| +
|
| + scoped_ptr<FakeFileStreamReader> reader(new FakeFileStreamReader(kData));
|
| + reader->DoAsync(message_loop_.task_runner().get());
|
| +
|
| + ExpectLocalFileCall(kPath, kTime, 0, reader.release());
|
| +
|
| + int calculated_size = -1;
|
| + EXPECT_FALSE(IsReaderTotalSizeCalculated());
|
| + EXPECT_EQ(
|
| + BlobReader::Status::IO_PENDING,
|
| + reader_->CalculateSize(base::Bind(&SetValue<int>, &calculated_size)));
|
| + CheckSizeNotCalculatedYet(calculated_size);
|
| + message_loop_.RunUntilIdle();
|
| + CheckSizeCalculatedAsynchronously(kData.size(), calculated_size);
|
| +
|
| + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kData.size()));
|
| +
|
| + int bytes_read = 0;
|
| + int async_bytes_read = 0;
|
| + EXPECT_EQ(BlobReader::Status::IO_PENDING,
|
| + reader_->Read(buffer.get(), kData.size(), &bytes_read,
|
| + base::Bind(&SetValue<int>, &async_bytes_read)));
|
| + message_loop_.RunUntilIdle();
|
| + EXPECT_EQ(net::OK, reader_->net_error());
|
| + EXPECT_EQ(kData.size(), static_cast<size_t>(async_bytes_read));
|
| + EXPECT_EQ(0, bytes_read);
|
| + EXPECT_EQ(0, memcmp(buffer->data(), "FileData!!!", kData.size()));
|
| +}
|
| +
|
| +TEST_F(BlobReaderTest, FileSystemAsync) {
|
| + BlobDataBuilder b("uuid");
|
| + const GURL kURL("file://test_file/here.txt");
|
| + const std::string kData = "FileData!!!";
|
| + const base::Time kTime = base::Time::Now();
|
| + b.AppendFileSystemFile(kURL, 0, kData.size(), kTime);
|
| + this->InitializeReader(&b);
|
| +
|
| + scoped_ptr<FakeFileStreamReader> reader(new FakeFileStreamReader(kData));
|
| + reader->DoAsync(message_loop_.task_runner().get());
|
| +
|
| + ExpectFileSystemCall(kURL, 0, kData.size(), kTime, reader.release());
|
| +
|
| + int calculated_size = -1;
|
| + EXPECT_FALSE(IsReaderTotalSizeCalculated());
|
| + EXPECT_EQ(
|
| + BlobReader::Status::IO_PENDING,
|
| + reader_->CalculateSize(base::Bind(&SetValue<int>, &calculated_size)));
|
| + CheckSizeNotCalculatedYet(calculated_size);
|
| + message_loop_.RunUntilIdle();
|
| + CheckSizeCalculatedAsynchronously(kData.size(), calculated_size);
|
| +
|
| + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kData.size()));
|
| +
|
| + int bytes_read = 0;
|
| + int async_bytes_read = 0;
|
| + EXPECT_EQ(BlobReader::Status::IO_PENDING,
|
| + reader_->Read(buffer.get(), kData.size(), &bytes_read,
|
| + base::Bind(&SetValue<int>, &async_bytes_read)));
|
| + message_loop_.RunUntilIdle();
|
| + EXPECT_EQ(net::OK, reader_->net_error());
|
| + EXPECT_EQ(kData.size(), static_cast<size_t>(async_bytes_read));
|
| + EXPECT_EQ(0, bytes_read);
|
| + EXPECT_EQ(0, memcmp(buffer->data(), "FileData!!!", kData.size()));
|
| +}
|
| +
|
| +TEST_F(BlobReaderTest, DiskCacheAsync) {
|
| + scoped_ptr<disk_cache::Backend> cache =
|
| + CreateInMemoryDiskCache(message_loop_.task_runner());
|
| + ASSERT_TRUE(cache);
|
| +
|
| + BlobDataBuilder b("uuid");
|
| + const std::string kData = "Test Blob Data";
|
| + scoped_refptr<BlobDataBuilder::DataHandle> data_handle =
|
| + new EmptyDataHandle();
|
| + scoped_ptr<DelayedReadEntry> delayed_read_entry(new DelayedReadEntry(
|
| + CreateDiskCacheEntry(cache.get(), "test entry", kData).Pass()));
|
| + b.AppendDiskCacheEntry(data_handle, delayed_read_entry.get(),
|
| + kTestDiskCacheStreamIndex);
|
| + this->InitializeReader(&b);
|
| +
|
| + int calculated_size = -1;
|
| + EXPECT_FALSE(IsReaderTotalSizeCalculated());
|
| + EXPECT_EQ(BlobReader::Status::DONE, reader_->CalculateSize(base::Bind(
|
| + &SetValue<int>, &calculated_size)));
|
| + CheckSizeCalculatedSynchronously(kData.size(), calculated_size);
|
| +
|
| + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kData.size()));
|
| +
|
| + int bytes_read = 0;
|
| + int async_bytes_read = 0;
|
| + EXPECT_EQ(BlobReader::Status::IO_PENDING,
|
| + reader_->Read(buffer.get(), kData.size(), &bytes_read,
|
| + base::Bind(&SetValue<int>, &async_bytes_read)));
|
| + EXPECT_TRUE(delayed_read_entry->HasPendingReadCallbacks());
|
| + delayed_read_entry->RunPendingReadCallbacks();
|
| + EXPECT_EQ(net::OK, reader_->net_error());
|
| + EXPECT_EQ(0, bytes_read);
|
| + EXPECT_EQ(kData.size(), static_cast<size_t>(async_bytes_read));
|
| + EXPECT_EQ(0, memcmp(buffer->data(), "Test Blob Data", kData.size()));
|
| +}
|
| +
|
| +TEST_F(BlobReaderTest, FileRange) {
|
| + BlobDataBuilder b("uuid");
|
| + const FilePath kPath = FilePath::FromUTF8Unsafe("/fake/file.txt");
|
| + // We check the offset in the ExpectLocalFileCall mock.
|
| + const std::string kRangeData = "leD";
|
| + const std::string kData = "FileData!!!";
|
| + const uint64_t kOffset = 2;
|
| + const uint64_t kReadLength = 3;
|
| + const base::Time kTime = base::Time::Now();
|
| + b.AppendFile(kPath, 0, kData.size(), kTime);
|
| + this->InitializeReader(&b);
|
| +
|
| + scoped_ptr<FakeFileStreamReader> reader(new FakeFileStreamReader(kData));
|
| + reader->DoAsync(message_loop_.task_runner().get());
|
| + ExpectLocalFileCall(kPath, kTime, 0, reader.release());
|
| +
|
| + // We create the reader again with the offset after the seek.
|
| + reader.reset(new FakeFileStreamReader(kRangeData));
|
| + reader->DoAsync(message_loop_.task_runner().get());
|
| + ExpectLocalFileCall(kPath, kTime, kOffset, reader.release());
|
| +
|
| + int calculated_size = -1;
|
| + EXPECT_EQ(
|
| + BlobReader::Status::IO_PENDING,
|
| + reader_->CalculateSize(base::Bind(&SetValue<int>, &calculated_size)));
|
| + message_loop_.RunUntilIdle();
|
| +
|
| + scoped_refptr<net::IOBuffer> buffer = CreateBuffer(kReadLength);
|
| + EXPECT_EQ(BlobReader::Status::DONE,
|
| + reader_->SetReadRange(kOffset, kReadLength));
|
| +
|
| + int bytes_read = 0;
|
| + int async_bytes_read = 0;
|
| + EXPECT_EQ(BlobReader::Status::IO_PENDING,
|
| + reader_->Read(buffer.get(), kReadLength, &bytes_read,
|
| + base::Bind(&SetValue<int>, &async_bytes_read)));
|
| + message_loop_.RunUntilIdle();
|
| + EXPECT_EQ(net::OK, reader_->net_error());
|
| + EXPECT_EQ(kReadLength, static_cast<size_t>(async_bytes_read));
|
| + EXPECT_EQ(0, bytes_read);
|
| + EXPECT_EQ(0, memcmp(buffer->data(), "leD", kReadLength));
|
| +}
|
| +
|
| +TEST_F(BlobReaderTest, DiskCacheRange) {
|
| + scoped_ptr<disk_cache::Backend> cache =
|
| + CreateInMemoryDiskCache(message_loop_.task_runner());
|
| + ASSERT_TRUE(cache);
|
| +
|
| + BlobDataBuilder b("uuid");
|
| + const std::string kData = "Test Blob Data";
|
| + const uint64_t kOffset = 2;
|
| + const uint64_t kReadLength = 3;
|
| + scoped_refptr<BlobDataBuilder::DataHandle> data_handle =
|
| + new EmptyDataHandle();
|
| + disk_cache::ScopedEntryPtr entry =
|
| + CreateDiskCacheEntry(cache.get(), "test entry", kData);
|
| + b.AppendDiskCacheEntry(data_handle, entry.get(), kTestDiskCacheStreamIndex);
|
| + this->InitializeReader(&b);
|
| +
|
| + int calculated_size = -1;
|
| + EXPECT_EQ(BlobReader::Status::DONE, reader_->CalculateSize(base::Bind(
|
| + &SetValue<int>, &calculated_size)));
|
| +
|
| + scoped_refptr<net::IOBuffer> buffer = CreateBuffer(kReadLength);
|
| + EXPECT_EQ(BlobReader::Status::DONE,
|
| + reader_->SetReadRange(kOffset, kReadLength));
|
| +
|
| + int bytes_read = 0;
|
| + int async_bytes_read = 0;
|
| + EXPECT_EQ(BlobReader::Status::DONE,
|
| + reader_->Read(buffer.get(), kReadLength, &bytes_read,
|
| + base::Bind(&SetValue<int>, &async_bytes_read)));
|
| + EXPECT_EQ(net::OK, reader_->net_error());
|
| + EXPECT_EQ(kReadLength, static_cast<size_t>(bytes_read));
|
| + EXPECT_EQ(0, async_bytes_read);
|
| + EXPECT_EQ(0, memcmp(buffer->data(), "st ", kReadLength));
|
| +}
|
| +
|
| +TEST_F(BlobReaderTest, FileSomeAsyncSegmentedOffsetsUnknownSizes) {
|
| + // This tests includes:
|
| + // * Unknown file sizes (item length of uint64::max) for every other item.
|
| + // * Offsets for every 3rd file item.
|
| + // * Non-async reader for every 4th file item.
|
| + BlobDataBuilder b("uuid");
|
| + const FilePath kPathBase = FilePath::FromUTF8Unsafe("/fake/file.txt");
|
| + const base::Time kTime = base::Time::Now();
|
| + const size_t kNumItems = 10;
|
| + const size_t kItemSize = 6;
|
| + const size_t kBufferSize = 10;
|
| + const size_t kTotalSize = kNumItems * kItemSize;
|
| + char current_value = 0;
|
| + // Create blob and reader.
|
| + for (size_t i = 0; i < kNumItems; i++) {
|
| + current_value += kItemSize;
|
| + FilePath path = kPathBase.Append(
|
| + FilePath::FromUTF8Unsafe(base::StringPrintf("%d", current_value)));
|
| + uint64_t offset = i % 3 == 0 ? 1 : 0;
|
| + uint64_t size =
|
| + i % 2 == 0 ? kItemSize : std::numeric_limits<uint64_t>::max();
|
| + b.AppendFile(path, offset, size, kTime);
|
| + }
|
| + this->InitializeReader(&b);
|
| +
|
| + // Set expectations.
|
| + current_value = 0;
|
| + for (size_t i = 0; i < kNumItems; i++) {
|
| + uint64_t offset = i % 3 == 0 ? 1 : 0;
|
| + char buf[kItemSize + offset];
|
| + if (offset > 0) {
|
| + memset(buf, 7, offset);
|
| + }
|
| + for (size_t j = 0; j < kItemSize; j++) {
|
| + buf[j + offset] = current_value++;
|
| + }
|
| + scoped_ptr<FakeFileStreamReader> reader(new FakeFileStreamReader(
|
| + std::string(buf + offset, kItemSize), kItemSize + offset));
|
| + if (i % 4 != 0) {
|
| + reader->DoAsync(message_loop_.task_runner().get());
|
| + }
|
| + FilePath path = kPathBase.Append(
|
| + FilePath::FromUTF8Unsafe(base::StringPrintf("%d", current_value)));
|
| + ExpectLocalFileCall(path, kTime, offset, reader.release());
|
| + }
|
| +
|
| + int calculated_size = -1;
|
| + EXPECT_FALSE(IsReaderTotalSizeCalculated());
|
| + EXPECT_EQ(
|
| + BlobReader::Status::IO_PENDING,
|
| + reader_->CalculateSize(base::Bind(&SetValue<int>, &calculated_size)));
|
| + CheckSizeNotCalculatedYet(calculated_size);
|
| + message_loop_.RunUntilIdle();
|
| + CheckSizeCalculatedAsynchronously(kTotalSize, calculated_size);
|
| +
|
| + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize));
|
| +
|
| + current_value = 0;
|
| + for (size_t i = 0; i < kTotalSize / kBufferSize; i++) {
|
| + int bytes_read = 0;
|
| + int async_bytes_read = 0;
|
| + EXPECT_EQ(BlobReader::Status::IO_PENDING,
|
| + reader_->Read(buffer.get(), kBufferSize, &bytes_read,
|
| + base::Bind(&SetValue<int>, &async_bytes_read)));
|
| + message_loop_.RunUntilIdle();
|
| + EXPECT_EQ(net::OK, reader_->net_error());
|
| + EXPECT_EQ(0, bytes_read);
|
| + EXPECT_EQ(kBufferSize, static_cast<size_t>(async_bytes_read));
|
| + for (size_t j = 0; j < kBufferSize; j++) {
|
| + EXPECT_EQ(current_value, buffer->data()[j]);
|
| + current_value++;
|
| + }
|
| + }
|
| +}
|
| +
|
| +TEST_F(BlobReaderTest, MixedContent) {
|
| + // Includes data, a file, and a disk cache entry.
|
| + scoped_ptr<disk_cache::Backend> cache =
|
| + CreateInMemoryDiskCache(message_loop_.task_runner());
|
| + ASSERT_TRUE(cache);
|
| +
|
| + BlobDataBuilder b("uuid");
|
| + const std::string kData1("Hello ");
|
| + const std::string kData2("there. ");
|
| + const std::string kData3("This ");
|
| + const std::string kData4("is multi-content.");
|
| + const uint64_t kDataSize = 35;
|
| +
|
| + const base::Time kTime = base::Time::Now();
|
| + const FilePath kData1Path = FilePath::FromUTF8Unsafe("/fake/file.txt");
|
| +
|
| + disk_cache::ScopedEntryPtr entry3 =
|
| + CreateDiskCacheEntry(cache.get(), "test entry", kData3);
|
| +
|
| + b.AppendFile(kData1Path, 0, kData1.size(), kTime);
|
| + b.AppendData(kData2);
|
| + b.AppendDiskCacheEntry(
|
| + scoped_refptr<BlobDataBuilder::DataHandle>(new EmptyDataHandle()),
|
| + entry3.get(), kTestDiskCacheStreamIndex);
|
| + b.AppendData(kData4);
|
| +
|
| + this->InitializeReader(&b);
|
| +
|
| + scoped_ptr<FakeFileStreamReader> reader(new FakeFileStreamReader(kData1));
|
| + reader->DoAsync(message_loop_.task_runner().get());
|
| + ExpectLocalFileCall(kData1Path, kTime, 0, reader.release());
|
| +
|
| + int calculated_size = -1;
|
| + EXPECT_FALSE(IsReaderTotalSizeCalculated());
|
| + EXPECT_EQ(
|
| + BlobReader::Status::IO_PENDING,
|
| + reader_->CalculateSize(base::Bind(&SetValue<int>, &calculated_size)));
|
| + CheckSizeNotCalculatedYet(calculated_size);
|
| + message_loop_.RunUntilIdle();
|
| + CheckSizeCalculatedAsynchronously(kDataSize, calculated_size);
|
| +
|
| + scoped_refptr<net::IOBuffer> buffer = CreateBuffer(kDataSize);
|
| +
|
| + int bytes_read = 0;
|
| + int async_bytes_read = 0;
|
| + EXPECT_EQ(BlobReader::Status::IO_PENDING,
|
| + reader_->Read(buffer.get(), kDataSize, &bytes_read,
|
| + base::Bind(&SetValue<int>, &async_bytes_read)));
|
| + EXPECT_EQ(0, async_bytes_read);
|
| + message_loop_.RunUntilIdle();
|
| + EXPECT_EQ(net::OK, reader_->net_error());
|
| + EXPECT_EQ(0, bytes_read);
|
| + EXPECT_EQ(kDataSize, static_cast<size_t>(async_bytes_read));
|
| + EXPECT_EQ(0, memcmp(buffer->data(), "Hello there. This is multi-content.",
|
| + kDataSize));
|
| +}
|
| +
|
| +TEST_F(BlobReaderTest, StateErrors) {
|
| + // Test common variables
|
| + int bytes_read = -1;
|
| + int async_bytes_read = -1;
|
| + int calculated_size = -1;
|
| + const std::string kData("Hello!!!");
|
| +
|
| + // Case: Blob handle is a nullptr.
|
| + InitializeReader(nullptr);
|
| + EXPECT_EQ(
|
| + BlobReader::Status::NET_ERROR,
|
| + reader_->CalculateSize(base::Bind(&SetValue<int>, &calculated_size)));
|
| + EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error());
|
| + EXPECT_EQ(BlobReader::Status::NET_ERROR, reader_->SetReadRange(0, 10));
|
| + EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error());
|
| + scoped_refptr<net::IOBuffer> buffer = CreateBuffer(10);
|
| + EXPECT_EQ(BlobReader::Status::NET_ERROR,
|
| + reader_->Read(buffer.get(), 10, &bytes_read,
|
| + base::Bind(&SetValue<int>, &async_bytes_read)));
|
| + EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error());
|
| +
|
| + // Case: Not calling CalculateSize before SetReadRange.
|
| + BlobDataBuilder builder1("uuid1");
|
| + builder1.AppendData(kData);
|
| + InitializeReader(&builder1);
|
| + EXPECT_EQ(BlobReader::Status::NET_ERROR, reader_->SetReadRange(0, 10));
|
| + EXPECT_EQ(net::ERR_FAILED, reader_->net_error());
|
| + EXPECT_EQ(BlobReader::Status::NET_ERROR,
|
| + reader_->Read(buffer.get(), 10, &bytes_read,
|
| + base::Bind(&SetValue<int>, &async_bytes_read)));
|
| + EXPECT_EQ(net::ERR_FAILED, reader_->net_error());
|
| + EXPECT_EQ(0, bytes_read);
|
| +
|
| + // Case: Not calling CalculateSize before Read.
|
| + BlobDataBuilder builder2("uuid2");
|
| + builder2.AppendData(kData);
|
| + InitializeReader(&builder2);
|
| + EXPECT_EQ(BlobReader::Status::NET_ERROR,
|
| + reader_->Read(buffer.get(), 10, &bytes_read,
|
| + base::Bind(&SetValue<int>, &async_bytes_read)));
|
| + EXPECT_EQ(net::ERR_FAILED, reader_->net_error());
|
| + EXPECT_EQ(0, bytes_read);
|
| +}
|
| +
|
| +TEST_F(BlobReaderTest, FileErrorsSync) {
|
| + int calculated_size = -1;
|
| + const FilePath kPath = FilePath::FromUTF8Unsafe("/fake/file.txt");
|
| + const std::string kData = "FileData!!!";
|
| + const base::Time kTime = base::Time::Now();
|
| +
|
| + // Case: Error on length query.
|
| + BlobDataBuilder builder1("uuid1");
|
| + builder1.AppendFile(kPath, 0, kData.size(), kTime);
|
| + this->InitializeReader(&builder1);
|
| + FakeFileStreamReader* reader = new FakeFileStreamReader(kData);
|
| + reader->ReturnError(net::ERR_FILE_NOT_FOUND);
|
| + ExpectLocalFileCall(kPath, kTime, 0, reader);
|
| +
|
| + EXPECT_EQ(
|
| + BlobReader::Status::NET_ERROR,
|
| + reader_->CalculateSize(base::Bind(&SetValue<int>, &calculated_size)));
|
| + EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error());
|
| +
|
| + // Case: Error on read.
|
| + BlobDataBuilder builder2("uuid2");
|
| + builder2.AppendFile(kPath, 0, kData.size(), kTime);
|
| + this->InitializeReader(&builder2);
|
| + reader = new FakeFileStreamReader(kData);
|
| + ExpectLocalFileCall(kPath, kTime, 0, reader);
|
| + EXPECT_EQ(BlobReader::Status::DONE, reader_->CalculateSize(base::Bind(
|
| + &SetValue<int>, &calculated_size)));
|
| + reader->ReturnError(net::ERR_FILE_NOT_FOUND);
|
| +
|
| + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kData.size()));
|
| + int bytes_read = 0;
|
| + int async_bytes_read = 0;
|
| + EXPECT_EQ(BlobReader::Status::NET_ERROR,
|
| + reader_->Read(buffer.get(), kData.size(), &bytes_read,
|
| + base::Bind(&SetValue<int>, &async_bytes_read)));
|
| + EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error());
|
| +}
|
| +
|
| +TEST_F(BlobReaderTest, FileErrorsAsync) {
|
| + int calculated_size = -1;
|
| + const FilePath kPath = FilePath::FromUTF8Unsafe("/fake/file.txt");
|
| + const std::string kData = "FileData!!!";
|
| + const base::Time kTime = base::Time::Now();
|
| +
|
| + // Case: Error on length query.
|
| + BlobDataBuilder builder1("uuid1");
|
| + builder1.AppendFile(kPath, 0, kData.size(), kTime);
|
| + this->InitializeReader(&builder1);
|
| + FakeFileStreamReader* reader = new FakeFileStreamReader(kData);
|
| + reader->DoAsync(message_loop_.task_runner().get());
|
| + reader->ReturnError(net::ERR_FILE_NOT_FOUND);
|
| + ExpectLocalFileCall(kPath, kTime, 0, reader);
|
| +
|
| + EXPECT_EQ(
|
| + BlobReader::Status::IO_PENDING,
|
| + reader_->CalculateSize(base::Bind(&SetValue<int>, &calculated_size)));
|
| + EXPECT_EQ(net::OK, reader_->net_error());
|
| + message_loop_.RunUntilIdle();
|
| + EXPECT_EQ(net::ERR_FILE_NOT_FOUND, calculated_size);
|
| + EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error());
|
| +
|
| + // Case: Error on read.
|
| + BlobDataBuilder builder2("uuid2");
|
| + builder2.AppendFile(kPath, 0, kData.size(), kTime);
|
| + this->InitializeReader(&builder2);
|
| + reader = new FakeFileStreamReader(kData);
|
| + ExpectLocalFileCall(kPath, kTime, 0, reader);
|
| + EXPECT_EQ(BlobReader::Status::DONE, reader_->CalculateSize(base::Bind(
|
| + &SetValue<int>, &calculated_size)));
|
| + reader->ReturnError(net::ERR_FILE_NOT_FOUND);
|
| + reader->DoAsync(message_loop_.task_runner().get());
|
| +
|
| + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kData.size()));
|
| + int bytes_read = 0;
|
| + int async_bytes_read = 0;
|
| + EXPECT_EQ(BlobReader::Status::IO_PENDING,
|
| + reader_->Read(buffer.get(), kData.size(), &bytes_read,
|
| + base::Bind(&SetValue<int>, &async_bytes_read)));
|
| + EXPECT_EQ(net::OK, reader_->net_error());
|
| + message_loop_.RunUntilIdle();
|
| + EXPECT_EQ(net::ERR_FILE_NOT_FOUND, async_bytes_read);
|
| + EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error());
|
| +}
|
| +
|
| +TEST_F(BlobReaderTest, RangeError) {
|
| + const std::string kData("Hello!!!");
|
| + const size_t kDataSize = 8ul;
|
| + const uint64_t kReadLength = 4ull;
|
| +
|
| + // Case: offset too high.
|
| + BlobDataBuilder b("uuid1");
|
| + b.AppendData(kData);
|
| + this->InitializeReader(&b);
|
| + int calculated_size = -1;
|
| + EXPECT_EQ(BlobReader::Status::DONE, reader_->CalculateSize(base::Bind(
|
| + &SetValue<int>, &calculated_size)));
|
| + scoped_refptr<net::IOBuffer> buffer = CreateBuffer(kDataSize);
|
| + EXPECT_EQ(BlobReader::Status::NET_ERROR,
|
| + reader_->SetReadRange(kDataSize + 1, kReadLength));
|
| + EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error());
|
| +
|
| + // Case: length too long.
|
| + BlobDataBuilder b2("uuid2");
|
| + b2.AppendData(kData);
|
| + this->InitializeReader(&b2);
|
| + calculated_size = -1;
|
| + EXPECT_EQ(BlobReader::Status::DONE, reader_->CalculateSize(base::Bind(
|
| + &SetValue<int>, &calculated_size)));
|
| + buffer = CreateBuffer(kDataSize + 1);
|
| + EXPECT_EQ(BlobReader::Status::NET_ERROR,
|
| + reader_->SetReadRange(0, kDataSize + 1));
|
| + EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error());
|
| +}
|
| +
|
| +} // namespace
|
| +} // namespace storage
|
|
|