blob: 641b96852ca5df66e77b9081f959ed6b3e7d3c80 [file] [log] [blame]
// Copyright 2013 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 "content/browser/fileapi/upload_file_system_file_element_reader.h"
#include "base/files/scoped_temp_dir.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "content/public/test/async_file_test_helper.h"
#include "content/public/test/test_file_system_context.h"
#include "net/base/io_buffer.h"
#include "net/base/test_completion_callback.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webkit/browser/fileapi/file_system_backend.h"
#include "webkit/browser/fileapi/file_system_context.h"
#include "webkit/browser/fileapi/file_system_operation_context.h"
#include "webkit/browser/fileapi/file_system_url.h"
using content::AsyncFileTestHelper;
using fileapi::FileSystemContext;
using fileapi::FileSystemType;
using fileapi::FileSystemURL;
namespace content {
namespace {
const char kFileSystemURLOrigin[] = "http://remote";
const fileapi::FileSystemType kFileSystemType =
fileapi::kFileSystemTypeTemporary;
} // namespace
class UploadFileSystemFileElementReaderTest : public testing::Test {
public:
UploadFileSystemFileElementReaderTest() {}
virtual void SetUp() OVERRIDE {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
file_system_context_ = CreateFileSystemContextForTesting(
NULL, temp_dir_.path());
file_system_context_->OpenFileSystem(
GURL(kFileSystemURLOrigin),
kFileSystemType,
fileapi::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
base::Bind(&UploadFileSystemFileElementReaderTest::OnOpenFileSystem,
base::Unretained(this)));
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(file_system_root_url_.is_valid());
// Prepare a file on file system.
const char kTestData[] = "abcdefghijklmnop0123456789";
file_data_.assign(kTestData, kTestData + arraysize(kTestData) - 1);
const char kFilename[] = "File.dat";
file_url_ = GetFileSystemURL(kFilename);
WriteFileSystemFile(kFilename, &file_data_[0], file_data_.size(),
&file_modification_time_);
// Create and initialize a reader.
reader_.reset(
new UploadFileSystemFileElementReader(file_system_context_.get(),
file_url_,
0,
kuint64max,
file_modification_time_));
net::TestCompletionCallback callback;
ASSERT_EQ(net::ERR_IO_PENDING, reader_->Init(callback.callback()));
EXPECT_EQ(net::OK, callback.WaitForResult());
EXPECT_EQ(file_data_.size(), reader_->GetContentLength());
EXPECT_EQ(file_data_.size(), reader_->BytesRemaining());
EXPECT_FALSE(reader_->IsInMemory());
}
virtual void TearDown() OVERRIDE {
reader_.reset();
base::RunLoop().RunUntilIdle();
}
protected:
GURL GetFileSystemURL(const std::string& filename) {
return GURL(file_system_root_url_.spec() + filename);
}
void WriteFileSystemFile(const std::string& filename,
const char* buf,
int buf_size,
base::Time* modification_time) {
fileapi::FileSystemURL url =
file_system_context_->CreateCrackedFileSystemURL(
GURL(kFileSystemURLOrigin),
kFileSystemType,
base::FilePath().AppendASCII(filename));
ASSERT_EQ(base::File::FILE_OK,
AsyncFileTestHelper::CreateFileWithData(
file_system_context_, url, buf, buf_size));
base::File::Info file_info;
ASSERT_EQ(base::File::FILE_OK,
AsyncFileTestHelper::GetMetadata(
file_system_context_, url, &file_info));
*modification_time = file_info.last_modified;
}
void OnOpenFileSystem(const GURL& root,
const std::string& name,
base::File::Error result) {
ASSERT_EQ(base::File::FILE_OK, result);
ASSERT_TRUE(root.is_valid());
file_system_root_url_ = root;
}
base::MessageLoopForIO message_loop_;
base::ScopedTempDir temp_dir_;
scoped_refptr<FileSystemContext> file_system_context_;
GURL file_system_root_url_;
std::vector<char> file_data_;
GURL file_url_;
base::Time file_modification_time_;
scoped_ptr<UploadFileSystemFileElementReader> reader_;
};
TEST_F(UploadFileSystemFileElementReaderTest, ReadAll) {
scoped_refptr<net::IOBufferWithSize> buf =
new net::IOBufferWithSize(file_data_.size());
net::TestCompletionCallback read_callback;
ASSERT_EQ(net::ERR_IO_PENDING,
reader_->Read(buf.get(), buf->size(), read_callback.callback()));
EXPECT_EQ(buf->size(), read_callback.WaitForResult());
EXPECT_EQ(0U, reader_->BytesRemaining());
EXPECT_TRUE(std::equal(file_data_.begin(), file_data_.end(), buf->data()));
// Try to read again.
EXPECT_EQ(0, reader_->Read(buf.get(), buf->size(), read_callback.callback()));
}
TEST_F(UploadFileSystemFileElementReaderTest, ReadPartially) {
const size_t kHalfSize = file_data_.size() / 2;
ASSERT_EQ(file_data_.size(), kHalfSize * 2);
scoped_refptr<net::IOBufferWithSize> buf =
new net::IOBufferWithSize(kHalfSize);
net::TestCompletionCallback read_callback1;
ASSERT_EQ(net::ERR_IO_PENDING,
reader_->Read(buf.get(), buf->size(), read_callback1.callback()));
EXPECT_EQ(buf->size(), read_callback1.WaitForResult());
EXPECT_EQ(file_data_.size() - buf->size(), reader_->BytesRemaining());
EXPECT_TRUE(std::equal(file_data_.begin(), file_data_.begin() + kHalfSize,
buf->data()));
net::TestCompletionCallback read_callback2;
EXPECT_EQ(net::ERR_IO_PENDING,
reader_->Read(buf.get(), buf->size(), read_callback2.callback()));
EXPECT_EQ(buf->size(), read_callback2.WaitForResult());
EXPECT_EQ(0U, reader_->BytesRemaining());
EXPECT_TRUE(std::equal(file_data_.begin() + kHalfSize, file_data_.end(),
buf->data()));
}
TEST_F(UploadFileSystemFileElementReaderTest, ReadTooMuch) {
const size_t kTooLargeSize = file_data_.size() * 2;
scoped_refptr<net::IOBufferWithSize> buf =
new net::IOBufferWithSize(kTooLargeSize);
net::TestCompletionCallback read_callback;
ASSERT_EQ(net::ERR_IO_PENDING,
reader_->Read(buf.get(), buf->size(), read_callback.callback()));
EXPECT_EQ(static_cast<int>(file_data_.size()), read_callback.WaitForResult());
EXPECT_EQ(0U, reader_->BytesRemaining());
EXPECT_TRUE(std::equal(file_data_.begin(), file_data_.end(), buf->data()));
}
TEST_F(UploadFileSystemFileElementReaderTest, MultipleInit) {
scoped_refptr<net::IOBufferWithSize> buf =
new net::IOBufferWithSize(file_data_.size());
// Read all.
net::TestCompletionCallback read_callback1;
ASSERT_EQ(net::ERR_IO_PENDING,
reader_->Read(buf.get(), buf->size(), read_callback1.callback()));
EXPECT_EQ(buf->size(), read_callback1.WaitForResult());
EXPECT_EQ(0U, reader_->BytesRemaining());
EXPECT_TRUE(std::equal(file_data_.begin(), file_data_.end(), buf->data()));
// Call Init() again to reset the state.
net::TestCompletionCallback init_callback;
ASSERT_EQ(net::ERR_IO_PENDING, reader_->Init(init_callback.callback()));
EXPECT_EQ(net::OK, init_callback.WaitForResult());
EXPECT_EQ(file_data_.size(), reader_->GetContentLength());
EXPECT_EQ(file_data_.size(), reader_->BytesRemaining());
// Read again.
net::TestCompletionCallback read_callback2;
ASSERT_EQ(net::ERR_IO_PENDING,
reader_->Read(buf.get(), buf->size(), read_callback2.callback()));
EXPECT_EQ(buf->size(), read_callback2.WaitForResult());
EXPECT_EQ(0U, reader_->BytesRemaining());
EXPECT_TRUE(std::equal(file_data_.begin(), file_data_.end(), buf->data()));
}
TEST_F(UploadFileSystemFileElementReaderTest, InitDuringAsyncOperation) {
scoped_refptr<net::IOBufferWithSize> buf =
new net::IOBufferWithSize(file_data_.size());
// Start reading all.
net::TestCompletionCallback read_callback1;
EXPECT_EQ(net::ERR_IO_PENDING,
reader_->Read(buf.get(), buf->size(), read_callback1.callback()));
// Call Init to cancel the previous read.
net::TestCompletionCallback init_callback1;
EXPECT_EQ(net::ERR_IO_PENDING, reader_->Init(init_callback1.callback()));
// Call Init again to cancel the previous init.
net::TestCompletionCallback init_callback2;
EXPECT_EQ(net::ERR_IO_PENDING, reader_->Init(init_callback2.callback()));
EXPECT_EQ(net::OK, init_callback2.WaitForResult());
EXPECT_EQ(file_data_.size(), reader_->GetContentLength());
EXPECT_EQ(file_data_.size(), reader_->BytesRemaining());
// Read half.
scoped_refptr<net::IOBufferWithSize> buf2 =
new net::IOBufferWithSize(file_data_.size() / 2);
net::TestCompletionCallback read_callback2;
EXPECT_EQ(net::ERR_IO_PENDING,
reader_->Read(buf2.get(), buf2->size(), read_callback2.callback()));
EXPECT_EQ(buf2->size(), read_callback2.WaitForResult());
EXPECT_EQ(file_data_.size() - buf2->size(), reader_->BytesRemaining());
EXPECT_TRUE(std::equal(file_data_.begin(), file_data_.begin() + buf2->size(),
buf2->data()));
// Make sure callbacks are not called for cancelled operations.
EXPECT_FALSE(read_callback1.have_result());
EXPECT_FALSE(init_callback1.have_result());
}
TEST_F(UploadFileSystemFileElementReaderTest, Range) {
const int kOffset = 2;
const int kLength = file_data_.size() - kOffset * 3;
reader_.reset(new UploadFileSystemFileElementReader(
file_system_context_.get(), file_url_, kOffset, kLength, base::Time()));
net::TestCompletionCallback init_callback;
ASSERT_EQ(net::ERR_IO_PENDING, reader_->Init(init_callback.callback()));
EXPECT_EQ(net::OK, init_callback.WaitForResult());
EXPECT_EQ(static_cast<uint64>(kLength), reader_->GetContentLength());
EXPECT_EQ(static_cast<uint64>(kLength), reader_->BytesRemaining());
scoped_refptr<net::IOBufferWithSize> buf = new net::IOBufferWithSize(kLength);
net::TestCompletionCallback read_callback;
ASSERT_EQ(net::ERR_IO_PENDING,
reader_->Read(buf.get(), buf->size(), read_callback.callback()));
EXPECT_EQ(kLength, read_callback.WaitForResult());
EXPECT_TRUE(std::equal(file_data_.begin() + kOffset,
file_data_.begin() + kOffset + kLength,
buf->data()));
}
TEST_F(UploadFileSystemFileElementReaderTest, FileChanged) {
// Expect one second before the actual modification time to simulate change.
const base::Time expected_modification_time =
file_modification_time_ - base::TimeDelta::FromSeconds(1);
reader_.reset(
new UploadFileSystemFileElementReader(file_system_context_.get(),
file_url_,
0,
kuint64max,
expected_modification_time));
net::TestCompletionCallback init_callback;
ASSERT_EQ(net::ERR_IO_PENDING, reader_->Init(init_callback.callback()));
EXPECT_EQ(net::ERR_UPLOAD_FILE_CHANGED, init_callback.WaitForResult());
}
TEST_F(UploadFileSystemFileElementReaderTest, WrongURL) {
const GURL wrong_url = GetFileSystemURL("wrong_file_name.dat");
reader_.reset(new UploadFileSystemFileElementReader(
file_system_context_.get(), wrong_url, 0, kuint64max, base::Time()));
net::TestCompletionCallback init_callback;
ASSERT_EQ(net::ERR_IO_PENDING, reader_->Init(init_callback.callback()));
EXPECT_EQ(net::ERR_FILE_NOT_FOUND, init_callback.WaitForResult());
}
} // namespace content