1 // Copyright (c) 2012 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.
5 #include "webkit/fileapi/file_system_file_stream_reader.h"
10 #include "base/files/scoped_temp_dir.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/message_loop.h"
13 #include "base/platform_file.h"
14 #include "net/base/io_buffer.h"
15 #include "net/base/net_errors.h"
16 #include "net/base/test_completion_callback.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "webkit/browser/fileapi/sandbox_mount_point_provider.h"
19 #include "webkit/fileapi/external_mount_points.h"
20 #include "webkit/fileapi/file_system_context.h"
21 #include "webkit/fileapi/file_system_file_util.h"
22 #include "webkit/fileapi/file_system_operation_context.h"
23 #include "webkit/fileapi/mock_file_system_context.h"
29 const char kURLOrigin
[] = "http://remote/";
30 const char kTestFileName
[] = "test.dat";
31 const char kTestData
[] = "0123456789";
32 const int kTestDataSize
= arraysize(kTestData
) - 1;
34 void ReadFromReader(FileSystemFileStreamReader
* reader
,
38 ASSERT_TRUE(reader
!= NULL
);
39 ASSERT_TRUE(result
!= NULL
);
41 net::TestCompletionCallback callback
;
42 size_t total_bytes_read
= 0;
43 while (total_bytes_read
< size
) {
44 scoped_refptr
<net::IOBufferWithSize
> buf(
45 new net::IOBufferWithSize(size
- total_bytes_read
));
46 int rv
= reader
->Read(buf
, buf
->size(), callback
.callback());
47 if (rv
== net::ERR_IO_PENDING
)
48 rv
= callback
.WaitForResult();
53 total_bytes_read
+= rv
;
54 data
->append(buf
->data(), rv
);
58 void NeverCalled(int unused
) { ADD_FAILURE(); }
62 class FileSystemFileStreamReaderTest
: public testing::Test
{
64 FileSystemFileStreamReaderTest()
65 : message_loop_(base::MessageLoop::TYPE_IO
) {}
67 virtual void SetUp() OVERRIDE
{
68 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
70 file_system_context_
= CreateFileSystemContextForTesting(
71 NULL
, temp_dir_
.path());
73 file_system_context_
->sandbox_provider()->ValidateFileSystemRoot(
74 GURL(kURLOrigin
), kFileSystemTypeTemporary
, true, // create
75 base::Bind(&OnValidateFileSystem
));
76 base::MessageLoop::current()->RunUntilIdle();
78 WriteFile(kTestFileName
, kTestData
, kTestDataSize
,
79 &test_file_modification_time_
);
82 virtual void TearDown() OVERRIDE
{
83 base::MessageLoop::current()->RunUntilIdle();
87 FileSystemFileStreamReader
* CreateFileReader(
88 const std::string
& file_name
,
90 const base::Time
& expected_modification_time
) {
91 return new FileSystemFileStreamReader(file_system_context_
,
92 GetFileSystemURL(file_name
),
94 expected_modification_time
);
97 base::Time
test_file_modification_time() const {
98 return test_file_modification_time_
;
101 void WriteFile(const std::string
& file_name
,
104 base::Time
* modification_time
) {
105 FileSystemFileUtil
* file_util
= file_system_context_
->
106 sandbox_provider()->GetFileUtil(kFileSystemTypeTemporary
);
107 FileSystemURL url
= GetFileSystemURL(file_name
);
109 FileSystemOperationContext
context(file_system_context_
);
110 context
.set_allowed_bytes_growth(1024);
112 base::PlatformFile handle
= base::kInvalidPlatformFileValue
;
113 bool created
= false;
114 ASSERT_EQ(base::PLATFORM_FILE_OK
, file_util
->CreateOrOpen(
117 base::PLATFORM_FILE_CREATE
| base::PLATFORM_FILE_WRITE
,
120 EXPECT_TRUE(created
);
121 ASSERT_NE(base::kInvalidPlatformFileValue
, handle
);
123 base::WritePlatformFile(handle
, 0 /* offset */, buf
, buf_size
));
124 base::ClosePlatformFile(handle
);
126 base::PlatformFileInfo file_info
;
127 base::FilePath platform_path
;
128 ASSERT_EQ(base::PLATFORM_FILE_OK
,
129 file_util
->GetFileInfo(&context
, url
, &file_info
,
131 if (modification_time
)
132 *modification_time
= file_info
.last_modified
;
136 static void OnValidateFileSystem(base::PlatformFileError result
) {
137 ASSERT_EQ(base::PLATFORM_FILE_OK
, result
);
140 FileSystemURL
GetFileSystemURL(const std::string
& file_name
) {
141 return file_system_context_
->CreateCrackedFileSystemURL(
143 kFileSystemTypeTemporary
,
144 base::FilePath().AppendASCII(file_name
));
147 base::MessageLoop message_loop_
;
148 base::ScopedTempDir temp_dir_
;
149 scoped_refptr
<FileSystemContext
> file_system_context_
;
150 base::Time test_file_modification_time_
;
153 TEST_F(FileSystemFileStreamReaderTest
, NonExistent
) {
154 const char kFileName
[] = "nonexistent";
155 scoped_ptr
<FileSystemFileStreamReader
> reader(
156 CreateFileReader(kFileName
, 0, base::Time()));
159 ReadFromReader(reader
.get(), &data
, 10, &result
);
160 ASSERT_EQ(net::ERR_FILE_NOT_FOUND
, result
);
161 ASSERT_EQ(0U, data
.size());
164 TEST_F(FileSystemFileStreamReaderTest
, Empty
) {
165 const char kFileName
[] = "empty";
166 WriteFile(kFileName
, NULL
, 0, NULL
);
168 scoped_ptr
<FileSystemFileStreamReader
> reader(
169 CreateFileReader(kFileName
, 0, base::Time()));
172 ReadFromReader(reader
.get(), &data
, 10, &result
);
173 ASSERT_EQ(net::OK
, result
);
174 ASSERT_EQ(0U, data
.size());
176 net::TestInt64CompletionCallback callback
;
177 int64 length_result
= reader
->GetLength(callback
.callback());
178 if (length_result
== net::ERR_IO_PENDING
)
179 length_result
= callback
.WaitForResult();
180 ASSERT_EQ(0, length_result
);
183 TEST_F(FileSystemFileStreamReaderTest
, GetLengthNormal
) {
184 scoped_ptr
<FileSystemFileStreamReader
> reader(
185 CreateFileReader(kTestFileName
, 0, test_file_modification_time()));
186 net::TestInt64CompletionCallback callback
;
187 int64 result
= reader
->GetLength(callback
.callback());
188 if (result
== net::ERR_IO_PENDING
)
189 result
= callback
.WaitForResult();
190 ASSERT_EQ(kTestDataSize
, result
);
193 TEST_F(FileSystemFileStreamReaderTest
, GetLengthAfterModified
) {
194 // Pass a fake expected modifictaion time so that the expectation fails.
195 base::Time fake_expected_modification_time
=
196 test_file_modification_time() - base::TimeDelta::FromSeconds(10);
198 scoped_ptr
<FileSystemFileStreamReader
> reader(
199 CreateFileReader(kTestFileName
, 0, fake_expected_modification_time
));
200 net::TestInt64CompletionCallback callback
;
201 int64 result
= reader
->GetLength(callback
.callback());
202 if (result
== net::ERR_IO_PENDING
)
203 result
= callback
.WaitForResult();
204 ASSERT_EQ(net::ERR_UPLOAD_FILE_CHANGED
, result
);
206 // With NULL expected modification time this should work.
207 reader
.reset(CreateFileReader(kTestFileName
, 0, base::Time()));
208 result
= reader
->GetLength(callback
.callback());
209 if (result
== net::ERR_IO_PENDING
)
210 result
= callback
.WaitForResult();
211 ASSERT_EQ(kTestDataSize
, result
);
214 TEST_F(FileSystemFileStreamReaderTest
, GetLengthWithOffset
) {
215 scoped_ptr
<FileSystemFileStreamReader
> reader(
216 CreateFileReader(kTestFileName
, 3, base::Time()));
217 net::TestInt64CompletionCallback callback
;
218 int64 result
= reader
->GetLength(callback
.callback());
219 if (result
== net::ERR_IO_PENDING
)
220 result
= callback
.WaitForResult();
221 // Initial offset does not affect the result of GetLength.
222 ASSERT_EQ(kTestDataSize
, result
);
225 TEST_F(FileSystemFileStreamReaderTest
, ReadNormal
) {
226 scoped_ptr
<FileSystemFileStreamReader
> reader(
227 CreateFileReader(kTestFileName
, 0, test_file_modification_time()));
230 ReadFromReader(reader
.get(), &data
, kTestDataSize
, &result
);
231 ASSERT_EQ(net::OK
, result
);
232 ASSERT_EQ(kTestData
, data
);
235 TEST_F(FileSystemFileStreamReaderTest
, ReadAfterModified
) {
236 // Pass a fake expected modifictaion time so that the expectation fails.
237 base::Time fake_expected_modification_time
=
238 test_file_modification_time() - base::TimeDelta::FromSeconds(10);
240 scoped_ptr
<FileSystemFileStreamReader
> reader(
241 CreateFileReader(kTestFileName
, 0, fake_expected_modification_time
));
244 ReadFromReader(reader
.get(), &data
, kTestDataSize
, &result
);
245 ASSERT_EQ(net::ERR_UPLOAD_FILE_CHANGED
, result
);
246 ASSERT_EQ(0U, data
.size());
248 // With NULL expected modification time this should work.
250 reader
.reset(CreateFileReader(kTestFileName
, 0, base::Time()));
251 ReadFromReader(reader
.get(), &data
, kTestDataSize
, &result
);
252 ASSERT_EQ(net::OK
, result
);
253 ASSERT_EQ(kTestData
, data
);
256 TEST_F(FileSystemFileStreamReaderTest
, ReadWithOffset
) {
257 scoped_ptr
<FileSystemFileStreamReader
> reader(
258 CreateFileReader(kTestFileName
, 3, base::Time()));
261 ReadFromReader(reader
.get(), &data
, kTestDataSize
, &result
);
262 ASSERT_EQ(net::OK
, result
);
263 ASSERT_EQ(&kTestData
[3], data
);
266 TEST_F(FileSystemFileStreamReaderTest
, DeleteWithUnfinishedRead
) {
267 scoped_ptr
<FileSystemFileStreamReader
> reader(
268 CreateFileReader(kTestFileName
, 0, base::Time()));
270 net::TestCompletionCallback callback
;
271 scoped_refptr
<net::IOBufferWithSize
> buf(
272 new net::IOBufferWithSize(kTestDataSize
));
273 int rv
= reader
->Read(buf
, buf
->size(), base::Bind(&NeverCalled
));
274 ASSERT_TRUE(rv
== net::ERR_IO_PENDING
|| rv
>= 0);
276 // Delete immediately.
277 // Should not crash; nor should NeverCalled be callback.
281 } // namespace fileapi