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