Only sync parent directory once after a leveldb file rename.
[chromium-blink-merge.git] / webkit / fileapi / file_writer_delegate_unittest.cc
blobd9bab7aee0fd4d98ff4e5fbfe1f08a65378d88c9
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 <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.h"
13 #include "googleurl/src/gurl.h"
14 #include "net/base/io_buffer.h"
15 #include "net/url_request/url_request.h"
16 #include "net/url_request/url_request_context.h"
17 #include "net/url_request/url_request_job.h"
18 #include "net/url_request/url_request_status.h"
19 #include "testing/platform_test.h"
20 #include "webkit/browser/fileapi/file_system_quota_util.h"
21 #include "webkit/browser/fileapi/sandbox_file_stream_writer.h"
22 #include "webkit/fileapi/file_system_context.h"
23 #include "webkit/fileapi/file_system_file_util.h"
24 #include "webkit/fileapi/file_system_operation_context.h"
25 #include "webkit/fileapi/file_writer_delegate.h"
26 #include "webkit/fileapi/local_file_system_operation.h"
27 #include "webkit/fileapi/mock_file_system_context.h"
29 namespace fileapi {
31 namespace {
33 const GURL kOrigin("http://example.com");
34 const FileSystemType kFileSystemType = kFileSystemTypeTest;
36 class Result {
37 public:
38 Result()
39 : status_(base::PLATFORM_FILE_OK),
40 bytes_written_(0),
41 write_status_(FileWriterDelegate::SUCCESS_IO_PENDING) {}
43 base::PlatformFileError status() const { return status_; }
44 int64 bytes_written() const { return bytes_written_; }
45 FileWriterDelegate::WriteProgressStatus write_status() const {
46 return write_status_;
49 void DidWrite(base::PlatformFileError status, int64 bytes,
50 FileWriterDelegate::WriteProgressStatus write_status) {
51 write_status_ = write_status;
52 if (status == base::PLATFORM_FILE_OK) {
53 bytes_written_ += bytes;
54 if (write_status_ != FileWriterDelegate::SUCCESS_IO_PENDING)
55 base::MessageLoop::current()->Quit();
56 } else {
57 EXPECT_EQ(base::PLATFORM_FILE_OK, status_);
58 status_ = status;
59 base::MessageLoop::current()->Quit();
63 private:
64 // For post-operation status.
65 base::PlatformFileError status_;
66 int64 bytes_written_;
67 FileWriterDelegate::WriteProgressStatus write_status_;
70 const char kData[] = "The quick brown fox jumps over the lazy dog.\n";
71 const int kDataSize = ARRAYSIZE_UNSAFE(kData) - 1;
73 } // namespace (anonymous)
75 class FileWriterDelegateTest : public PlatformTest {
76 public:
77 FileWriterDelegateTest()
78 : loop_(base::MessageLoop::TYPE_IO) {}
80 protected:
81 virtual void SetUp() OVERRIDE;
82 virtual void TearDown() OVERRIDE;
84 FileSystemFileUtil* file_util() {
85 return file_system_context_->GetFileUtil(kFileSystemType);
88 int64 usage() {
89 return file_system_context_->GetQuotaUtil(kFileSystemType)->
90 GetOriginUsageOnFileThread(file_system_context_,
91 kOrigin,
92 kFileSystemType);
95 int64 GetFileSizeOnDisk(const char* test_file_path) {
96 // There might be in-flight flush/write.
97 base::MessageLoop::current()->PostTask(
98 FROM_HERE, base::Bind(&base::DoNothing));
99 base::MessageLoop::current()->RunUntilIdle();
101 FileSystemURL url = GetFileSystemURL(test_file_path);
102 base::PlatformFileInfo file_info;
103 base::FilePath platform_path;
104 EXPECT_EQ(base::PLATFORM_FILE_OK,
105 file_util()->GetFileInfo(NewOperationContext().get(), url,
106 &file_info, &platform_path));
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 scoped_ptr<FileSystemOperationContext> NewOperationContext() {
116 FileSystemOperationContext* context =
117 new FileSystemOperationContext(file_system_context_);
118 context->set_update_observers(
119 *file_system_context_->GetUpdateObservers(kFileSystemType));
120 return make_scoped_ptr(context);
123 FileWriterDelegate* CreateWriterDelegate(
124 const char* test_file_path,
125 int64 offset,
126 int64 allowed_growth,
127 Result* result) {
128 SandboxFileStreamWriter* writer = new SandboxFileStreamWriter(
129 file_system_context_,
130 GetFileSystemURL(test_file_path),
131 offset,
132 *file_system_context_->GetUpdateObservers(kFileSystemType));
133 writer->set_default_quota(allowed_growth);
134 return new FileWriterDelegate(
135 base::Bind(&Result::DidWrite, base::Unretained(result)),
136 scoped_ptr<FileStreamWriter>(writer));
139 // Creates and sets up a FileWriterDelegate for writing the given |blob_url|,
140 // and creates a new FileWriterDelegate for the file.
141 void PrepareForWrite(const char* test_file_path,
142 const GURL& blob_url,
143 int64 offset,
144 int64 allowed_growth) {
145 result_.reset(new Result());
146 file_writer_delegate_.reset(
147 CreateWriterDelegate(test_file_path, offset, allowed_growth,
148 result_.get()));
149 request_.reset(empty_context_.CreateRequest(
150 blob_url, file_writer_delegate_.get()));
153 static net::URLRequest::ProtocolFactory Factory;
155 // This should be alive until the very end of this instance.
156 base::MessageLoop loop_;
158 scoped_refptr<FileSystemContext> file_system_context_;
160 net::URLRequestContext empty_context_;
161 scoped_ptr<FileWriterDelegate> file_writer_delegate_;
162 scoped_ptr<net::URLRequest> request_;
163 scoped_ptr<Result> result_;
165 base::ScopedTempDir dir_;
167 static const char* content_;
170 const char* FileWriterDelegateTest::content_ = NULL;
172 namespace {
174 static std::string g_content;
176 class FileWriterDelegateTestJob : public net::URLRequestJob {
177 public:
178 FileWriterDelegateTestJob(net::URLRequest* request,
179 net::NetworkDelegate* network_delegate,
180 const std::string& content)
181 : net::URLRequestJob(request, network_delegate),
182 content_(content),
183 remaining_bytes_(content.length()),
184 cursor_(0) {
187 virtual void Start() OVERRIDE {
188 base::MessageLoop::current()->PostTask(
189 FROM_HERE,
190 base::Bind(&FileWriterDelegateTestJob::NotifyHeadersComplete, this));
193 virtual bool ReadRawData(net::IOBuffer* buf,
194 int buf_size,
195 int *bytes_read) OVERRIDE {
196 if (remaining_bytes_ < buf_size)
197 buf_size = static_cast<int>(remaining_bytes_);
199 for (int i = 0; i < buf_size; ++i)
200 buf->data()[i] = content_[cursor_++];
201 remaining_bytes_ -= buf_size;
203 SetStatus(net::URLRequestStatus());
204 *bytes_read = buf_size;
205 return true;
208 virtual int GetResponseCode() const OVERRIDE {
209 return 200;
212 protected:
213 virtual ~FileWriterDelegateTestJob() {}
215 private:
216 std::string content_;
217 int remaining_bytes_;
218 int cursor_;
221 } // namespace (anonymous)
223 // static
224 net::URLRequestJob* FileWriterDelegateTest::Factory(
225 net::URLRequest* request,
226 net::NetworkDelegate* network_delegate,
227 const std::string& scheme) {
228 return new FileWriterDelegateTestJob(
229 request, network_delegate, FileWriterDelegateTest::content_);
232 void FileWriterDelegateTest::SetUp() {
233 ASSERT_TRUE(dir_.CreateUniqueTempDir());
235 file_system_context_ = CreateFileSystemContextForTesting(
236 NULL, dir_.path());
238 bool created = false;
239 scoped_ptr<FileSystemOperationContext> context = NewOperationContext();
240 context->set_allowed_bytes_growth(kint64max);
241 base::PlatformFileError error = file_util()->EnsureFileExists(
242 context.get(),
243 GetFileSystemURL("test"),
244 &created);
245 ASSERT_EQ(base::PLATFORM_FILE_OK, error);
246 ASSERT_TRUE(created);
247 net::URLRequest::Deprecated::RegisterProtocolFactory("blob", &Factory);
250 void FileWriterDelegateTest::TearDown() {
251 net::URLRequest::Deprecated::RegisterProtocolFactory("blob", NULL);
252 file_system_context_ = NULL;
253 base::MessageLoop::current()->RunUntilIdle();
256 TEST_F(FileWriterDelegateTest, WriteSuccessWithoutQuotaLimit) {
257 const GURL kBlobURL("blob:nolimit");
258 content_ = kData;
260 PrepareForWrite("test", kBlobURL, 0, kint64max);
262 ASSERT_EQ(0, usage());
263 file_writer_delegate_->Start(request_.Pass());
264 base::MessageLoop::current()->Run();
266 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result_->write_status());
267 file_writer_delegate_.reset();
269 ASSERT_EQ(kDataSize, usage());
270 EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
271 EXPECT_EQ(kDataSize, result_->bytes_written());
272 EXPECT_EQ(base::PLATFORM_FILE_OK, result_->status());
275 TEST_F(FileWriterDelegateTest, WriteSuccessWithJustQuota) {
276 const GURL kBlobURL("blob:just");
277 content_ = kData;
278 const int64 kAllowedGrowth = kDataSize;
279 PrepareForWrite("test", kBlobURL, 0, kAllowedGrowth);
281 ASSERT_EQ(0, usage());
282 file_writer_delegate_->Start(request_.Pass());
283 base::MessageLoop::current()->Run();
284 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result_->write_status());
285 file_writer_delegate_.reset();
287 ASSERT_EQ(kAllowedGrowth, usage());
288 EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
290 EXPECT_EQ(kAllowedGrowth, result_->bytes_written());
291 EXPECT_EQ(base::PLATFORM_FILE_OK, result_->status());
294 TEST_F(FileWriterDelegateTest, DISABLED_WriteFailureByQuota) {
295 const GURL kBlobURL("blob:failure");
296 content_ = kData;
297 const int64 kAllowedGrowth = kDataSize - 1;
298 PrepareForWrite("test", kBlobURL, 0, kAllowedGrowth);
300 ASSERT_EQ(0, usage());
301 file_writer_delegate_->Start(request_.Pass());
302 base::MessageLoop::current()->Run();
303 ASSERT_EQ(FileWriterDelegate::ERROR_WRITE_STARTED, result_->write_status());
304 file_writer_delegate_.reset();
306 ASSERT_EQ(kAllowedGrowth, usage());
307 EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
309 EXPECT_EQ(kAllowedGrowth, result_->bytes_written());
310 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE, result_->status());
311 ASSERT_EQ(FileWriterDelegate::ERROR_WRITE_STARTED, result_->write_status());
314 TEST_F(FileWriterDelegateTest, WriteZeroBytesSuccessfullyWithZeroQuota) {
315 const GURL kBlobURL("blob:zero");
316 content_ = "";
317 int64 kAllowedGrowth = 0;
318 PrepareForWrite("test", kBlobURL, 0, kAllowedGrowth);
320 ASSERT_EQ(0, usage());
321 file_writer_delegate_->Start(request_.Pass());
322 base::MessageLoop::current()->Run();
323 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result_->write_status());
324 file_writer_delegate_.reset();
326 ASSERT_EQ(kAllowedGrowth, usage());
327 EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
329 EXPECT_EQ(kAllowedGrowth, result_->bytes_written());
330 EXPECT_EQ(base::PLATFORM_FILE_OK, result_->status());
331 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result_->write_status());
334 TEST_F(FileWriterDelegateTest, WriteSuccessWithoutQuotaLimitConcurrent) {
335 scoped_ptr<FileWriterDelegate> file_writer_delegate2;
336 scoped_ptr<net::URLRequest> request2;
337 scoped_ptr<Result> result2;
339 bool created = false;
340 file_util()->EnsureFileExists(NewOperationContext().get(),
341 GetFileSystemURL("test2"),
342 &created);
343 ASSERT_TRUE(created);
345 const GURL kBlobURL("blob:nolimitconcurrent");
346 const GURL kBlobURL2("blob:nolimitconcurrent2");
347 content_ = kData;
349 PrepareForWrite("test", kBlobURL, 0, kint64max);
351 // Credate another FileWriterDelegate for concurrent write.
352 result2.reset(new Result());
353 file_writer_delegate2.reset(CreateWriterDelegate(
354 "test2", 0, kint64max, result2.get()));
355 request2.reset(empty_context_.CreateRequest(
356 kBlobURL2, file_writer_delegate2.get()));
358 ASSERT_EQ(0, usage());
359 file_writer_delegate_->Start(request_.Pass());
360 file_writer_delegate2->Start(request2.Pass());
361 base::MessageLoop::current()->Run();
362 if (result_->write_status() == FileWriterDelegate::SUCCESS_IO_PENDING ||
363 result2->write_status() == FileWriterDelegate::SUCCESS_IO_PENDING)
364 base::MessageLoop::current()->Run();
366 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result_->write_status());
367 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result2->write_status());
368 file_writer_delegate_.reset();
369 file_writer_delegate2.reset();
371 ASSERT_EQ(kDataSize * 2, usage());
372 EXPECT_EQ(GetFileSizeOnDisk("test") + GetFileSizeOnDisk("test2"), usage());
374 EXPECT_EQ(kDataSize, result_->bytes_written());
375 EXPECT_EQ(base::PLATFORM_FILE_OK, result_->status());
376 EXPECT_EQ(kDataSize, result2->bytes_written());
377 EXPECT_EQ(base::PLATFORM_FILE_OK, result2->status());
380 TEST_F(FileWriterDelegateTest, WritesWithQuotaAndOffset) {
381 const GURL kBlobURL("blob:failure-with-updated-quota");
382 content_ = kData;
384 // Writing kDataSize (=45) bytes data while allowed_growth is 100.
385 int64 offset = 0;
386 int64 allowed_growth = 100;
387 ASSERT_LT(kDataSize, allowed_growth);
388 PrepareForWrite("test", kBlobURL, offset, allowed_growth);
390 ASSERT_EQ(0, usage());
391 file_writer_delegate_->Start(request_.Pass());
392 base::MessageLoop::current()->Run();
393 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result_->write_status());
394 file_writer_delegate_.reset();
396 ASSERT_EQ(kDataSize, usage());
397 EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
398 EXPECT_EQ(kDataSize, result_->bytes_written());
399 EXPECT_EQ(base::PLATFORM_FILE_OK, result_->status());
401 // Trying to overwrite kDataSize bytes data while allowed_growth is 20.
402 offset = 0;
403 allowed_growth = 20;
404 PrepareForWrite("test", kBlobURL, offset, allowed_growth);
406 file_writer_delegate_->Start(request_.Pass());
407 base::MessageLoop::current()->Run();
408 EXPECT_EQ(kDataSize, usage());
409 EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
410 EXPECT_EQ(kDataSize, result_->bytes_written());
411 EXPECT_EQ(base::PLATFORM_FILE_OK, result_->status());
412 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result_->write_status());
414 // Trying to write kDataSize bytes data from offset 25 while
415 // allowed_growth is 55.
416 offset = 25;
417 allowed_growth = 55;
418 PrepareForWrite("test", kBlobURL, offset, allowed_growth);
420 file_writer_delegate_->Start(request_.Pass());
421 base::MessageLoop::current()->Run();
422 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result_->write_status());
423 file_writer_delegate_.reset();
425 EXPECT_EQ(offset + kDataSize, usage());
426 EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
427 EXPECT_EQ(kDataSize, result_->bytes_written());
428 EXPECT_EQ(base::PLATFORM_FILE_OK, result_->status());
430 // Trying to overwrite 45 bytes data while allowed_growth is -20.
431 offset = 0;
432 allowed_growth = -20;
433 PrepareForWrite("test", kBlobURL, offset, allowed_growth);
435 int64 pre_write_usage = GetFileSizeOnDisk("test");
436 file_writer_delegate_->Start(request_.Pass());
437 base::MessageLoop::current()->Run();
438 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result_->write_status());
439 file_writer_delegate_.reset();
441 EXPECT_EQ(pre_write_usage, usage());
442 EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
443 EXPECT_EQ(kDataSize, result_->bytes_written());
444 EXPECT_EQ(base::PLATFORM_FILE_OK, result_->status());
446 // Trying to overwrite 45 bytes data with offset pre_write_usage - 20,
447 // while allowed_growth is 10.
448 const int kOverlap = 20;
449 offset = pre_write_usage - kOverlap;
450 allowed_growth = 10;
451 PrepareForWrite("test", kBlobURL, offset, allowed_growth);
453 file_writer_delegate_->Start(request_.Pass());
454 base::MessageLoop::current()->Run();
455 ASSERT_EQ(FileWriterDelegate::ERROR_WRITE_STARTED, result_->write_status());
456 file_writer_delegate_.reset();
458 EXPECT_EQ(pre_write_usage + allowed_growth,
459 usage());
460 EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
461 EXPECT_EQ(kOverlap + allowed_growth, result_->bytes_written());
462 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE, result_->status());
465 } // namespace fileapi