Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / content / browser / fileapi / file_writer_delegate_unittest.cc
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 <string>
6 #include <vector>
7
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 "storage/browser/fileapi/file_system_context.h"
24 #include "storage/browser/fileapi/file_system_quota_util.h"
25 #include "storage/browser/fileapi/file_writer_delegate.h"
26 #include "storage/browser/fileapi/sandbox_file_stream_writer.h"
27 #include "testing/platform_test.h"
28 #include "url/gurl.h"
29
30 using content::AsyncFileTestHelper;
31 using storage::FileSystemURL;
32 using storage::FileWriterDelegate;
33
34 namespace content {
35
36 namespace {
37
38 const GURL kOrigin("http://example.com");
39 const storage::FileSystemType kFileSystemType = storage::kFileSystemTypeTest;
40
41 const char kData[] = "The quick brown fox jumps over the lazy dog.\n";
42 const int kDataSize = ARRAYSIZE_UNSAFE(kData) - 1;
43
44 class Result {
45  public:
46   Result()
47       : status_(base::File::FILE_OK),
48         bytes_written_(0),
49         write_status_(FileWriterDelegate::SUCCESS_IO_PENDING) {}
50
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_;
55   }
56
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();
68     }
69   }
70
71  private:
72   // For post-operation status.
73   base::File::Error status_;
74   int64 bytes_written_;
75   FileWriterDelegate::WriteProgressStatus write_status_;
76 };
77
78 class BlobURLRequestJobFactory;
79
80 }  // namespace (anonymous)
81
82 class FileWriterDelegateTest : public PlatformTest {
83  public:
84   FileWriterDelegateTest() {}
85
86  protected:
87   virtual void SetUp() OVERRIDE;
88   virtual void TearDown() OVERRIDE;
89
90   int64 usage() {
91     return file_system_context_->GetQuotaUtil(kFileSystemType)
92         ->GetOriginUsageOnFileTaskRunner(
93               file_system_context_.get(), kOrigin, kFileSystemType);
94   }
95
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();
101
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;
108   }
109
110   FileSystemURL GetFileSystemURL(const char* file_name) const {
111     return file_system_context_->CreateCrackedFileSystemURL(
112         kOrigin, kFileSystemType, base::FilePath().FromUTF8Unsafe(file_name));
113   }
114
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);
128   }
129
130   FileWriterDelegate::DelegateWriteCallback GetWriteCallback(Result* result) {
131     return base::Bind(&Result::DidWrite, base::Unretained(result));
132   }
133
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);
144   }
145
146   // This should be alive until the very end of this instance.
147   base::MessageLoopForIO loop_;
148
149   scoped_refptr<storage::FileSystemContext> file_system_context_;
150
151   net::URLRequestContext empty_context_;
152   scoped_ptr<FileWriterDelegate> file_writer_delegate_;
153   scoped_ptr<net::URLRequest> request_;
154   scoped_ptr<BlobURLRequestJobFactory> job_factory_;
155
156   base::ScopedTempDir dir_;
157
158   static const char* content_;
159 };
160
161 const char* FileWriterDelegateTest::content_ = NULL;
162
163 namespace {
164
165 static std::string g_content;
166
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) {
176   }
177
178   virtual void Start() OVERRIDE {
179     base::MessageLoop::current()->PostTask(
180         FROM_HERE,
181         base::Bind(&FileWriterDelegateTestJob::NotifyHeadersComplete, this));
182   }
183
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_);
189
190     for (int i = 0; i < buf_size; ++i)
191       buf->data()[i] = content_[cursor_++];
192     remaining_bytes_ -= buf_size;
193
194     SetStatus(net::URLRequestStatus());
195     *bytes_read = buf_size;
196     return true;
197   }
198
199   virtual int GetResponseCode() const OVERRIDE {
200     return 200;
201   }
202
203  protected:
204   virtual ~FileWriterDelegateTestJob() {}
205
206  private:
207   std::string content_;
208   int remaining_bytes_;
209   int cursor_;
210 };
211
212 class BlobURLRequestJobFactory : public net::URLRequestJobFactory {
213  public:
214   explicit BlobURLRequestJobFactory(const char** content_data)
215       : content_data_(content_data) {
216   }
217
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_);
224   }
225
226   virtual bool IsHandledProtocol(const std::string& scheme) const OVERRIDE {
227     return scheme == "blob";
228   }
229
230   virtual bool IsHandledURL(const GURL& url) const OVERRIDE {
231     return url.SchemeIs("blob");
232   }
233
234   virtual bool IsSafeRedirectTarget(const GURL& location) const OVERRIDE {
235     return true;
236   }
237
238  private:
239   const char** content_data_;
240
241   DISALLOW_COPY_AND_ASSIGN(BlobURLRequestJobFactory);
242 };
243
244 }  // namespace (anonymous)
245
246 void FileWriterDelegateTest::SetUp() {
247   ASSERT_TRUE(dir_.CreateUniqueTempDir());
248
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());
256 }
257
258 void FileWriterDelegateTest::TearDown() {
259   file_system_context_ = NULL;
260   base::RunLoop().RunUntilIdle();
261 }
262
263 TEST_F(FileWriterDelegateTest, WriteSuccessWithoutQuotaLimit) {
264   const GURL kBlobURL("blob:nolimit");
265   content_ = kData;
266
267   PrepareForWrite("test", kBlobURL, 0, kint64max);
268
269   Result result;
270   ASSERT_EQ(0, usage());
271   file_writer_delegate_->Start(request_.Pass(), GetWriteCallback(&result));
272   base::MessageLoop::current()->Run();
273
274   ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result.write_status());
275   file_writer_delegate_.reset();
276
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());
281 }
282
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);
288
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();
295
296   ASSERT_EQ(kAllowedGrowth, usage());
297   EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
298
299   EXPECT_EQ(kAllowedGrowth, result.bytes_written());
300   EXPECT_EQ(base::File::FILE_OK, result.status());
301 }
302
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);
308
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();
315
316   ASSERT_EQ(kAllowedGrowth, usage());
317   EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
318
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());
322 }
323
324 TEST_F(FileWriterDelegateTest, WriteZeroBytesSuccessfullyWithZeroQuota) {
325   const GURL kBlobURL("blob:zero");
326   content_ = "";
327   int64 kAllowedGrowth = 0;
328   PrepareForWrite("test", kBlobURL, 0, kAllowedGrowth);
329
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();
336
337   ASSERT_EQ(kAllowedGrowth, usage());
338   EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
339
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());
343 }
344
345 TEST_F(FileWriterDelegateTest, WriteSuccessWithoutQuotaLimitConcurrent) {
346   scoped_ptr<FileWriterDelegate> file_writer_delegate2;
347   scoped_ptr<net::URLRequest> request2;
348
349   ASSERT_EQ(base::File::FILE_OK,
350             AsyncFileTestHelper::CreateFile(file_system_context_.get(),
351                                             GetFileSystemURL("test2")));
352
353   const GURL kBlobURL("blob:nolimitconcurrent");
354   const GURL kBlobURL2("blob:nolimitconcurrent2");
355   content_ = kData;
356
357   PrepareForWrite("test", kBlobURL, 0, kint64max);
358
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);
363
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();
372
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();
377
378   ASSERT_EQ(kDataSize * 2, usage());
379   EXPECT_EQ(GetFileSizeOnDisk("test") + GetFileSizeOnDisk("test2"), usage());
380
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());
385 }
386
387 TEST_F(FileWriterDelegateTest, WritesWithQuotaAndOffset) {
388   const GURL kBlobURL("blob:failure-with-updated-quota");
389   content_ = kData;
390
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);
396
397   {
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();
404
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());
409   }
410
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);
415
416   {
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());
425   }
426
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);
432
433   {
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();
439
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());
444   }
445
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");
451
452   {
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();
458
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());
463   }
464
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);
471
472   {
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();
478
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());
483   }
484 }
485
486 }  // namespace content