1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "storage/browser/fileapi/file_system_file_stream_reader.h" 6 7#include <limits> 8#include <string> 9 10#include "base/files/scoped_temp_dir.h" 11#include "base/memory/scoped_ptr.h" 12#include "base/run_loop.h" 13#include "content/public/test/async_file_test_helper.h" 14#include "content/public/test/test_file_system_context.h" 15#include "net/base/io_buffer.h" 16#include "net/base/net_errors.h" 17#include "net/base/test_completion_callback.h" 18#include "storage/browser/fileapi/external_mount_points.h" 19#include "storage/browser/fileapi/file_system_context.h" 20#include "storage/browser/fileapi/file_system_file_util.h" 21#include "testing/gtest/include/gtest/gtest.h" 22 23using content::AsyncFileTestHelper; 24using storage::FileSystemContext; 25using storage::FileSystemFileStreamReader; 26using storage::FileSystemType; 27using storage::FileSystemURL; 28 29namespace content { 30 31namespace { 32 33const char kURLOrigin[] = "http://remote/"; 34const char kTestFileName[] = "test.dat"; 35const char kTestData[] = "0123456789"; 36const int kTestDataSize = arraysize(kTestData) - 1; 37 38void ReadFromReader(storage::FileSystemFileStreamReader* reader, 39 std::string* data, 40 size_t size, 41 int* result) { 42 ASSERT_TRUE(reader != NULL); 43 ASSERT_TRUE(result != NULL); 44 *result = net::OK; 45 net::TestCompletionCallback callback; 46 size_t total_bytes_read = 0; 47 while (total_bytes_read < size) { 48 scoped_refptr<net::IOBufferWithSize> buf( 49 new net::IOBufferWithSize(size - total_bytes_read)); 50 int rv = reader->Read(buf.get(), buf->size(), callback.callback()); 51 if (rv == net::ERR_IO_PENDING) 52 rv = callback.WaitForResult(); 53 if (rv < 0) 54 *result = rv; 55 if (rv <= 0) 56 break; 57 total_bytes_read += rv; 58 data->append(buf->data(), rv); 59 } 60} 61 62void NeverCalled(int unused) { ADD_FAILURE(); } 63 64} // namespace 65 66class FileSystemFileStreamReaderTest : public testing::Test { 67 public: 68 FileSystemFileStreamReaderTest() {} 69 70 virtual void SetUp() OVERRIDE { 71 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 72 73 file_system_context_ = CreateFileSystemContextForTesting( 74 NULL, temp_dir_.path()); 75 76 file_system_context_->OpenFileSystem( 77 GURL(kURLOrigin), 78 storage::kFileSystemTypeTemporary, 79 storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT, 80 base::Bind(&OnOpenFileSystem)); 81 base::RunLoop().RunUntilIdle(); 82 83 WriteFile(kTestFileName, kTestData, kTestDataSize, 84 &test_file_modification_time_); 85 } 86 87 virtual void TearDown() OVERRIDE { 88 base::RunLoop().RunUntilIdle(); 89 } 90 91 protected: 92 storage::FileSystemFileStreamReader* CreateFileReader( 93 const std::string& file_name, 94 int64 initial_offset, 95 const base::Time& expected_modification_time) { 96 return new FileSystemFileStreamReader(file_system_context_.get(), 97 GetFileSystemURL(file_name), 98 initial_offset, 99 expected_modification_time); 100 } 101 102 base::Time test_file_modification_time() const { 103 return test_file_modification_time_; 104 } 105 106 void WriteFile(const std::string& file_name, 107 const char* buf, 108 int buf_size, 109 base::Time* modification_time) { 110 FileSystemURL url = GetFileSystemURL(file_name); 111 112 ASSERT_EQ(base::File::FILE_OK, 113 content::AsyncFileTestHelper::CreateFileWithData( 114 file_system_context_.get(), url, buf, buf_size)); 115 116 base::File::Info file_info; 117 ASSERT_EQ(base::File::FILE_OK, 118 AsyncFileTestHelper::GetMetadata( 119 file_system_context_.get(), url, &file_info)); 120 if (modification_time) 121 *modification_time = file_info.last_modified; 122 } 123 124 private: 125 static void OnOpenFileSystem(const GURL& root_url, 126 const std::string& name, 127 base::File::Error result) { 128 ASSERT_EQ(base::File::FILE_OK, result); 129 } 130 131 FileSystemURL GetFileSystemURL(const std::string& file_name) { 132 return file_system_context_->CreateCrackedFileSystemURL( 133 GURL(kURLOrigin), 134 storage::kFileSystemTypeTemporary, 135 base::FilePath().AppendASCII(file_name)); 136 } 137 138 base::MessageLoopForIO message_loop_; 139 base::ScopedTempDir temp_dir_; 140 scoped_refptr<FileSystemContext> file_system_context_; 141 base::Time test_file_modification_time_; 142}; 143 144TEST_F(FileSystemFileStreamReaderTest, NonExistent) { 145 const char kFileName[] = "nonexistent"; 146 scoped_ptr<FileSystemFileStreamReader> reader( 147 CreateFileReader(kFileName, 0, base::Time())); 148 int result = 0; 149 std::string data; 150 ReadFromReader(reader.get(), &data, 10, &result); 151 ASSERT_EQ(net::ERR_FILE_NOT_FOUND, result); 152 ASSERT_EQ(0U, data.size()); 153} 154 155TEST_F(FileSystemFileStreamReaderTest, Empty) { 156 const char kFileName[] = "empty"; 157 WriteFile(kFileName, NULL, 0, NULL); 158 159 scoped_ptr<FileSystemFileStreamReader> reader( 160 CreateFileReader(kFileName, 0, base::Time())); 161 int result = 0; 162 std::string data; 163 ReadFromReader(reader.get(), &data, 10, &result); 164 ASSERT_EQ(net::OK, result); 165 ASSERT_EQ(0U, data.size()); 166 167 net::TestInt64CompletionCallback callback; 168 int64 length_result = reader->GetLength(callback.callback()); 169 if (length_result == net::ERR_IO_PENDING) 170 length_result = callback.WaitForResult(); 171 ASSERT_EQ(0, length_result); 172} 173 174TEST_F(FileSystemFileStreamReaderTest, GetLengthNormal) { 175 scoped_ptr<FileSystemFileStreamReader> reader( 176 CreateFileReader(kTestFileName, 0, test_file_modification_time())); 177 net::TestInt64CompletionCallback callback; 178 int64 result = reader->GetLength(callback.callback()); 179 if (result == net::ERR_IO_PENDING) 180 result = callback.WaitForResult(); 181 ASSERT_EQ(kTestDataSize, result); 182} 183 184TEST_F(FileSystemFileStreamReaderTest, GetLengthAfterModified) { 185 // Pass a fake expected modifictaion time so that the expectation fails. 186 base::Time fake_expected_modification_time = 187 test_file_modification_time() - base::TimeDelta::FromSeconds(10); 188 189 scoped_ptr<FileSystemFileStreamReader> reader( 190 CreateFileReader(kTestFileName, 0, fake_expected_modification_time)); 191 net::TestInt64CompletionCallback callback; 192 int64 result = reader->GetLength(callback.callback()); 193 if (result == net::ERR_IO_PENDING) 194 result = callback.WaitForResult(); 195 ASSERT_EQ(net::ERR_UPLOAD_FILE_CHANGED, result); 196 197 // With NULL expected modification time this should work. 198 reader.reset(CreateFileReader(kTestFileName, 0, base::Time())); 199 result = reader->GetLength(callback.callback()); 200 if (result == net::ERR_IO_PENDING) 201 result = callback.WaitForResult(); 202 ASSERT_EQ(kTestDataSize, result); 203} 204 205TEST_F(FileSystemFileStreamReaderTest, GetLengthWithOffset) { 206 scoped_ptr<FileSystemFileStreamReader> reader( 207 CreateFileReader(kTestFileName, 3, base::Time())); 208 net::TestInt64CompletionCallback callback; 209 int64 result = reader->GetLength(callback.callback()); 210 if (result == net::ERR_IO_PENDING) 211 result = callback.WaitForResult(); 212 // Initial offset does not affect the result of GetLength. 213 ASSERT_EQ(kTestDataSize, result); 214} 215 216TEST_F(FileSystemFileStreamReaderTest, ReadNormal) { 217 scoped_ptr<FileSystemFileStreamReader> reader( 218 CreateFileReader(kTestFileName, 0, test_file_modification_time())); 219 int result = 0; 220 std::string data; 221 ReadFromReader(reader.get(), &data, kTestDataSize, &result); 222 ASSERT_EQ(net::OK, result); 223 ASSERT_EQ(kTestData, data); 224} 225 226TEST_F(FileSystemFileStreamReaderTest, ReadAfterModified) { 227 // Pass a fake expected modifictaion time so that the expectation fails. 228 base::Time fake_expected_modification_time = 229 test_file_modification_time() - base::TimeDelta::FromSeconds(10); 230 231 scoped_ptr<FileSystemFileStreamReader> reader( 232 CreateFileReader(kTestFileName, 0, fake_expected_modification_time)); 233 int result = 0; 234 std::string data; 235 ReadFromReader(reader.get(), &data, kTestDataSize, &result); 236 ASSERT_EQ(net::ERR_UPLOAD_FILE_CHANGED, result); 237 ASSERT_EQ(0U, data.size()); 238 239 // With NULL expected modification time this should work. 240 data.clear(); 241 reader.reset(CreateFileReader(kTestFileName, 0, base::Time())); 242 ReadFromReader(reader.get(), &data, kTestDataSize, &result); 243 ASSERT_EQ(net::OK, result); 244 ASSERT_EQ(kTestData, data); 245} 246 247TEST_F(FileSystemFileStreamReaderTest, ReadWithOffset) { 248 scoped_ptr<FileSystemFileStreamReader> reader( 249 CreateFileReader(kTestFileName, 3, base::Time())); 250 int result = 0; 251 std::string data; 252 ReadFromReader(reader.get(), &data, kTestDataSize, &result); 253 ASSERT_EQ(net::OK, result); 254 ASSERT_EQ(&kTestData[3], data); 255} 256 257TEST_F(FileSystemFileStreamReaderTest, DeleteWithUnfinishedRead) { 258 scoped_ptr<FileSystemFileStreamReader> reader( 259 CreateFileReader(kTestFileName, 0, base::Time())); 260 261 net::TestCompletionCallback callback; 262 scoped_refptr<net::IOBufferWithSize> buf( 263 new net::IOBufferWithSize(kTestDataSize)); 264 int rv = reader->Read(buf.get(), buf->size(), base::Bind(&NeverCalled)); 265 ASSERT_TRUE(rv == net::ERR_IO_PENDING || rv >= 0); 266 267 // Delete immediately. 268 // Should not crash; nor should NeverCalled be callback. 269 reader.reset(); 270} 271 272} // namespace content 273