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.
8 #include "base/basictypes.h"
10 #include "base/files/scoped_temp_dir.h"
11 #include "base/message_loop.h"
12 #include "googleurl/src/gurl.h"
13 #include "net/base/io_buffer.h"
14 #include "net/url_request/url_request.h"
15 #include "net/url_request/url_request_context.h"
16 #include "net/url_request/url_request_job.h"
17 #include "net/url_request/url_request_status.h"
18 #include "testing/platform_test.h"
19 #include "webkit/fileapi/file_system_context.h"
20 #include "webkit/fileapi/file_system_file_util.h"
21 #include "webkit/fileapi/file_system_operation_context.h"
22 #include "webkit/fileapi/file_writer_delegate.h"
23 #include "webkit/fileapi/local_file_system_operation.h"
24 #include "webkit/fileapi/local_file_system_test_helper.h"
25 #include "webkit/fileapi/sandbox_file_stream_writer.h"
26 #include "webkit/quota/quota_manager.h"
35 : status_(base::PLATFORM_FILE_OK
),
37 write_status_(FileWriterDelegate::SUCCESS_IO_PENDING
) {}
39 base::PlatformFileError
status() const { return status_
; }
40 int64
bytes_written() const { return bytes_written_
; }
41 FileWriterDelegate::WriteProgressStatus
write_status() const {
45 void DidWrite(base::PlatformFileError status
, int64 bytes
,
46 FileWriterDelegate::WriteProgressStatus write_status
) {
47 write_status_
= write_status
;
48 if (status
== base::PLATFORM_FILE_OK
) {
49 bytes_written_
+= bytes
;
50 if (write_status_
!= FileWriterDelegate::SUCCESS_IO_PENDING
)
51 MessageLoop::current()->Quit();
53 EXPECT_EQ(base::PLATFORM_FILE_OK
, status_
);
55 MessageLoop::current()->Quit();
60 // For post-operation status.
61 base::PlatformFileError status_
;
63 FileWriterDelegate::WriteProgressStatus write_status_
;
66 const char kData
[] = "The quick brown fox jumps over the lazy dog.\n";
67 const int kDataSize
= ARRAYSIZE_UNSAFE(kData
) - 1;
69 } // namespace (anonymous)
71 class FileWriterDelegateTest
: public PlatformTest
{
73 FileWriterDelegateTest()
74 : loop_(MessageLoop::TYPE_IO
),
75 test_helper_(GURL("http://example.com"), kFileSystemTypeTest
) {}
78 virtual void SetUp() OVERRIDE
;
79 virtual void TearDown() OVERRIDE
;
81 FileSystemFileUtil
* file_util() {
82 return test_helper_
.file_util();
85 int64
ComputeCurrentOriginUsage() {
86 return test_helper_
.ComputeCurrentOriginUsage();
89 FileSystemURL
GetFileSystemURL(const char* file_name
) const {
90 return test_helper_
.CreateURLFromUTF8(file_name
);
93 FileWriterDelegate
* CreateWriterDelegate(
94 const char* test_file_path
,
98 SandboxFileStreamWriter
* writer
= new SandboxFileStreamWriter(
99 test_helper_
.file_system_context(),
100 GetFileSystemURL(test_file_path
),
102 *test_helper_
.file_system_context()->GetUpdateObservers(
103 test_helper_
.type()));
104 writer
->set_default_quota(allowed_growth
);
105 return new FileWriterDelegate(
106 base::Bind(&Result::DidWrite
, base::Unretained(result
)),
107 scoped_ptr
<FileStreamWriter
>(writer
));
110 // Creates and sets up a FileWriterDelegate for writing the given |blob_url|,
111 // and creates a new FileWriterDelegate for the file.
112 void PrepareForWrite(const GURL
& blob_url
,
114 int64 allowed_growth
) {
115 result_
.reset(new Result());
116 file_writer_delegate_
.reset(
117 CreateWriterDelegate("test", offset
, allowed_growth
, result_
.get()));
118 request_
.reset(empty_context_
.CreateRequest(
119 blob_url
, file_writer_delegate_
.get()));
122 static net::URLRequest::ProtocolFactory Factory
;
124 // This should be alive until the very end of this instance.
127 net::URLRequestContext empty_context_
;
128 scoped_ptr
<FileWriterDelegate
> file_writer_delegate_
;
129 scoped_ptr
<net::URLRequest
> request_
;
130 scoped_ptr
<Result
> result_
;
131 LocalFileSystemTestOriginHelper test_helper_
;
133 base::ScopedTempDir dir_
;
135 static const char* content_
;
138 const char* FileWriterDelegateTest::content_
= NULL
;
142 static std::string g_content
;
144 class FileWriterDelegateTestJob
: public net::URLRequestJob
{
146 FileWriterDelegateTestJob(net::URLRequest
* request
,
147 net::NetworkDelegate
* network_delegate
,
148 const std::string
& content
)
149 : net::URLRequestJob(request
, network_delegate
),
151 remaining_bytes_(content
.length()),
155 virtual void Start() OVERRIDE
{
156 MessageLoop::current()->PostTask(
158 base::Bind(&FileWriterDelegateTestJob::NotifyHeadersComplete
, this));
161 virtual bool ReadRawData(net::IOBuffer
* buf
,
163 int *bytes_read
) OVERRIDE
{
164 if (remaining_bytes_
< buf_size
)
165 buf_size
= static_cast<int>(remaining_bytes_
);
167 for (int i
= 0; i
< buf_size
; ++i
)
168 buf
->data()[i
] = content_
[cursor_
++];
169 remaining_bytes_
-= buf_size
;
171 SetStatus(net::URLRequestStatus());
172 *bytes_read
= buf_size
;
176 virtual int GetResponseCode() const OVERRIDE
{
181 virtual ~FileWriterDelegateTestJob() {}
184 std::string content_
;
185 int remaining_bytes_
;
189 } // namespace (anonymous)
192 net::URLRequestJob
* FileWriterDelegateTest::Factory(
193 net::URLRequest
* request
,
194 net::NetworkDelegate
* network_delegate
,
195 const std::string
& scheme
) {
196 return new FileWriterDelegateTestJob(
197 request
, network_delegate
, FileWriterDelegateTest::content_
);
200 void FileWriterDelegateTest::SetUp() {
201 ASSERT_TRUE(dir_
.CreateUniqueTempDir());
202 base::FilePath base_dir
= dir_
.path().AppendASCII("filesystem");
203 test_helper_
.SetUp(base_dir
);
205 scoped_ptr
<FileSystemOperationContext
> context(
206 test_helper_
.NewOperationContext());
207 context
->set_allowed_bytes_growth(kint64max
);
208 bool created
= false;
209 base::PlatformFileError error
= file_util()->EnsureFileExists(
211 GetFileSystemURL("test"),
213 ASSERT_EQ(base::PLATFORM_FILE_OK
, error
);
214 ASSERT_TRUE(created
);
215 net::URLRequest::Deprecated::RegisterProtocolFactory("blob", &Factory
);
218 void FileWriterDelegateTest::TearDown() {
219 net::URLRequest::Deprecated::RegisterProtocolFactory("blob", NULL
);
220 test_helper_
.TearDown();
223 // FileWriterDelegateTest.WriteSuccessWithoutQuotaLimit is flaky on windows
224 // http://crbug.com/130401
226 #define MAYBE_WriteSuccessWithoutQuotaLimit \
227 DISABLED_WriteSuccessWithoutQuotaLimit
229 #define MAYBE_WriteSuccessWithoutQuotaLimit \
230 WriteSuccessWithoutQuotaLimit
232 TEST_F(FileWriterDelegateTest
, MAYBE_WriteSuccessWithoutQuotaLimit
) {
233 const GURL
kBlobURL("blob:nolimit");
236 PrepareForWrite(kBlobURL
, 0, quota::QuotaManager::kNoLimit
);
238 ASSERT_EQ(0, test_helper_
.GetCachedOriginUsage());
239 file_writer_delegate_
->Start(request_
.Pass());
240 MessageLoop::current()->Run();
242 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED
, result_
->write_status());
243 file_writer_delegate_
.reset();
245 ASSERT_EQ(kDataSize
, test_helper_
.GetCachedOriginUsage());
246 EXPECT_EQ(ComputeCurrentOriginUsage(), test_helper_
.GetCachedOriginUsage());
247 EXPECT_EQ(kDataSize
, result_
->bytes_written());
248 EXPECT_EQ(base::PLATFORM_FILE_OK
, result_
->status());
251 // FileWriterDelegateTest.WriteSuccessWithJustQuota is flaky on windows
252 // http://crbug.com/130401
254 #define MAYBE_WriteSuccessWithJustQuota DISABLED_WriteSuccessWithJustQuota
256 #define MAYBE_WriteSuccessWithJustQuota WriteSuccessWithJustQuota
259 TEST_F(FileWriterDelegateTest
, MAYBE_WriteSuccessWithJustQuota
) {
260 const GURL
kBlobURL("blob:just");
262 const int64 kAllowedGrowth
= kDataSize
;
263 PrepareForWrite(kBlobURL
, 0, kAllowedGrowth
);
265 ASSERT_EQ(0, test_helper_
.GetCachedOriginUsage());
266 file_writer_delegate_
->Start(request_
.Pass());
267 MessageLoop::current()->Run();
268 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED
, result_
->write_status());
269 file_writer_delegate_
.reset();
271 ASSERT_EQ(kAllowedGrowth
, test_helper_
.GetCachedOriginUsage());
272 EXPECT_EQ(ComputeCurrentOriginUsage(), test_helper_
.GetCachedOriginUsage());
274 EXPECT_EQ(kAllowedGrowth
, result_
->bytes_written());
275 EXPECT_EQ(base::PLATFORM_FILE_OK
, result_
->status());
278 TEST_F(FileWriterDelegateTest
, DISABLED_WriteFailureByQuota
) {
279 const GURL
kBlobURL("blob:failure");
281 const int64 kAllowedGrowth
= kDataSize
- 1;
282 PrepareForWrite(kBlobURL
, 0, kAllowedGrowth
);
284 ASSERT_EQ(0, test_helper_
.GetCachedOriginUsage());
285 file_writer_delegate_
->Start(request_
.Pass());
286 MessageLoop::current()->Run();
287 ASSERT_EQ(FileWriterDelegate::ERROR_WRITE_STARTED
, result_
->write_status());
288 file_writer_delegate_
.reset();
290 ASSERT_EQ(kAllowedGrowth
, test_helper_
.GetCachedOriginUsage());
291 EXPECT_EQ(ComputeCurrentOriginUsage(), test_helper_
.GetCachedOriginUsage());
293 EXPECT_EQ(kAllowedGrowth
, result_
->bytes_written());
294 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE
, result_
->status());
295 ASSERT_EQ(FileWriterDelegate::ERROR_WRITE_STARTED
, result_
->write_status());
298 TEST_F(FileWriterDelegateTest
, WriteZeroBytesSuccessfullyWithZeroQuota
) {
299 const GURL
kBlobURL("blob:zero");
301 int64 kAllowedGrowth
= 0;
302 PrepareForWrite(kBlobURL
, 0, kAllowedGrowth
);
304 ASSERT_EQ(0, test_helper_
.GetCachedOriginUsage());
305 file_writer_delegate_
->Start(request_
.Pass());
306 MessageLoop::current()->Run();
307 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED
, result_
->write_status());
308 file_writer_delegate_
.reset();
310 ASSERT_EQ(kAllowedGrowth
, test_helper_
.GetCachedOriginUsage());
311 EXPECT_EQ(ComputeCurrentOriginUsage(), test_helper_
.GetCachedOriginUsage());
313 EXPECT_EQ(kAllowedGrowth
, result_
->bytes_written());
314 EXPECT_EQ(base::PLATFORM_FILE_OK
, result_
->status());
315 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED
, result_
->write_status());
319 // See http://crbug.com/129264
320 #define MAYBE_WriteSuccessWithoutQuotaLimitConcurrent \
321 DISABLED_WriteSuccessWithoutQuotaLimitConcurrent
323 #define MAYBE_WriteSuccessWithoutQuotaLimitConcurrent \
324 WriteSuccessWithoutQuotaLimitConcurrent
327 TEST_F(FileWriterDelegateTest
, MAYBE_WriteSuccessWithoutQuotaLimitConcurrent
) {
328 scoped_ptr
<FileWriterDelegate
> file_writer_delegate2
;
329 scoped_ptr
<net::URLRequest
> request2
;
330 scoped_ptr
<Result
> result2
;
332 scoped_ptr
<FileSystemOperationContext
> context(
333 test_helper_
.NewOperationContext());
334 bool created
= false;
335 file_util()->EnsureFileExists(context
.get(),
336 GetFileSystemURL("test2"),
338 ASSERT_TRUE(created
);
340 const GURL
kBlobURL("blob:nolimitconcurrent");
341 const GURL
kBlobURL2("blob:nolimitconcurrent2");
344 PrepareForWrite(kBlobURL
, 0, quota::QuotaManager::kNoLimit
);
346 // Credate another FileWriterDelegate for concurrent write.
347 result2
.reset(new Result());
348 file_writer_delegate2
.reset(CreateWriterDelegate(
349 "test2", 0, quota::QuotaManager::kNoLimit
, result2
.get()));
350 request2
.reset(empty_context_
.CreateRequest(
351 kBlobURL2
, file_writer_delegate2
.get()));
353 ASSERT_EQ(0, test_helper_
.GetCachedOriginUsage());
354 file_writer_delegate_
->Start(request_
.Pass());
355 file_writer_delegate2
->Start(request2
.Pass());
356 MessageLoop::current()->Run();
357 if (result_
->write_status() == FileWriterDelegate::SUCCESS_IO_PENDING
||
358 result2
->write_status() == FileWriterDelegate::SUCCESS_IO_PENDING
)
359 MessageLoop::current()->Run();
361 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED
, result_
->write_status());
362 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED
, result2
->write_status());
363 file_writer_delegate_
.reset();
364 file_writer_delegate2
.reset();
366 ASSERT_EQ(kDataSize
* 2, test_helper_
.GetCachedOriginUsage());
367 EXPECT_EQ(ComputeCurrentOriginUsage(), test_helper_
.GetCachedOriginUsage());
369 EXPECT_EQ(kDataSize
, result_
->bytes_written());
370 EXPECT_EQ(base::PLATFORM_FILE_OK
, result_
->status());
371 EXPECT_EQ(kDataSize
, result2
->bytes_written());
372 EXPECT_EQ(base::PLATFORM_FILE_OK
, result2
->status());
376 // See http://crbug.com/129264
377 #define MAYBE_WritesWithQuotaAndOffset \
378 DISABLED_WritesWithQuotaAndOffset
380 #define MAYBE_WritesWithQuotaAndOffset \
381 WritesWithQuotaAndOffset
384 TEST_F(FileWriterDelegateTest
, MAYBE_WritesWithQuotaAndOffset
) {
385 const GURL
kBlobURL("blob:failure-with-updated-quota");
388 // Writing kDataSize (=45) bytes data while allowed_growth is 100.
390 int64 allowed_growth
= 100;
391 ASSERT_LT(kDataSize
, allowed_growth
);
392 PrepareForWrite(kBlobURL
, offset
, allowed_growth
);
394 ASSERT_EQ(0, test_helper_
.GetCachedOriginUsage());
395 file_writer_delegate_
->Start(request_
.Pass());
396 MessageLoop::current()->Run();
397 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED
, result_
->write_status());
398 file_writer_delegate_
.reset();
400 ASSERT_EQ(kDataSize
, test_helper_
.GetCachedOriginUsage());
401 EXPECT_EQ(ComputeCurrentOriginUsage(), test_helper_
.GetCachedOriginUsage());
402 EXPECT_EQ(kDataSize
, result_
->bytes_written());
403 EXPECT_EQ(base::PLATFORM_FILE_OK
, result_
->status());
405 // Trying to overwrite kDataSize bytes data while allowed_growth is 20.
408 PrepareForWrite(kBlobURL
, offset
, allowed_growth
);
410 file_writer_delegate_
->Start(request_
.Pass());
411 MessageLoop::current()->Run();
412 EXPECT_EQ(kDataSize
, test_helper_
.GetCachedOriginUsage());
413 EXPECT_EQ(ComputeCurrentOriginUsage(), test_helper_
.GetCachedOriginUsage());
414 EXPECT_EQ(kDataSize
, result_
->bytes_written());
415 EXPECT_EQ(base::PLATFORM_FILE_OK
, result_
->status());
416 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED
, result_
->write_status());
418 // Trying to write kDataSize bytes data from offset 25 while
419 // allowed_growth is 55.
422 PrepareForWrite(kBlobURL
, offset
, allowed_growth
);
424 file_writer_delegate_
->Start(request_
.Pass());
425 MessageLoop::current()->Run();
426 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED
, result_
->write_status());
427 file_writer_delegate_
.reset();
429 EXPECT_EQ(offset
+ kDataSize
, test_helper_
.GetCachedOriginUsage());
430 EXPECT_EQ(ComputeCurrentOriginUsage(), test_helper_
.GetCachedOriginUsage());
431 EXPECT_EQ(kDataSize
, result_
->bytes_written());
432 EXPECT_EQ(base::PLATFORM_FILE_OK
, result_
->status());
434 // Trying to overwrite 45 bytes data while allowed_growth is -20.
436 allowed_growth
= -20;
437 PrepareForWrite(kBlobURL
, offset
, allowed_growth
);
439 int64 pre_write_usage
= ComputeCurrentOriginUsage();
440 file_writer_delegate_
->Start(request_
.Pass());
441 MessageLoop::current()->Run();
442 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED
, result_
->write_status());
443 file_writer_delegate_
.reset();
445 EXPECT_EQ(pre_write_usage
, test_helper_
.GetCachedOriginUsage());
446 EXPECT_EQ(ComputeCurrentOriginUsage(), test_helper_
.GetCachedOriginUsage());
447 EXPECT_EQ(kDataSize
, result_
->bytes_written());
448 EXPECT_EQ(base::PLATFORM_FILE_OK
, result_
->status());
450 // Trying to overwrite 45 bytes data with offset pre_write_usage - 20,
451 // while allowed_growth is 10.
452 const int kOverlap
= 20;
453 offset
= pre_write_usage
- kOverlap
;
455 PrepareForWrite(kBlobURL
, offset
, allowed_growth
);
457 file_writer_delegate_
->Start(request_
.Pass());
458 MessageLoop::current()->Run();
459 ASSERT_EQ(FileWriterDelegate::ERROR_WRITE_STARTED
, result_
->write_status());
460 file_writer_delegate_
.reset();
462 EXPECT_EQ(pre_write_usage
+ allowed_growth
,
463 test_helper_
.GetCachedOriginUsage());
464 EXPECT_EQ(ComputeCurrentOriginUsage(), test_helper_
.GetCachedOriginUsage());
465 EXPECT_EQ(kOverlap
+ allowed_growth
, result_
->bytes_written());
466 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE
, result_
->status());
469 } // namespace fileapi