Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / browser / fileapi / file_writer_delegate_unittest.cc
blob25293e0b5ffaad5c5e7812fb149607aa6f5ca69a
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.
5 #include <string>
6 #include <vector>
8 #include "base/basictypes.h"
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/run_loop.h"
14 #include "content/public/test/async_file_test_helper.h"
15 #include "content/public/test/test_file_system_context.h"
16 #include "net/base/io_buffer.h"
17 #include "net/base/request_priority.h"
18 #include "net/url_request/url_request.h"
19 #include "net/url_request/url_request_context.h"
20 #include "net/url_request/url_request_job.h"
21 #include "net/url_request/url_request_job_factory.h"
22 #include "net/url_request/url_request_status.h"
23 #include "testing/platform_test.h"
24 #include "url/gurl.h"
25 #include "webkit/browser/fileapi/file_system_context.h"
26 #include "webkit/browser/fileapi/file_system_quota_util.h"
27 #include "webkit/browser/fileapi/file_writer_delegate.h"
28 #include "webkit/browser/fileapi/sandbox_file_stream_writer.h"
30 using content::AsyncFileTestHelper;
31 using storage::FileSystemURL;
32 using storage::FileWriterDelegate;
34 namespace content {
36 namespace {
38 const GURL kOrigin("http://example.com");
39 const storage::FileSystemType kFileSystemType = storage::kFileSystemTypeTest;
41 const char kData[] = "The quick brown fox jumps over the lazy dog.\n";
42 const int kDataSize = ARRAYSIZE_UNSAFE(kData) - 1;
44 class Result {
45 public:
46 Result()
47 : status_(base::File::FILE_OK),
48 bytes_written_(0),
49 write_status_(FileWriterDelegate::SUCCESS_IO_PENDING) {}
51 base::File::Error status() const { return status_; }
52 int64 bytes_written() const { return bytes_written_; }
53 FileWriterDelegate::WriteProgressStatus write_status() const {
54 return write_status_;
57 void DidWrite(base::File::Error status, int64 bytes,
58 FileWriterDelegate::WriteProgressStatus write_status) {
59 write_status_ = write_status;
60 if (status == base::File::FILE_OK) {
61 bytes_written_ += bytes;
62 if (write_status_ != FileWriterDelegate::SUCCESS_IO_PENDING)
63 base::MessageLoop::current()->Quit();
64 } else {
65 EXPECT_EQ(base::File::FILE_OK, status_);
66 status_ = status;
67 base::MessageLoop::current()->Quit();
71 private:
72 // For post-operation status.
73 base::File::Error status_;
74 int64 bytes_written_;
75 FileWriterDelegate::WriteProgressStatus write_status_;
78 class BlobURLRequestJobFactory;
80 } // namespace (anonymous)
82 class FileWriterDelegateTest : public PlatformTest {
83 public:
84 FileWriterDelegateTest() {}
86 protected:
87 virtual void SetUp() OVERRIDE;
88 virtual void TearDown() OVERRIDE;
90 int64 usage() {
91 return file_system_context_->GetQuotaUtil(kFileSystemType)
92 ->GetOriginUsageOnFileTaskRunner(
93 file_system_context_.get(), kOrigin, kFileSystemType);
96 int64 GetFileSizeOnDisk(const char* test_file_path) {
97 // There might be in-flight flush/write.
98 base::MessageLoop::current()->PostTask(
99 FROM_HERE, base::Bind(&base::DoNothing));
100 base::RunLoop().RunUntilIdle();
102 FileSystemURL url = GetFileSystemURL(test_file_path);
103 base::File::Info file_info;
104 EXPECT_EQ(base::File::FILE_OK,
105 AsyncFileTestHelper::GetMetadata(
106 file_system_context_.get(), url, &file_info));
107 return file_info.size;
110 FileSystemURL GetFileSystemURL(const char* file_name) const {
111 return file_system_context_->CreateCrackedFileSystemURL(
112 kOrigin, kFileSystemType, base::FilePath().FromUTF8Unsafe(file_name));
115 FileWriterDelegate* CreateWriterDelegate(
116 const char* test_file_path,
117 int64 offset,
118 int64 allowed_growth) {
119 storage::SandboxFileStreamWriter* writer =
120 new storage::SandboxFileStreamWriter(
121 file_system_context_.get(),
122 GetFileSystemURL(test_file_path),
123 offset,
124 *file_system_context_->GetUpdateObservers(kFileSystemType));
125 writer->set_default_quota(allowed_growth);
126 return new FileWriterDelegate(scoped_ptr<storage::FileStreamWriter>(writer),
127 FileWriterDelegate::FLUSH_ON_COMPLETION);
130 FileWriterDelegate::DelegateWriteCallback GetWriteCallback(Result* result) {
131 return base::Bind(&Result::DidWrite, base::Unretained(result));
134 // Creates and sets up a FileWriterDelegate for writing the given |blob_url|,
135 // and creates a new FileWriterDelegate for the file.
136 void PrepareForWrite(const char* test_file_path,
137 const GURL& blob_url,
138 int64 offset,
139 int64 allowed_growth) {
140 file_writer_delegate_.reset(
141 CreateWriterDelegate(test_file_path, offset, allowed_growth));
142 request_ = empty_context_.CreateRequest(
143 blob_url, net::DEFAULT_PRIORITY, file_writer_delegate_.get(), NULL);
146 // This should be alive until the very end of this instance.
147 base::MessageLoopForIO loop_;
149 scoped_refptr<storage::FileSystemContext> file_system_context_;
151 net::URLRequestContext empty_context_;
152 scoped_ptr<FileWriterDelegate> file_writer_delegate_;
153 scoped_ptr<net::URLRequest> request_;
154 scoped_ptr<BlobURLRequestJobFactory> job_factory_;
156 base::ScopedTempDir dir_;
158 static const char* content_;
161 const char* FileWriterDelegateTest::content_ = NULL;
163 namespace {
165 static std::string g_content;
167 class FileWriterDelegateTestJob : public net::URLRequestJob {
168 public:
169 FileWriterDelegateTestJob(net::URLRequest* request,
170 net::NetworkDelegate* network_delegate,
171 const std::string& content)
172 : net::URLRequestJob(request, network_delegate),
173 content_(content),
174 remaining_bytes_(content.length()),
175 cursor_(0) {
178 virtual void Start() OVERRIDE {
179 base::MessageLoop::current()->PostTask(
180 FROM_HERE,
181 base::Bind(&FileWriterDelegateTestJob::NotifyHeadersComplete, this));
184 virtual bool ReadRawData(net::IOBuffer* buf,
185 int buf_size,
186 int *bytes_read) OVERRIDE {
187 if (remaining_bytes_ < buf_size)
188 buf_size = static_cast<int>(remaining_bytes_);
190 for (int i = 0; i < buf_size; ++i)
191 buf->data()[i] = content_[cursor_++];
192 remaining_bytes_ -= buf_size;
194 SetStatus(net::URLRequestStatus());
195 *bytes_read = buf_size;
196 return true;
199 virtual int GetResponseCode() const OVERRIDE {
200 return 200;
203 protected:
204 virtual ~FileWriterDelegateTestJob() {}
206 private:
207 std::string content_;
208 int remaining_bytes_;
209 int cursor_;
212 class BlobURLRequestJobFactory : public net::URLRequestJobFactory {
213 public:
214 explicit BlobURLRequestJobFactory(const char** content_data)
215 : content_data_(content_data) {
218 virtual net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
219 const std::string& scheme,
220 net::URLRequest* request,
221 net::NetworkDelegate* network_delegate) const OVERRIDE {
222 return new FileWriterDelegateTestJob(
223 request, network_delegate, *content_data_);
226 virtual bool IsHandledProtocol(const std::string& scheme) const OVERRIDE {
227 return scheme == "blob";
230 virtual bool IsHandledURL(const GURL& url) const OVERRIDE {
231 return url.SchemeIs("blob");
234 virtual bool IsSafeRedirectTarget(const GURL& location) const OVERRIDE {
235 return true;
238 private:
239 const char** content_data_;
241 DISALLOW_COPY_AND_ASSIGN(BlobURLRequestJobFactory);
244 } // namespace (anonymous)
246 void FileWriterDelegateTest::SetUp() {
247 ASSERT_TRUE(dir_.CreateUniqueTempDir());
249 file_system_context_ = CreateFileSystemContextForTesting(
250 NULL, dir_.path());
251 ASSERT_EQ(base::File::FILE_OK,
252 AsyncFileTestHelper::CreateFile(file_system_context_.get(),
253 GetFileSystemURL("test")));
254 job_factory_.reset(new BlobURLRequestJobFactory(&content_));
255 empty_context_.set_job_factory(job_factory_.get());
258 void FileWriterDelegateTest::TearDown() {
259 file_system_context_ = NULL;
260 base::RunLoop().RunUntilIdle();
263 TEST_F(FileWriterDelegateTest, WriteSuccessWithoutQuotaLimit) {
264 const GURL kBlobURL("blob:nolimit");
265 content_ = kData;
267 PrepareForWrite("test", kBlobURL, 0, kint64max);
269 Result result;
270 ASSERT_EQ(0, usage());
271 file_writer_delegate_->Start(request_.Pass(), GetWriteCallback(&result));
272 base::MessageLoop::current()->Run();
274 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result.write_status());
275 file_writer_delegate_.reset();
277 ASSERT_EQ(kDataSize, usage());
278 EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
279 EXPECT_EQ(kDataSize, result.bytes_written());
280 EXPECT_EQ(base::File::FILE_OK, result.status());
283 TEST_F(FileWriterDelegateTest, WriteSuccessWithJustQuota) {
284 const GURL kBlobURL("blob:just");
285 content_ = kData;
286 const int64 kAllowedGrowth = kDataSize;
287 PrepareForWrite("test", kBlobURL, 0, kAllowedGrowth);
289 Result result;
290 ASSERT_EQ(0, usage());
291 file_writer_delegate_->Start(request_.Pass(), GetWriteCallback(&result));
292 base::MessageLoop::current()->Run();
293 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result.write_status());
294 file_writer_delegate_.reset();
296 ASSERT_EQ(kAllowedGrowth, usage());
297 EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
299 EXPECT_EQ(kAllowedGrowth, result.bytes_written());
300 EXPECT_EQ(base::File::FILE_OK, result.status());
303 TEST_F(FileWriterDelegateTest, DISABLED_WriteFailureByQuota) {
304 const GURL kBlobURL("blob:failure");
305 content_ = kData;
306 const int64 kAllowedGrowth = kDataSize - 1;
307 PrepareForWrite("test", kBlobURL, 0, kAllowedGrowth);
309 Result result;
310 ASSERT_EQ(0, usage());
311 file_writer_delegate_->Start(request_.Pass(), GetWriteCallback(&result));
312 base::MessageLoop::current()->Run();
313 ASSERT_EQ(FileWriterDelegate::ERROR_WRITE_STARTED, result.write_status());
314 file_writer_delegate_.reset();
316 ASSERT_EQ(kAllowedGrowth, usage());
317 EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
319 EXPECT_EQ(kAllowedGrowth, result.bytes_written());
320 EXPECT_EQ(base::File::FILE_ERROR_NO_SPACE, result.status());
321 ASSERT_EQ(FileWriterDelegate::ERROR_WRITE_STARTED, result.write_status());
324 TEST_F(FileWriterDelegateTest, WriteZeroBytesSuccessfullyWithZeroQuota) {
325 const GURL kBlobURL("blob:zero");
326 content_ = "";
327 int64 kAllowedGrowth = 0;
328 PrepareForWrite("test", kBlobURL, 0, kAllowedGrowth);
330 Result result;
331 ASSERT_EQ(0, usage());
332 file_writer_delegate_->Start(request_.Pass(), GetWriteCallback(&result));
333 base::MessageLoop::current()->Run();
334 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result.write_status());
335 file_writer_delegate_.reset();
337 ASSERT_EQ(kAllowedGrowth, usage());
338 EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
340 EXPECT_EQ(kAllowedGrowth, result.bytes_written());
341 EXPECT_EQ(base::File::FILE_OK, result.status());
342 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result.write_status());
345 TEST_F(FileWriterDelegateTest, WriteSuccessWithoutQuotaLimitConcurrent) {
346 scoped_ptr<FileWriterDelegate> file_writer_delegate2;
347 scoped_ptr<net::URLRequest> request2;
349 ASSERT_EQ(base::File::FILE_OK,
350 AsyncFileTestHelper::CreateFile(file_system_context_.get(),
351 GetFileSystemURL("test2")));
353 const GURL kBlobURL("blob:nolimitconcurrent");
354 const GURL kBlobURL2("blob:nolimitconcurrent2");
355 content_ = kData;
357 PrepareForWrite("test", kBlobURL, 0, kint64max);
359 // Credate another FileWriterDelegate for concurrent write.
360 file_writer_delegate2.reset(CreateWriterDelegate("test2", 0, kint64max));
361 request2 = empty_context_.CreateRequest(
362 kBlobURL2, net::DEFAULT_PRIORITY, file_writer_delegate2.get(), NULL);
364 Result result, result2;
365 ASSERT_EQ(0, usage());
366 file_writer_delegate_->Start(request_.Pass(), GetWriteCallback(&result));
367 file_writer_delegate2->Start(request2.Pass(), GetWriteCallback(&result2));
368 base::MessageLoop::current()->Run();
369 if (result.write_status() == FileWriterDelegate::SUCCESS_IO_PENDING ||
370 result2.write_status() == FileWriterDelegate::SUCCESS_IO_PENDING)
371 base::MessageLoop::current()->Run();
373 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result.write_status());
374 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result2.write_status());
375 file_writer_delegate_.reset();
376 file_writer_delegate2.reset();
378 ASSERT_EQ(kDataSize * 2, usage());
379 EXPECT_EQ(GetFileSizeOnDisk("test") + GetFileSizeOnDisk("test2"), usage());
381 EXPECT_EQ(kDataSize, result.bytes_written());
382 EXPECT_EQ(base::File::FILE_OK, result.status());
383 EXPECT_EQ(kDataSize, result2.bytes_written());
384 EXPECT_EQ(base::File::FILE_OK, result2.status());
387 TEST_F(FileWriterDelegateTest, WritesWithQuotaAndOffset) {
388 const GURL kBlobURL("blob:failure-with-updated-quota");
389 content_ = kData;
391 // Writing kDataSize (=45) bytes data while allowed_growth is 100.
392 int64 offset = 0;
393 int64 allowed_growth = 100;
394 ASSERT_LT(kDataSize, allowed_growth);
395 PrepareForWrite("test", kBlobURL, offset, allowed_growth);
398 Result result;
399 ASSERT_EQ(0, usage());
400 file_writer_delegate_->Start(request_.Pass(), GetWriteCallback(&result));
401 base::MessageLoop::current()->Run();
402 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result.write_status());
403 file_writer_delegate_.reset();
405 ASSERT_EQ(kDataSize, usage());
406 EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
407 EXPECT_EQ(kDataSize, result.bytes_written());
408 EXPECT_EQ(base::File::FILE_OK, result.status());
411 // Trying to overwrite kDataSize bytes data while allowed_growth is 20.
412 offset = 0;
413 allowed_growth = 20;
414 PrepareForWrite("test", kBlobURL, offset, allowed_growth);
417 Result result;
418 file_writer_delegate_->Start(request_.Pass(), GetWriteCallback(&result));
419 base::MessageLoop::current()->Run();
420 EXPECT_EQ(kDataSize, usage());
421 EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
422 EXPECT_EQ(kDataSize, result.bytes_written());
423 EXPECT_EQ(base::File::FILE_OK, result.status());
424 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result.write_status());
427 // Trying to write kDataSize bytes data from offset 25 while
428 // allowed_growth is 55.
429 offset = 25;
430 allowed_growth = 55;
431 PrepareForWrite("test", kBlobURL, offset, allowed_growth);
434 Result result;
435 file_writer_delegate_->Start(request_.Pass(), GetWriteCallback(&result));
436 base::MessageLoop::current()->Run();
437 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result.write_status());
438 file_writer_delegate_.reset();
440 EXPECT_EQ(offset + kDataSize, usage());
441 EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
442 EXPECT_EQ(kDataSize, result.bytes_written());
443 EXPECT_EQ(base::File::FILE_OK, result.status());
446 // Trying to overwrite 45 bytes data while allowed_growth is -20.
447 offset = 0;
448 allowed_growth = -20;
449 PrepareForWrite("test", kBlobURL, offset, allowed_growth);
450 int64 pre_write_usage = GetFileSizeOnDisk("test");
453 Result result;
454 file_writer_delegate_->Start(request_.Pass(), GetWriteCallback(&result));
455 base::MessageLoop::current()->Run();
456 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result.write_status());
457 file_writer_delegate_.reset();
459 EXPECT_EQ(pre_write_usage, usage());
460 EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
461 EXPECT_EQ(kDataSize, result.bytes_written());
462 EXPECT_EQ(base::File::FILE_OK, result.status());
465 // Trying to overwrite 45 bytes data with offset pre_write_usage - 20,
466 // while allowed_growth is 10.
467 const int kOverlap = 20;
468 offset = pre_write_usage - kOverlap;
469 allowed_growth = 10;
470 PrepareForWrite("test", kBlobURL, offset, allowed_growth);
473 Result result;
474 file_writer_delegate_->Start(request_.Pass(), GetWriteCallback(&result));
475 base::MessageLoop::current()->Run();
476 ASSERT_EQ(FileWriterDelegate::ERROR_WRITE_STARTED, result.write_status());
477 file_writer_delegate_.reset();
479 EXPECT_EQ(pre_write_usage + allowed_growth, usage());
480 EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
481 EXPECT_EQ(kOverlap + allowed_growth, result.bytes_written());
482 EXPECT_EQ(base::File::FILE_ERROR_NO_SPACE, result.status());
486 } // namespace content