Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / content / browser / fileapi / obfuscated_file_util_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 <set>
6 #include <string>
7 #include <vector>
8
9 #include "base/bind.h"
10 #include "base/files/file.h"
11 #include "base/files/file_path.h"
12 #include "base/files/file_util.h"
13 #include "base/files/scoped_temp_dir.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/run_loop.h"
16 #include "content/browser/fileapi/mock_file_change_observer.h"
17 #include "content/public/test/async_file_test_helper.h"
18 #include "content/public/test/mock_special_storage_policy.h"
19 #include "content/public/test/sandbox_file_system_test_helper.h"
20 #include "content/public/test/test_file_system_context.h"
21 #include "content/test/fileapi_test_file_set.h"
22 #include "storage/browser/fileapi/external_mount_points.h"
23 #include "storage/browser/fileapi/file_system_backend.h"
24 #include "storage/browser/fileapi/file_system_context.h"
25 #include "storage/browser/fileapi/file_system_operation_context.h"
26 #include "storage/browser/fileapi/file_system_usage_cache.h"
27 #include "storage/browser/fileapi/obfuscated_file_util.h"
28 #include "storage/browser/fileapi/sandbox_directory_database.h"
29 #include "storage/browser/fileapi/sandbox_file_system_backend_delegate.h"
30 #include "storage/browser/fileapi/sandbox_isolated_origin_database.h"
31 #include "storage/browser/fileapi/sandbox_origin_database.h"
32 #include "storage/browser/quota/quota_manager.h"
33 #include "storage/common/database/database_identifier.h"
34 #include "storage/common/quota/quota_types.h"
35 #include "testing/gtest/include/gtest/gtest.h"
36
37 using content::AsyncFileTestHelper;
38 using storage::FileSystemContext;
39 using storage::FileSystemOperation;
40 using storage::FileSystemOperationContext;
41 using storage::FileSystemURL;
42 using storage::ObfuscatedFileUtil;
43 using storage::SandboxDirectoryDatabase;
44 using storage::SandboxIsolatedOriginDatabase;
45 using storage::kFileSystemTypeTemporary;
46 using storage::kFileSystemTypePersistent;
47
48 namespace content {
49
50 namespace {
51
52 bool FileExists(const base::FilePath& path) {
53   return base::PathExists(path) && !base::DirectoryExists(path);
54 }
55
56 int64 GetSize(const base::FilePath& path) {
57   int64 size;
58   EXPECT_TRUE(base::GetFileSize(path, &size));
59   return size;
60 }
61
62 // After a move, the dest exists and the source doesn't.
63 // After a copy, both source and dest exist.
64 struct CopyMoveTestCaseRecord {
65   bool is_copy_not_move;
66   const char source_path[64];
67   const char dest_path[64];
68   bool cause_overwrite;
69 };
70
71 const CopyMoveTestCaseRecord kCopyMoveTestCases[] = {
72   // This is the combinatoric set of:
73   //  rename vs. same-name
74   //  different directory vs. same directory
75   //  overwrite vs. no-overwrite
76   //  copy vs. move
77   //  We can never be called with source and destination paths identical, so
78   //  those cases are omitted.
79   {true, "dir0/file0", "dir0/file1", false},
80   {false, "dir0/file0", "dir0/file1", false},
81   {true, "dir0/file0", "dir0/file1", true},
82   {false, "dir0/file0", "dir0/file1", true},
83
84   {true, "dir0/file0", "dir1/file0", false},
85   {false, "dir0/file0", "dir1/file0", false},
86   {true, "dir0/file0", "dir1/file0", true},
87   {false, "dir0/file0", "dir1/file0", true},
88   {true, "dir0/file0", "dir1/file1", false},
89   {false, "dir0/file0", "dir1/file1", false},
90   {true, "dir0/file0", "dir1/file1", true},
91   {false, "dir0/file0", "dir1/file1", true},
92 };
93
94 struct OriginEnumerationTestRecord {
95   std::string origin_url;
96   bool has_temporary;
97   bool has_persistent;
98 };
99
100 const OriginEnumerationTestRecord kOriginEnumerationTestRecords[] = {
101   {"http://example.com", false, true},
102   {"http://example1.com", true, false},
103   {"https://example1.com", true, true},
104   {"file://", false, true},
105   {"http://example.com:8000", false, true},
106 };
107
108 FileSystemURL FileSystemURLAppend(
109     const FileSystemURL& url, const base::FilePath::StringType& child) {
110   return FileSystemURL::CreateForTest(
111       url.origin(), url.mount_type(), url.virtual_path().Append(child));
112 }
113
114 FileSystemURL FileSystemURLAppendUTF8(
115     const FileSystemURL& url, const std::string& child) {
116   return FileSystemURL::CreateForTest(
117       url.origin(),
118       url.mount_type(),
119       url.virtual_path().Append(base::FilePath::FromUTF8Unsafe(child)));
120 }
121
122 FileSystemURL FileSystemURLDirName(const FileSystemURL& url) {
123   return FileSystemURL::CreateForTest(
124       url.origin(),
125       url.mount_type(),
126       storage::VirtualPath::DirName(url.virtual_path()));
127 }
128
129 std::string GetTypeString(storage::FileSystemType type) {
130   return storage::SandboxFileSystemBackendDelegate::GetTypeString(type);
131 }
132
133 bool HasFileSystemType(ObfuscatedFileUtil::AbstractOriginEnumerator* enumerator,
134                        storage::FileSystemType type) {
135   return enumerator->HasTypeDirectory(GetTypeString(type));
136 }
137
138 }  // namespace
139
140 // TODO(ericu): The vast majority of this and the other FSFU subclass tests
141 // could theoretically be shared.  It would basically be a FSFU interface
142 // compliance test, and only the subclass-specific bits that look into the
143 // implementation would need to be written per-subclass.
144 class ObfuscatedFileUtilTest : public testing::Test {
145  public:
146   ObfuscatedFileUtilTest()
147       : origin_(GURL("http://www.example.com")),
148         type_(storage::kFileSystemTypeTemporary),
149         weak_factory_(this),
150         sandbox_file_system_(origin_, type_),
151         quota_status_(storage::kQuotaStatusUnknown),
152         usage_(-1) {}
153
154   void SetUp() override {
155     ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
156
157     storage_policy_ = new MockSpecialStoragePolicy();
158
159     quota_manager_ =
160         new storage::QuotaManager(false /* is_incognito */,
161                                   data_dir_.path(),
162                                   base::MessageLoopProxy::current().get(),
163                                   base::MessageLoopProxy::current().get(),
164                                   storage_policy_.get());
165
166     // Every time we create a new sandbox_file_system helper,
167     // it creates another context, which creates another path manager,
168     // another sandbox_backend, and another OFU.
169     // We need to pass in the context to skip all that.
170     file_system_context_ = CreateFileSystemContextForTesting(
171         quota_manager_->proxy(),
172         data_dir_.path());
173
174     sandbox_file_system_.SetUp(file_system_context_.get());
175
176     change_observers_ =
177         storage::MockFileChangeObserver::CreateList(&change_observer_);
178   }
179
180   void TearDown() override {
181     quota_manager_ = NULL;
182     sandbox_file_system_.TearDown();
183   }
184
185   scoped_ptr<FileSystemOperationContext> LimitedContext(
186       int64 allowed_bytes_growth) {
187     scoped_ptr<FileSystemOperationContext> context(
188         sandbox_file_system_.NewOperationContext());
189     context->set_allowed_bytes_growth(allowed_bytes_growth);
190     return context.Pass();
191   }
192
193   scoped_ptr<FileSystemOperationContext> UnlimitedContext() {
194     return LimitedContext(kint64max);
195   }
196
197   FileSystemOperationContext* NewContext(
198       SandboxFileSystemTestHelper* file_system) {
199     change_observer()->ResetCount();
200     FileSystemOperationContext* context;
201     if (file_system)
202       context = file_system->NewOperationContext();
203     else
204       context = sandbox_file_system_.NewOperationContext();
205     // Setting allowed_bytes_growth big enough for all tests.
206     context->set_allowed_bytes_growth(1024 * 1024);
207     context->set_change_observers(change_observers());
208     return context;
209   }
210
211   const storage::ChangeObserverList& change_observers() const {
212     return change_observers_;
213   }
214
215   storage::MockFileChangeObserver* change_observer() {
216     return &change_observer_;
217   }
218
219   // This can only be used after SetUp has run and created file_system_context_
220   // and obfuscated_file_util_.
221   // Use this for tests which need to run in multiple origins; we need a test
222   // helper per origin.
223   SandboxFileSystemTestHelper* NewFileSystem(const GURL& origin,
224                                              storage::FileSystemType type) {
225     SandboxFileSystemTestHelper* file_system =
226         new SandboxFileSystemTestHelper(origin, type);
227
228     file_system->SetUp(file_system_context_.get());
229     return file_system;
230   }
231
232   scoped_ptr<ObfuscatedFileUtil> CreateObfuscatedFileUtil(
233       storage::SpecialStoragePolicy* storage_policy) {
234     return scoped_ptr<ObfuscatedFileUtil>(
235       ObfuscatedFileUtil::CreateForTesting(
236           storage_policy, data_dir_path(), NULL,
237           base::MessageLoopProxy::current().get()));
238   }
239
240   ObfuscatedFileUtil* ofu() {
241     return static_cast<ObfuscatedFileUtil*>(sandbox_file_system_.file_util());
242   }
243
244   const base::FilePath& test_directory() const {
245     return data_dir_.path();
246   }
247
248   const GURL& origin() const {
249     return origin_;
250   }
251
252   storage::FileSystemType type() const { return type_; }
253
254   std::string type_string() const {
255     return GetTypeString(type_);
256   }
257
258   int64 ComputeTotalFileSize() {
259     return sandbox_file_system_.ComputeCurrentOriginUsage() -
260         sandbox_file_system_.ComputeCurrentDirectoryDatabaseUsage();
261   }
262
263   void GetUsageFromQuotaManager() {
264     int64 quota = -1;
265     quota_status_ =
266         AsyncFileTestHelper::GetUsageAndQuota(quota_manager_.get(),
267                                               origin(),
268                                               sandbox_file_system_.type(),
269                                               &usage_,
270                                               &quota);
271     EXPECT_EQ(storage::kQuotaStatusOk, quota_status_);
272   }
273
274   void RevokeUsageCache() {
275     quota_manager_->ResetUsageTracker(sandbox_file_system_.storage_type());
276     usage_cache()->Delete(sandbox_file_system_.GetUsageCachePath());
277   }
278
279   int64 SizeByQuotaUtil() {
280     return sandbox_file_system_.GetCachedOriginUsage();
281   }
282
283   int64 SizeInUsageFile() {
284     base::RunLoop().RunUntilIdle();
285     int64 usage = 0;
286     return usage_cache()->GetUsage(
287         sandbox_file_system_.GetUsageCachePath(), &usage) ? usage : -1;
288   }
289
290   bool PathExists(const FileSystemURL& url) {
291     scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
292     base::File::Info file_info;
293     base::FilePath platform_path;
294     base::File::Error error = ofu()->GetFileInfo(
295         context.get(), url, &file_info, &platform_path);
296     return error == base::File::FILE_OK;
297   }
298
299   bool DirectoryExists(const FileSystemURL& url) {
300     return AsyncFileTestHelper::DirectoryExists(file_system_context(), url);
301   }
302
303   int64 usage() const { return usage_; }
304   storage::FileSystemUsageCache* usage_cache() {
305     return sandbox_file_system_.usage_cache();
306   }
307
308   FileSystemURL CreateURLFromUTF8(const std::string& path) {
309     return sandbox_file_system_.CreateURLFromUTF8(path);
310   }
311
312   int64 PathCost(const FileSystemURL& url) {
313     return ObfuscatedFileUtil::ComputeFilePathCost(url.path());
314   }
315
316   FileSystemURL CreateURL(const base::FilePath& path) {
317     return sandbox_file_system_.CreateURL(path);
318   }
319
320   void CheckFileAndCloseHandle(const FileSystemURL& url, base::File file) {
321     scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
322     base::FilePath local_path;
323     EXPECT_EQ(base::File::FILE_OK,
324               ofu()->GetLocalFilePath(context.get(), url, &local_path));
325
326     base::File::Info file_info0;
327     base::FilePath data_path;
328     EXPECT_EQ(base::File::FILE_OK,
329               ofu()->GetFileInfo(context.get(), url, &file_info0, &data_path));
330     EXPECT_EQ(data_path, local_path);
331     EXPECT_TRUE(FileExists(data_path));
332     EXPECT_EQ(0, GetSize(data_path));
333
334     const char data[] = "test data";
335     const int length = arraysize(data) - 1;
336
337     if (!file.IsValid()) {
338       file.Initialize(data_path,
339                       base::File::FLAG_OPEN | base::File::FLAG_WRITE);
340       ASSERT_TRUE(file.IsValid());
341       EXPECT_FALSE(file.created());
342     }
343     ASSERT_EQ(length, file.Write(0, data, length));
344     file.Close();
345
346     base::File::Info file_info1;
347     EXPECT_EQ(length, GetSize(data_path));
348     context.reset(NewContext(NULL));
349     EXPECT_EQ(base::File::FILE_OK,
350               ofu()->GetFileInfo(context.get(), url, &file_info1, &data_path));
351     EXPECT_EQ(data_path, local_path);
352
353     EXPECT_FALSE(file_info0.is_directory);
354     EXPECT_FALSE(file_info1.is_directory);
355     EXPECT_FALSE(file_info0.is_symbolic_link);
356     EXPECT_FALSE(file_info1.is_symbolic_link);
357     EXPECT_EQ(0, file_info0.size);
358     EXPECT_EQ(length, file_info1.size);
359     EXPECT_LE(file_info0.last_modified, file_info1.last_modified);
360
361     context.reset(NewContext(NULL));
362     EXPECT_EQ(base::File::FILE_OK,
363               ofu()->Truncate(context.get(), url, length * 2));
364     EXPECT_EQ(length * 2, GetSize(data_path));
365
366     context.reset(NewContext(NULL));
367     EXPECT_EQ(base::File::FILE_OK,
368               ofu()->Truncate(context.get(), url, 0));
369     EXPECT_EQ(0, GetSize(data_path));
370   }
371
372   void ValidateTestDirectory(
373       const FileSystemURL& root_url,
374       const std::set<base::FilePath::StringType>& files,
375       const std::set<base::FilePath::StringType>& directories) {
376     scoped_ptr<FileSystemOperationContext> context;
377     std::set<base::FilePath::StringType>::const_iterator iter;
378     for (iter = files.begin(); iter != files.end(); ++iter) {
379       bool created = true;
380       context.reset(NewContext(NULL));
381       ASSERT_EQ(base::File::FILE_OK,
382                 ofu()->EnsureFileExists(context.get(),
383                                         FileSystemURLAppend(root_url, *iter),
384                                         &created));
385       ASSERT_FALSE(created);
386     }
387     for (iter = directories.begin(); iter != directories.end(); ++iter) {
388       context.reset(NewContext(NULL));
389       EXPECT_TRUE(DirectoryExists(
390           FileSystemURLAppend(root_url, *iter)));
391     }
392   }
393
394   class UsageVerifyHelper {
395    public:
396     UsageVerifyHelper(scoped_ptr<FileSystemOperationContext> context,
397                       SandboxFileSystemTestHelper* file_system,
398                       int64 expected_usage)
399         : context_(context.Pass()),
400           sandbox_file_system_(file_system),
401           expected_usage_(expected_usage) {}
402
403     ~UsageVerifyHelper() {
404       base::RunLoop().RunUntilIdle();
405       Check();
406     }
407
408     FileSystemOperationContext* context() {
409       return context_.get();
410     }
411
412    private:
413     void Check() {
414       ASSERT_EQ(expected_usage_,
415                 sandbox_file_system_->GetCachedOriginUsage());
416     }
417
418     scoped_ptr<FileSystemOperationContext> context_;
419     SandboxFileSystemTestHelper* sandbox_file_system_;
420     int64 expected_usage_;
421   };
422
423   scoped_ptr<UsageVerifyHelper> AllowUsageIncrease(int64 requested_growth) {
424     int64 usage = sandbox_file_system_.GetCachedOriginUsage();
425     return scoped_ptr<UsageVerifyHelper>(new UsageVerifyHelper(
426         LimitedContext(requested_growth),
427         &sandbox_file_system_, usage + requested_growth));
428   }
429
430   scoped_ptr<UsageVerifyHelper> DisallowUsageIncrease(int64 requested_growth) {
431     int64 usage = sandbox_file_system_.GetCachedOriginUsage();
432     return scoped_ptr<UsageVerifyHelper>(new UsageVerifyHelper(
433         LimitedContext(requested_growth - 1), &sandbox_file_system_, usage));
434   }
435
436   void FillTestDirectory(
437       const FileSystemURL& root_url,
438       std::set<base::FilePath::StringType>* files,
439       std::set<base::FilePath::StringType>* directories) {
440     scoped_ptr<FileSystemOperationContext> context;
441     std::vector<storage::DirectoryEntry> entries;
442     EXPECT_EQ(base::File::FILE_OK,
443               AsyncFileTestHelper::ReadDirectory(file_system_context(),
444                                                  root_url, &entries));
445     EXPECT_EQ(0UL, entries.size());
446
447     files->clear();
448     files->insert(FILE_PATH_LITERAL("first"));
449     files->insert(FILE_PATH_LITERAL("second"));
450     files->insert(FILE_PATH_LITERAL("third"));
451     directories->clear();
452     directories->insert(FILE_PATH_LITERAL("fourth"));
453     directories->insert(FILE_PATH_LITERAL("fifth"));
454     directories->insert(FILE_PATH_LITERAL("sixth"));
455     std::set<base::FilePath::StringType>::iterator iter;
456     for (iter = files->begin(); iter != files->end(); ++iter) {
457       bool created = false;
458       context.reset(NewContext(NULL));
459       ASSERT_EQ(base::File::FILE_OK,
460                 ofu()->EnsureFileExists(context.get(),
461                                         FileSystemURLAppend(root_url, *iter),
462                                         &created));
463       ASSERT_TRUE(created);
464     }
465     for (iter = directories->begin(); iter != directories->end(); ++iter) {
466       bool exclusive = true;
467       bool recursive = false;
468       context.reset(NewContext(NULL));
469       EXPECT_EQ(base::File::FILE_OK,
470                 ofu()->CreateDirectory(context.get(),
471                                        FileSystemURLAppend(root_url, *iter),
472                                        exclusive, recursive));
473     }
474     ValidateTestDirectory(root_url, *files, *directories);
475   }
476
477   void TestReadDirectoryHelper(const FileSystemURL& root_url) {
478     std::set<base::FilePath::StringType> files;
479     std::set<base::FilePath::StringType> directories;
480     FillTestDirectory(root_url, &files, &directories);
481
482     scoped_ptr<FileSystemOperationContext> context;
483     std::vector<storage::DirectoryEntry> entries;
484     context.reset(NewContext(NULL));
485     EXPECT_EQ(base::File::FILE_OK,
486               AsyncFileTestHelper::ReadDirectory(
487                   file_system_context(), root_url, &entries));
488     std::vector<storage::DirectoryEntry>::iterator entry_iter;
489     EXPECT_EQ(files.size() + directories.size(), entries.size());
490     EXPECT_TRUE(change_observer()->HasNoChange());
491     for (entry_iter = entries.begin(); entry_iter != entries.end();
492         ++entry_iter) {
493       const storage::DirectoryEntry& entry = *entry_iter;
494       std::set<base::FilePath::StringType>::iterator iter =
495           files.find(entry.name);
496       if (iter != files.end()) {
497         EXPECT_FALSE(entry.is_directory);
498         files.erase(iter);
499         continue;
500       }
501       iter = directories.find(entry.name);
502       EXPECT_FALSE(directories.end() == iter);
503       EXPECT_TRUE(entry.is_directory);
504       directories.erase(iter);
505     }
506   }
507
508   void TestTouchHelper(const FileSystemURL& url, bool is_file) {
509     base::Time last_access_time = base::Time::Now();
510     base::Time last_modified_time = base::Time::Now();
511
512     scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
513     EXPECT_EQ(base::File::FILE_OK,
514               ofu()->Touch(context.get(), url, last_access_time,
515                            last_modified_time));
516     // Currently we fire no change notifications for Touch.
517     EXPECT_TRUE(change_observer()->HasNoChange());
518     base::FilePath local_path;
519     base::File::Info file_info;
520     context.reset(NewContext(NULL));
521     EXPECT_EQ(base::File::FILE_OK, ofu()->GetFileInfo(
522         context.get(), url, &file_info, &local_path));
523     // We compare as time_t here to lower our resolution, to avoid false
524     // negatives caused by conversion to the local filesystem's native
525     // representation and back.
526     EXPECT_EQ(file_info.last_modified.ToTimeT(), last_modified_time.ToTimeT());
527
528     context.reset(NewContext(NULL));
529     last_modified_time += base::TimeDelta::FromHours(1);
530     last_access_time += base::TimeDelta::FromHours(14);
531     EXPECT_EQ(base::File::FILE_OK,
532               ofu()->Touch(context.get(), url, last_access_time,
533                            last_modified_time));
534     EXPECT_TRUE(change_observer()->HasNoChange());
535     context.reset(NewContext(NULL));
536     EXPECT_EQ(base::File::FILE_OK,
537               ofu()->GetFileInfo(context.get(), url, &file_info, &local_path));
538     EXPECT_EQ(file_info.last_modified.ToTimeT(), last_modified_time.ToTimeT());
539     if (is_file)  // Directories in OFU don't support atime.
540       EXPECT_EQ(file_info.last_accessed.ToTimeT(), last_access_time.ToTimeT());
541   }
542
543   void TestCopyInForeignFileHelper(bool overwrite) {
544     base::ScopedTempDir source_dir;
545     ASSERT_TRUE(source_dir.CreateUniqueTempDir());
546     base::FilePath root_file_path = source_dir.path();
547     base::FilePath src_file_path = root_file_path.AppendASCII("file_name");
548     FileSystemURL dest_url = CreateURLFromUTF8("new file");
549     int64 src_file_length = 87;
550
551     base::File file(src_file_path,
552                     base::File::FLAG_CREATE | base::File::FLAG_WRITE);
553     ASSERT_TRUE(file.IsValid());
554     EXPECT_TRUE(file.created());
555     ASSERT_TRUE(file.SetLength(src_file_length));
556     file.Close();
557
558     scoped_ptr<FileSystemOperationContext> context;
559
560     if (overwrite) {
561       context.reset(NewContext(NULL));
562       bool created = false;
563       EXPECT_EQ(base::File::FILE_OK,
564                 ofu()->EnsureFileExists(context.get(), dest_url, &created));
565       EXPECT_TRUE(created);
566
567       // We must have observed one (and only one) create_file_count.
568       EXPECT_EQ(1, change_observer()->get_and_reset_create_file_count());
569       EXPECT_TRUE(change_observer()->HasNoChange());
570     }
571
572     const int64 path_cost =
573         ObfuscatedFileUtil::ComputeFilePathCost(dest_url.path());
574     if (!overwrite) {
575       // Verify that file creation requires sufficient quota for the path.
576       context.reset(NewContext(NULL));
577       context->set_allowed_bytes_growth(path_cost + src_file_length - 1);
578       EXPECT_EQ(base::File::FILE_ERROR_NO_SPACE,
579                 ofu()->CopyInForeignFile(context.get(),
580                                          src_file_path, dest_url));
581     }
582
583     context.reset(NewContext(NULL));
584     context->set_allowed_bytes_growth(path_cost + src_file_length);
585     EXPECT_EQ(base::File::FILE_OK,
586               ofu()->CopyInForeignFile(context.get(),
587                                        src_file_path, dest_url));
588
589     EXPECT_TRUE(PathExists(dest_url));
590     EXPECT_FALSE(DirectoryExists(dest_url));
591
592     context.reset(NewContext(NULL));
593     base::File::Info file_info;
594     base::FilePath data_path;
595     EXPECT_EQ(base::File::FILE_OK,
596               ofu()->GetFileInfo(context.get(), dest_url, &file_info,
597                                  &data_path));
598     EXPECT_NE(data_path, src_file_path);
599     EXPECT_TRUE(FileExists(data_path));
600     EXPECT_EQ(src_file_length, GetSize(data_path));
601
602     EXPECT_EQ(base::File::FILE_OK,
603               ofu()->DeleteFile(context.get(), dest_url));
604   }
605
606   void ClearTimestamp(const FileSystemURL& url) {
607     scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
608     EXPECT_EQ(base::File::FILE_OK,
609               ofu()->Touch(context.get(), url, base::Time(), base::Time()));
610     EXPECT_EQ(base::Time(), GetModifiedTime(url));
611   }
612
613   base::Time GetModifiedTime(const FileSystemURL& url) {
614     scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
615     base::FilePath data_path;
616     base::File::Info file_info;
617     context.reset(NewContext(NULL));
618     EXPECT_EQ(base::File::FILE_OK,
619               ofu()->GetFileInfo(context.get(), url, &file_info, &data_path));
620     EXPECT_TRUE(change_observer()->HasNoChange());
621     return file_info.last_modified;
622   }
623
624   void TestDirectoryTimestampHelper(const FileSystemURL& base_dir,
625                                     bool copy,
626                                     bool overwrite) {
627     scoped_ptr<FileSystemOperationContext> context;
628     const FileSystemURL src_dir_url(
629         FileSystemURLAppendUTF8(base_dir, "foo_dir"));
630     const FileSystemURL dest_dir_url(
631         FileSystemURLAppendUTF8(base_dir, "bar_dir"));
632
633     const FileSystemURL src_file_url(
634         FileSystemURLAppendUTF8(src_dir_url, "hoge"));
635     const FileSystemURL dest_file_url(
636         FileSystemURLAppendUTF8(dest_dir_url, "fuga"));
637
638     context.reset(NewContext(NULL));
639     EXPECT_EQ(base::File::FILE_OK,
640               ofu()->CreateDirectory(context.get(), src_dir_url, true, true));
641     context.reset(NewContext(NULL));
642     EXPECT_EQ(base::File::FILE_OK,
643               ofu()->CreateDirectory(context.get(), dest_dir_url, true, true));
644
645     bool created = false;
646     context.reset(NewContext(NULL));
647     EXPECT_EQ(base::File::FILE_OK,
648               ofu()->EnsureFileExists(context.get(), src_file_url, &created));
649     if (overwrite) {
650       context.reset(NewContext(NULL));
651       EXPECT_EQ(base::File::FILE_OK,
652                 ofu()->EnsureFileExists(context.get(),
653                                         dest_file_url, &created));
654     }
655
656     ClearTimestamp(src_dir_url);
657     ClearTimestamp(dest_dir_url);
658     context.reset(NewContext(NULL));
659     EXPECT_EQ(base::File::FILE_OK,
660               ofu()->CopyOrMoveFile(context.get(),
661                                     src_file_url, dest_file_url,
662                                     FileSystemOperation::OPTION_NONE,
663                                     copy));
664     if (copy)
665       EXPECT_EQ(base::Time(), GetModifiedTime(src_dir_url));
666     else
667       EXPECT_NE(base::Time(), GetModifiedTime(src_dir_url));
668     EXPECT_NE(base::Time(), GetModifiedTime(dest_dir_url));
669   }
670
671   void MaybeDropDatabasesAliveCaseTestBody() {
672     scoped_ptr<ObfuscatedFileUtil> file_util = CreateObfuscatedFileUtil(NULL);
673     file_util->InitOriginDatabase(GURL(), true /*create*/);
674     ASSERT_TRUE(file_util->origin_database_ != NULL);
675
676     // Callback to Drop DB is called while ObfuscatedFileUtilTest is
677     // still alive.
678     file_util->db_flush_delay_seconds_ = 0;
679     file_util->MarkUsed();
680     base::RunLoop().RunUntilIdle();
681
682     ASSERT_TRUE(file_util->origin_database_ == NULL);
683   }
684
685   void MaybeDropDatabasesAlreadyDeletedCaseTestBody() {
686     // Run message loop after OFU is already deleted to make sure callback
687     // doesn't cause a crash for use after free.
688     {
689       scoped_ptr<ObfuscatedFileUtil> file_util = CreateObfuscatedFileUtil(NULL);
690       file_util->InitOriginDatabase(GURL(), true /*create*/);
691       file_util->db_flush_delay_seconds_ = 0;
692       file_util->MarkUsed();
693     }
694
695     // At this point the callback is still in the message queue but OFU is gone.
696     base::RunLoop().RunUntilIdle();
697   }
698
699   void DestroyDirectoryDatabase_IsolatedTestBody() {
700     storage_policy_->AddIsolated(origin_);
701     scoped_ptr<ObfuscatedFileUtil> file_util = CreateObfuscatedFileUtil(
702         storage_policy_.get());
703     const FileSystemURL url = FileSystemURL::CreateForTest(
704         origin_, kFileSystemTypePersistent, base::FilePath());
705
706     // Create DirectoryDatabase for isolated origin.
707     SandboxDirectoryDatabase* db =
708         file_util->GetDirectoryDatabase(url, true /* create */);
709     ASSERT_TRUE(db != NULL);
710
711     // Destory it.
712     file_util->DestroyDirectoryDatabase(
713         url.origin(), GetTypeString(url.type()));
714     ASSERT_TRUE(file_util->directories_.empty());
715   }
716
717   void GetDirectoryDatabase_IsolatedTestBody() {
718     storage_policy_->AddIsolated(origin_);
719     scoped_ptr<ObfuscatedFileUtil> file_util = CreateObfuscatedFileUtil(
720         storage_policy_.get());
721     const FileSystemURL url = FileSystemURL::CreateForTest(
722         origin_, kFileSystemTypePersistent, base::FilePath());
723
724     // Create DirectoryDatabase for isolated origin.
725     SandboxDirectoryDatabase* db =
726         file_util->GetDirectoryDatabase(url, true /* create */);
727     ASSERT_TRUE(db != NULL);
728     ASSERT_EQ(1U, file_util->directories_.size());
729
730     // Remove isolated.
731     storage_policy_->RemoveIsolated(url.origin());
732
733     // This should still get the same database.
734     SandboxDirectoryDatabase* db2 =
735         file_util->GetDirectoryDatabase(url, false /* create */);
736     ASSERT_EQ(db, db2);
737   }
738
739   void MigrationBackFromIsolatedTestBody() {
740     std::string kFakeDirectoryData("0123456789");
741     base::FilePath old_directory_db_path;
742
743     // Initialize the directory with one origin using
744     // SandboxIsolatedOriginDatabase.
745     {
746       std::string origin_string = storage::GetIdentifierFromOrigin(origin_);
747       SandboxIsolatedOriginDatabase database_old(
748           origin_string, data_dir_path(),
749           base::FilePath(
750               SandboxIsolatedOriginDatabase::kObsoleteOriginDirectory));
751       base::FilePath path;
752       EXPECT_TRUE(database_old.GetPathForOrigin(origin_string, &path));
753       EXPECT_FALSE(path.empty());
754
755       // Populate the origin directory with some fake data.
756       old_directory_db_path = data_dir_path().Append(path);
757       ASSERT_TRUE(base::CreateDirectory(old_directory_db_path));
758       EXPECT_EQ(static_cast<int>(kFakeDirectoryData.size()),
759                 base::WriteFile(old_directory_db_path.AppendASCII("dummy"),
760                                 kFakeDirectoryData.data(),
761                                 kFakeDirectoryData.size()));
762     }
763
764     storage_policy_->AddIsolated(origin_);
765     scoped_ptr<ObfuscatedFileUtil> file_util = CreateObfuscatedFileUtil(
766         storage_policy_.get());
767     base::File::Error error = base::File::FILE_ERROR_FAILED;
768     base::FilePath origin_directory = file_util->GetDirectoryForOrigin(
769         origin_, true /* create */, &error);
770     EXPECT_EQ(base::File::FILE_OK, error);
771
772     // The database is migrated from the old one.
773     EXPECT_TRUE(base::DirectoryExists(origin_directory));
774     EXPECT_FALSE(base::DirectoryExists(old_directory_db_path));
775
776     // Check we see the same contents in the new origin directory.
777     std::string origin_db_data;
778     EXPECT_TRUE(base::PathExists(origin_directory.AppendASCII("dummy")));
779     EXPECT_TRUE(base::ReadFileToString(
780             origin_directory.AppendASCII("dummy"), &origin_db_data));
781     EXPECT_EQ(kFakeDirectoryData, origin_db_data);
782   }
783
784   int64 ComputeCurrentUsage() {
785     return sandbox_file_system_.ComputeCurrentOriginUsage() -
786         sandbox_file_system_.ComputeCurrentDirectoryDatabaseUsage();
787   }
788
789   FileSystemContext* file_system_context() {
790     return sandbox_file_system_.file_system_context();
791   }
792
793   const base::FilePath& data_dir_path() const {
794     return data_dir_.path();
795   }
796
797  protected:
798   base::ScopedTempDir data_dir_;
799   base::MessageLoopForIO message_loop_;
800   scoped_refptr<MockSpecialStoragePolicy> storage_policy_;
801   scoped_refptr<storage::QuotaManager> quota_manager_;
802   scoped_refptr<FileSystemContext> file_system_context_;
803   GURL origin_;
804   storage::FileSystemType type_;
805   base::WeakPtrFactory<ObfuscatedFileUtilTest> weak_factory_;
806   SandboxFileSystemTestHelper sandbox_file_system_;
807   storage::QuotaStatusCode quota_status_;
808   int64 usage_;
809   storage::MockFileChangeObserver change_observer_;
810   storage::ChangeObserverList change_observers_;
811
812  private:
813   DISALLOW_COPY_AND_ASSIGN(ObfuscatedFileUtilTest);
814 };
815
816 TEST_F(ObfuscatedFileUtilTest, TestCreateAndDeleteFile) {
817   FileSystemURL url = CreateURLFromUTF8("fake/file");
818   scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
819   int file_flags = base::File::FLAG_CREATE | base::File::FLAG_WRITE;
820
821   base::File file = ofu()->CreateOrOpen(context.get(), url, file_flags);
822   EXPECT_FALSE(file.IsValid());
823   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, file.error_details());
824
825   context.reset(NewContext(NULL));
826   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
827             ofu()->DeleteFile(context.get(), url));
828
829   url = CreateURLFromUTF8("test file");
830
831   EXPECT_TRUE(change_observer()->HasNoChange());
832
833   // Verify that file creation requires sufficient quota for the path.
834   context.reset(NewContext(NULL));
835   context->set_allowed_bytes_growth(
836       ObfuscatedFileUtil::ComputeFilePathCost(url.path()) - 1);
837   file = ofu()->CreateOrOpen(context.get(), url, file_flags);
838   EXPECT_FALSE(file.IsValid());
839   ASSERT_EQ(base::File::FILE_ERROR_NO_SPACE, file.error_details());
840
841   context.reset(NewContext(NULL));
842   context->set_allowed_bytes_growth(
843       ObfuscatedFileUtil::ComputeFilePathCost(url.path()));
844   file = ofu()->CreateOrOpen(context.get(), url, file_flags);
845   EXPECT_TRUE(file.IsValid());
846   ASSERT_TRUE(file.created());
847   EXPECT_EQ(1, change_observer()->get_and_reset_create_file_count());
848
849   CheckFileAndCloseHandle(url, file.Pass());
850
851   context.reset(NewContext(NULL));
852   base::FilePath local_path;
853   EXPECT_EQ(base::File::FILE_OK,
854             ofu()->GetLocalFilePath(context.get(), url, &local_path));
855   EXPECT_TRUE(base::PathExists(local_path));
856
857   // Verify that deleting a file isn't stopped by zero quota, and that it frees
858   // up quote from its path.
859   context.reset(NewContext(NULL));
860   context->set_allowed_bytes_growth(0);
861   EXPECT_EQ(base::File::FILE_OK, ofu()->DeleteFile(context.get(), url));
862   EXPECT_EQ(1, change_observer()->get_and_reset_remove_file_count());
863   EXPECT_FALSE(base::PathExists(local_path));
864   EXPECT_EQ(ObfuscatedFileUtil::ComputeFilePathCost(url.path()),
865             context->allowed_bytes_growth());
866
867   context.reset(NewContext(NULL));
868   bool exclusive = true;
869   bool recursive = true;
870   FileSystemURL directory_url = CreateURLFromUTF8(
871       "series/of/directories");
872   url = FileSystemURLAppendUTF8(directory_url, "file name");
873   EXPECT_EQ(base::File::FILE_OK,
874             ofu()->CreateDirectory(context.get(), directory_url, exclusive,
875                                    recursive));
876   // The oepration created 3 directories recursively.
877   EXPECT_EQ(3, change_observer()->get_and_reset_create_directory_count());
878
879   context.reset(NewContext(NULL));
880   file = ofu()->CreateOrOpen(context.get(), url, file_flags);
881   ASSERT_TRUE(file.IsValid());
882   ASSERT_TRUE(file.created());
883   EXPECT_EQ(1, change_observer()->get_and_reset_create_file_count());
884
885   CheckFileAndCloseHandle(url, file.Pass());
886
887   context.reset(NewContext(NULL));
888   EXPECT_EQ(base::File::FILE_OK,
889             ofu()->GetLocalFilePath(context.get(), url, &local_path));
890   EXPECT_TRUE(base::PathExists(local_path));
891
892   context.reset(NewContext(NULL));
893   EXPECT_EQ(base::File::FILE_OK, ofu()->DeleteFile(context.get(), url));
894   EXPECT_EQ(1, change_observer()->get_and_reset_remove_file_count());
895   EXPECT_FALSE(base::PathExists(local_path));
896
897   // Make sure we have no unexpected changes.
898   EXPECT_TRUE(change_observer()->HasNoChange());
899 }
900
901 TEST_F(ObfuscatedFileUtilTest, TestTruncate) {
902   bool created = false;
903   FileSystemURL url = CreateURLFromUTF8("file");
904   scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
905
906   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
907             ofu()->Truncate(context.get(), url, 4));
908
909   context.reset(NewContext(NULL));
910   ASSERT_EQ(base::File::FILE_OK,
911             ofu()->EnsureFileExists(context.get(), url, &created));
912   ASSERT_TRUE(created);
913   EXPECT_EQ(1, change_observer()->get_and_reset_create_file_count());
914
915   context.reset(NewContext(NULL));
916   base::FilePath local_path;
917   EXPECT_EQ(base::File::FILE_OK,
918             ofu()->GetLocalFilePath(context.get(), url, &local_path));
919   EXPECT_EQ(0, GetSize(local_path));
920
921   context.reset(NewContext(NULL));
922   EXPECT_EQ(base::File::FILE_OK, ofu()->Truncate(context.get(), url, 10));
923   EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count());
924   EXPECT_EQ(10, GetSize(local_path));
925
926   context.reset(NewContext(NULL));
927   EXPECT_EQ(base::File::FILE_OK, ofu()->Truncate(context.get(), url, 1));
928   EXPECT_EQ(1, GetSize(local_path));
929   EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count());
930
931   EXPECT_FALSE(DirectoryExists(url));
932   EXPECT_TRUE(PathExists(url));
933
934   // Make sure we have no unexpected changes.
935   EXPECT_TRUE(change_observer()->HasNoChange());
936 }
937
938 TEST_F(ObfuscatedFileUtilTest, TestQuotaOnTruncation) {
939   bool created = false;
940   FileSystemURL url = CreateURLFromUTF8("file");
941
942   ASSERT_EQ(base::File::FILE_OK,
943             ofu()->EnsureFileExists(
944                 AllowUsageIncrease(PathCost(url))->context(),
945                 url, &created));
946   ASSERT_TRUE(created);
947   ASSERT_EQ(0, ComputeTotalFileSize());
948
949   ASSERT_EQ(base::File::FILE_OK,
950             ofu()->Truncate(AllowUsageIncrease(1020)->context(), url, 1020));
951   ASSERT_EQ(1020, ComputeTotalFileSize());
952
953   ASSERT_EQ(base::File::FILE_OK,
954             ofu()->Truncate(AllowUsageIncrease(-1020)->context(), url, 0));
955   ASSERT_EQ(0, ComputeTotalFileSize());
956
957   EXPECT_EQ(base::File::FILE_ERROR_NO_SPACE,
958             ofu()->Truncate(DisallowUsageIncrease(1021)->context(),
959                             url, 1021));
960   ASSERT_EQ(0, ComputeTotalFileSize());
961
962   EXPECT_EQ(base::File::FILE_OK,
963             ofu()->Truncate(AllowUsageIncrease(1020)->context(), url, 1020));
964   ASSERT_EQ(1020, ComputeTotalFileSize());
965
966   EXPECT_EQ(base::File::FILE_OK,
967             ofu()->Truncate(AllowUsageIncrease(0)->context(), url, 1020));
968   ASSERT_EQ(1020, ComputeTotalFileSize());
969
970   // quota exceeded
971   {
972     scoped_ptr<UsageVerifyHelper> helper = AllowUsageIncrease(-1);
973     helper->context()->set_allowed_bytes_growth(
974         helper->context()->allowed_bytes_growth() - 1);
975     EXPECT_EQ(base::File::FILE_OK,
976               ofu()->Truncate(helper->context(), url, 1019));
977     ASSERT_EQ(1019, ComputeTotalFileSize());
978   }
979
980   // Delete backing file to make following truncation fail.
981   base::FilePath local_path;
982   ASSERT_EQ(base::File::FILE_OK,
983             ofu()->GetLocalFilePath(UnlimitedContext().get(), url,
984                                     &local_path));
985   ASSERT_FALSE(local_path.empty());
986   ASSERT_TRUE(base::DeleteFile(local_path, false));
987
988   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
989             ofu()->Truncate(LimitedContext(1234).get(), url, 1234));
990   ASSERT_EQ(0, ComputeTotalFileSize());
991 }
992
993 TEST_F(ObfuscatedFileUtilTest, TestEnsureFileExists) {
994   FileSystemURL url = CreateURLFromUTF8("fake/file");
995   bool created = false;
996   scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
997   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
998             ofu()->EnsureFileExists(context.get(), url, &created));
999   EXPECT_TRUE(change_observer()->HasNoChange());
1000
1001   // Verify that file creation requires sufficient quota for the path.
1002   context.reset(NewContext(NULL));
1003   url = CreateURLFromUTF8("test file");
1004   created = false;
1005   context->set_allowed_bytes_growth(
1006       ObfuscatedFileUtil::ComputeFilePathCost(url.path()) - 1);
1007   ASSERT_EQ(base::File::FILE_ERROR_NO_SPACE,
1008             ofu()->EnsureFileExists(context.get(), url, &created));
1009   ASSERT_FALSE(created);
1010   EXPECT_TRUE(change_observer()->HasNoChange());
1011
1012   context.reset(NewContext(NULL));
1013   context->set_allowed_bytes_growth(
1014       ObfuscatedFileUtil::ComputeFilePathCost(url.path()));
1015   ASSERT_EQ(base::File::FILE_OK,
1016             ofu()->EnsureFileExists(context.get(), url, &created));
1017   ASSERT_TRUE(created);
1018   EXPECT_EQ(1, change_observer()->get_and_reset_create_file_count());
1019
1020   CheckFileAndCloseHandle(url, base::File());
1021
1022   context.reset(NewContext(NULL));
1023   ASSERT_EQ(base::File::FILE_OK,
1024             ofu()->EnsureFileExists(context.get(), url, &created));
1025   ASSERT_FALSE(created);
1026   EXPECT_TRUE(change_observer()->HasNoChange());
1027
1028   // Also test in a subdirectory.
1029   url = CreateURLFromUTF8("path/to/file.txt");
1030   context.reset(NewContext(NULL));
1031   bool exclusive = true;
1032   bool recursive = true;
1033   EXPECT_EQ(base::File::FILE_OK,
1034             ofu()->CreateDirectory(context.get(), FileSystemURLDirName(url),
1035                                    exclusive, recursive));
1036   // 2 directories: path/ and path/to.
1037   EXPECT_EQ(2, change_observer()->get_and_reset_create_directory_count());
1038
1039   context.reset(NewContext(NULL));
1040   ASSERT_EQ(base::File::FILE_OK,
1041             ofu()->EnsureFileExists(context.get(), url, &created));
1042   ASSERT_TRUE(created);
1043   EXPECT_FALSE(DirectoryExists(url));
1044   EXPECT_TRUE(PathExists(url));
1045   EXPECT_TRUE(change_observer()->HasNoChange());
1046 }
1047
1048 TEST_F(ObfuscatedFileUtilTest, TestDirectoryOps) {
1049   scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
1050
1051   bool exclusive = false;
1052   bool recursive = false;
1053   FileSystemURL url = CreateURLFromUTF8("foo/bar");
1054   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
1055             ofu()->CreateDirectory(context.get(), url, exclusive, recursive));
1056
1057   context.reset(NewContext(NULL));
1058   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
1059             ofu()->DeleteDirectory(context.get(), url));
1060
1061   FileSystemURL root = CreateURLFromUTF8(std::string());
1062   EXPECT_FALSE(DirectoryExists(url));
1063   EXPECT_FALSE(PathExists(url));
1064   context.reset(NewContext(NULL));
1065   EXPECT_TRUE(ofu()->IsDirectoryEmpty(context.get(), root));
1066
1067   context.reset(NewContext(NULL));
1068   exclusive = false;
1069   recursive = true;
1070   EXPECT_EQ(base::File::FILE_OK,
1071             ofu()->CreateDirectory(context.get(), url, exclusive, recursive));
1072   EXPECT_EQ(2, change_observer()->get_and_reset_create_directory_count());
1073
1074   EXPECT_TRUE(DirectoryExists(url));
1075   EXPECT_TRUE(PathExists(url));
1076
1077   context.reset(NewContext(NULL));
1078   EXPECT_FALSE(ofu()->IsDirectoryEmpty(context.get(), root));
1079   EXPECT_TRUE(DirectoryExists(FileSystemURLDirName(url)));
1080
1081   context.reset(NewContext(NULL));
1082   EXPECT_FALSE(ofu()->IsDirectoryEmpty(context.get(),
1083                                        FileSystemURLDirName(url)));
1084
1085   // Can't remove a non-empty directory.
1086   context.reset(NewContext(NULL));
1087   EXPECT_EQ(base::File::FILE_ERROR_NOT_EMPTY,
1088             ofu()->DeleteDirectory(context.get(),
1089                                    FileSystemURLDirName(url)));
1090   EXPECT_TRUE(change_observer()->HasNoChange());
1091
1092   base::File::Info file_info;
1093   base::FilePath local_path;
1094   EXPECT_EQ(base::File::FILE_OK,
1095             ofu()->GetFileInfo(context.get(), url, &file_info, &local_path));
1096   EXPECT_TRUE(local_path.empty());
1097   EXPECT_TRUE(file_info.is_directory);
1098   EXPECT_FALSE(file_info.is_symbolic_link);
1099
1100   // Same create again should succeed, since exclusive is false.
1101   context.reset(NewContext(NULL));
1102   EXPECT_EQ(base::File::FILE_OK,
1103             ofu()->CreateDirectory(context.get(), url, exclusive, recursive));
1104   EXPECT_TRUE(change_observer()->HasNoChange());
1105
1106   exclusive = true;
1107   recursive = true;
1108   context.reset(NewContext(NULL));
1109   EXPECT_EQ(base::File::FILE_ERROR_EXISTS,
1110             ofu()->CreateDirectory(context.get(), url, exclusive, recursive));
1111   EXPECT_TRUE(change_observer()->HasNoChange());
1112
1113   // Verify that deleting a directory isn't stopped by zero quota, and that it
1114   // frees up quota from its path.
1115   context.reset(NewContext(NULL));
1116   context->set_allowed_bytes_growth(0);
1117   EXPECT_EQ(base::File::FILE_OK, ofu()->DeleteDirectory(context.get(), url));
1118   EXPECT_EQ(1, change_observer()->get_and_reset_remove_directory_count());
1119   EXPECT_EQ(ObfuscatedFileUtil::ComputeFilePathCost(url.path()),
1120       context->allowed_bytes_growth());
1121
1122   url = CreateURLFromUTF8("foo/bop");
1123
1124   EXPECT_FALSE(DirectoryExists(url));
1125   EXPECT_FALSE(PathExists(url));
1126
1127   context.reset(NewContext(NULL));
1128   EXPECT_TRUE(ofu()->IsDirectoryEmpty(context.get(), url));
1129   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
1130             ofu()->GetFileInfo(context.get(), url, &file_info, &local_path));
1131
1132   // Verify that file creation requires sufficient quota for the path.
1133   exclusive = true;
1134   recursive = false;
1135   context.reset(NewContext(NULL));
1136   context->set_allowed_bytes_growth(
1137       ObfuscatedFileUtil::ComputeFilePathCost(url.path()) - 1);
1138   EXPECT_EQ(base::File::FILE_ERROR_NO_SPACE,
1139             ofu()->CreateDirectory(context.get(), url, exclusive, recursive));
1140   EXPECT_TRUE(change_observer()->HasNoChange());
1141
1142   context.reset(NewContext(NULL));
1143   context->set_allowed_bytes_growth(
1144       ObfuscatedFileUtil::ComputeFilePathCost(url.path()));
1145   EXPECT_EQ(base::File::FILE_OK,
1146             ofu()->CreateDirectory(context.get(), url, exclusive, recursive));
1147   EXPECT_EQ(1, change_observer()->get_and_reset_create_directory_count());
1148
1149   EXPECT_TRUE(DirectoryExists(url));
1150   EXPECT_TRUE(PathExists(url));
1151
1152   exclusive = true;
1153   recursive = false;
1154   context.reset(NewContext(NULL));
1155   EXPECT_EQ(base::File::FILE_ERROR_EXISTS,
1156             ofu()->CreateDirectory(context.get(), url, exclusive, recursive));
1157   EXPECT_TRUE(change_observer()->HasNoChange());
1158
1159   exclusive = true;
1160   recursive = false;
1161   url = CreateURLFromUTF8("foo");
1162   context.reset(NewContext(NULL));
1163   EXPECT_EQ(base::File::FILE_ERROR_EXISTS,
1164             ofu()->CreateDirectory(context.get(), url, exclusive, recursive));
1165   EXPECT_TRUE(change_observer()->HasNoChange());
1166
1167   url = CreateURLFromUTF8("blah");
1168
1169   EXPECT_FALSE(DirectoryExists(url));
1170   EXPECT_FALSE(PathExists(url));
1171
1172   exclusive = true;
1173   recursive = false;
1174   context.reset(NewContext(NULL));
1175   EXPECT_EQ(base::File::FILE_OK,
1176             ofu()->CreateDirectory(context.get(), url, exclusive, recursive));
1177   EXPECT_EQ(1, change_observer()->get_and_reset_create_directory_count());
1178
1179   EXPECT_TRUE(DirectoryExists(url));
1180   EXPECT_TRUE(PathExists(url));
1181
1182   exclusive = true;
1183   recursive = false;
1184   context.reset(NewContext(NULL));
1185   EXPECT_EQ(base::File::FILE_ERROR_EXISTS,
1186             ofu()->CreateDirectory(context.get(), url, exclusive, recursive));
1187   EXPECT_TRUE(change_observer()->HasNoChange());
1188 }
1189
1190 TEST_F(ObfuscatedFileUtilTest, TestReadDirectory) {
1191   scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
1192   bool exclusive = true;
1193   bool recursive = true;
1194   FileSystemURL url = CreateURLFromUTF8("directory/to/use");
1195   EXPECT_EQ(base::File::FILE_OK,
1196             ofu()->CreateDirectory(context.get(), url, exclusive, recursive));
1197   TestReadDirectoryHelper(url);
1198 }
1199
1200 TEST_F(ObfuscatedFileUtilTest, TestReadRootWithSlash) {
1201   TestReadDirectoryHelper(CreateURLFromUTF8(std::string()));
1202 }
1203
1204 TEST_F(ObfuscatedFileUtilTest, TestReadRootWithEmptyString) {
1205   TestReadDirectoryHelper(CreateURLFromUTF8("/"));
1206 }
1207
1208 TEST_F(ObfuscatedFileUtilTest, TestReadDirectoryOnFile) {
1209   FileSystemURL url = CreateURLFromUTF8("file");
1210   scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
1211
1212   bool created = false;
1213   ASSERT_EQ(base::File::FILE_OK,
1214             ofu()->EnsureFileExists(context.get(), url, &created));
1215   ASSERT_TRUE(created);
1216
1217   std::vector<storage::DirectoryEntry> entries;
1218   EXPECT_EQ(base::File::FILE_ERROR_NOT_A_DIRECTORY,
1219             AsyncFileTestHelper::ReadDirectory(file_system_context(), url,
1220                                                &entries));
1221
1222   EXPECT_TRUE(ofu()->IsDirectoryEmpty(context.get(), url));
1223 }
1224
1225 TEST_F(ObfuscatedFileUtilTest, TestTouch) {
1226   FileSystemURL url = CreateURLFromUTF8("file");
1227   scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
1228
1229   base::Time last_access_time = base::Time::Now();
1230   base::Time last_modified_time = base::Time::Now();
1231
1232   // It's not there yet.
1233   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
1234             ofu()->Touch(context.get(), url, last_access_time,
1235                          last_modified_time));
1236
1237   // OK, now create it.
1238   context.reset(NewContext(NULL));
1239   bool created = false;
1240   ASSERT_EQ(base::File::FILE_OK,
1241             ofu()->EnsureFileExists(context.get(), url, &created));
1242   ASSERT_TRUE(created);
1243   TestTouchHelper(url, true);
1244
1245   // Now test a directory:
1246   context.reset(NewContext(NULL));
1247   bool exclusive = true;
1248   bool recursive = false;
1249   url = CreateURLFromUTF8("dir");
1250   ASSERT_EQ(base::File::FILE_OK,
1251             ofu()->CreateDirectory(context.get(), url, exclusive, recursive));
1252   TestTouchHelper(url, false);
1253 }
1254
1255 TEST_F(ObfuscatedFileUtilTest, TestPathQuotas) {
1256   FileSystemURL url = CreateURLFromUTF8("fake/file");
1257   scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
1258
1259   url = CreateURLFromUTF8("file name");
1260   context->set_allowed_bytes_growth(5);
1261   bool created = false;
1262   EXPECT_EQ(base::File::FILE_ERROR_NO_SPACE,
1263             ofu()->EnsureFileExists(context.get(), url, &created));
1264   EXPECT_FALSE(created);
1265   context->set_allowed_bytes_growth(1024);
1266   EXPECT_EQ(base::File::FILE_OK,
1267             ofu()->EnsureFileExists(context.get(), url, &created));
1268   EXPECT_TRUE(created);
1269   int64 path_cost = ObfuscatedFileUtil::ComputeFilePathCost(url.path());
1270   EXPECT_EQ(1024 - path_cost, context->allowed_bytes_growth());
1271
1272   context->set_allowed_bytes_growth(1024);
1273   bool exclusive = true;
1274   bool recursive = true;
1275   url = CreateURLFromUTF8("directory/to/use");
1276   std::vector<base::FilePath::StringType> components;
1277   url.path().GetComponents(&components);
1278   path_cost = 0;
1279   typedef std::vector<base::FilePath::StringType>::iterator iterator;
1280   for (iterator iter = components.begin();
1281        iter != components.end(); ++iter) {
1282     path_cost += ObfuscatedFileUtil::ComputeFilePathCost(
1283         base::FilePath(*iter));
1284   }
1285   context.reset(NewContext(NULL));
1286   context->set_allowed_bytes_growth(1024);
1287   EXPECT_EQ(base::File::FILE_OK,
1288             ofu()->CreateDirectory(context.get(), url, exclusive, recursive));
1289   EXPECT_EQ(1024 - path_cost, context->allowed_bytes_growth());
1290 }
1291
1292 TEST_F(ObfuscatedFileUtilTest, TestCopyOrMoveFileNotFound) {
1293   FileSystemURL source_url = CreateURLFromUTF8("path0.txt");
1294   FileSystemURL dest_url = CreateURLFromUTF8("path1.txt");
1295   scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
1296
1297   bool is_copy_not_move = false;
1298   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
1299             ofu()->CopyOrMoveFile(context.get(), source_url, dest_url,
1300                                   FileSystemOperation::OPTION_NONE,
1301                                   is_copy_not_move));
1302   EXPECT_TRUE(change_observer()->HasNoChange());
1303   context.reset(NewContext(NULL));
1304   is_copy_not_move = true;
1305   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
1306             ofu()->CopyOrMoveFile(context.get(), source_url, dest_url,
1307                                   FileSystemOperation::OPTION_NONE,
1308                                   is_copy_not_move));
1309   EXPECT_TRUE(change_observer()->HasNoChange());
1310   source_url = CreateURLFromUTF8("dir/dir/file");
1311   bool exclusive = true;
1312   bool recursive = true;
1313   context.reset(NewContext(NULL));
1314   ASSERT_EQ(base::File::FILE_OK,
1315             ofu()->CreateDirectory(context.get(),
1316                 FileSystemURLDirName(source_url),
1317                 exclusive, recursive));
1318   EXPECT_EQ(2, change_observer()->get_and_reset_create_directory_count());
1319   is_copy_not_move = false;
1320   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
1321             ofu()->CopyOrMoveFile(context.get(), source_url, dest_url,
1322                                   FileSystemOperation::OPTION_NONE,
1323                                   is_copy_not_move));
1324   EXPECT_TRUE(change_observer()->HasNoChange());
1325   context.reset(NewContext(NULL));
1326   is_copy_not_move = true;
1327   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
1328             ofu()->CopyOrMoveFile(context.get(), source_url, dest_url,
1329                                   FileSystemOperation::OPTION_NONE,
1330                                   is_copy_not_move));
1331   EXPECT_TRUE(change_observer()->HasNoChange());
1332 }
1333
1334 TEST_F(ObfuscatedFileUtilTest, TestCopyOrMoveFileSuccess) {
1335   const int64 kSourceLength = 5;
1336   const int64 kDestLength = 50;
1337
1338   for (size_t i = 0; i < arraysize(kCopyMoveTestCases); ++i) {
1339     SCOPED_TRACE(testing::Message() << "kCopyMoveTestCase " << i);
1340     const CopyMoveTestCaseRecord& test_case = kCopyMoveTestCases[i];
1341     SCOPED_TRACE(testing::Message() << "\t is_copy_not_move " <<
1342       test_case.is_copy_not_move);
1343     SCOPED_TRACE(testing::Message() << "\t source_path " <<
1344       test_case.source_path);
1345     SCOPED_TRACE(testing::Message() << "\t dest_path " <<
1346       test_case.dest_path);
1347     SCOPED_TRACE(testing::Message() << "\t cause_overwrite " <<
1348       test_case.cause_overwrite);
1349     scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
1350
1351     bool exclusive = false;
1352     bool recursive = true;
1353     FileSystemURL source_url = CreateURLFromUTF8(test_case.source_path);
1354     FileSystemURL dest_url = CreateURLFromUTF8(test_case.dest_path);
1355
1356     context.reset(NewContext(NULL));
1357     ASSERT_EQ(base::File::FILE_OK,
1358               ofu()->CreateDirectory(context.get(),
1359                                      FileSystemURLDirName(source_url),
1360                                      exclusive, recursive));
1361     context.reset(NewContext(NULL));
1362     ASSERT_EQ(base::File::FILE_OK,
1363               ofu()->CreateDirectory(context.get(),
1364                                      FileSystemURLDirName(dest_url),
1365                                      exclusive, recursive));
1366
1367     bool created = false;
1368     context.reset(NewContext(NULL));
1369     ASSERT_EQ(base::File::FILE_OK,
1370               ofu()->EnsureFileExists(context.get(), source_url, &created));
1371     ASSERT_TRUE(created);
1372     context.reset(NewContext(NULL));
1373     ASSERT_EQ(base::File::FILE_OK,
1374               ofu()->Truncate(context.get(), source_url, kSourceLength));
1375
1376     if (test_case.cause_overwrite) {
1377       context.reset(NewContext(NULL));
1378       created = false;
1379       ASSERT_EQ(base::File::FILE_OK,
1380                 ofu()->EnsureFileExists(context.get(), dest_url, &created));
1381       ASSERT_TRUE(created);
1382       context.reset(NewContext(NULL));
1383       ASSERT_EQ(base::File::FILE_OK,
1384                 ofu()->Truncate(context.get(), dest_url, kDestLength));
1385     }
1386
1387     context.reset(NewContext(NULL));
1388     EXPECT_EQ(base::File::FILE_OK,
1389               ofu()->CopyOrMoveFile(context.get(), source_url, dest_url,
1390                                     FileSystemOperation::OPTION_NONE,
1391                                     test_case.is_copy_not_move));
1392
1393     if (test_case.is_copy_not_move) {
1394       base::File::Info file_info;
1395       base::FilePath local_path;
1396       context.reset(NewContext(NULL));
1397       EXPECT_EQ(base::File::FILE_OK,
1398                 ofu()->GetFileInfo(context.get(), source_url, &file_info,
1399                                    &local_path));
1400       EXPECT_EQ(kSourceLength, file_info.size);
1401       EXPECT_EQ(base::File::FILE_OK,
1402                 ofu()->DeleteFile(context.get(), source_url));
1403     } else {
1404       base::File::Info file_info;
1405       base::FilePath local_path;
1406       context.reset(NewContext(NULL));
1407       EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
1408                 ofu()->GetFileInfo(context.get(), source_url, &file_info,
1409                                    &local_path));
1410     }
1411     base::File::Info file_info;
1412     base::FilePath local_path;
1413     EXPECT_EQ(base::File::FILE_OK,
1414               ofu()->GetFileInfo(context.get(), dest_url, &file_info,
1415                                  &local_path));
1416     EXPECT_EQ(kSourceLength, file_info.size);
1417
1418     EXPECT_EQ(base::File::FILE_OK,
1419               ofu()->DeleteFile(context.get(), dest_url));
1420   }
1421 }
1422
1423 TEST_F(ObfuscatedFileUtilTest, TestCopyPathQuotas) {
1424   FileSystemURL src_url = CreateURLFromUTF8("src path");
1425   FileSystemURL dest_url = CreateURLFromUTF8("destination path");
1426   scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
1427   bool created = false;
1428   ASSERT_EQ(base::File::FILE_OK,
1429             ofu()->EnsureFileExists(context.get(), src_url, &created));
1430
1431   bool is_copy = true;
1432   // Copy, no overwrite.
1433   context->set_allowed_bytes_growth(
1434       ObfuscatedFileUtil::ComputeFilePathCost(dest_url.path()) - 1);
1435   EXPECT_EQ(base::File::FILE_ERROR_NO_SPACE,
1436             ofu()->CopyOrMoveFile(context.get(), src_url, dest_url,
1437                                   FileSystemOperation::OPTION_NONE, is_copy));
1438   context.reset(NewContext(NULL));
1439   context->set_allowed_bytes_growth(
1440       ObfuscatedFileUtil::ComputeFilePathCost(dest_url.path()));
1441   EXPECT_EQ(base::File::FILE_OK,
1442             ofu()->CopyOrMoveFile(context.get(), src_url, dest_url,
1443                                   FileSystemOperation::OPTION_NONE, is_copy));
1444
1445   // Copy, with overwrite.
1446   context.reset(NewContext(NULL));
1447   context->set_allowed_bytes_growth(0);
1448   EXPECT_EQ(base::File::FILE_OK,
1449             ofu()->CopyOrMoveFile(context.get(), src_url, dest_url,
1450                                   FileSystemOperation::OPTION_NONE, is_copy));
1451 }
1452
1453 TEST_F(ObfuscatedFileUtilTest, TestMovePathQuotasWithRename) {
1454   FileSystemURL src_url = CreateURLFromUTF8("src path");
1455   FileSystemURL dest_url = CreateURLFromUTF8("destination path");
1456   scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
1457   bool created = false;
1458   ASSERT_EQ(base::File::FILE_OK,
1459             ofu()->EnsureFileExists(context.get(), src_url, &created));
1460
1461   bool is_copy = false;
1462   // Move, rename, no overwrite.
1463   context.reset(NewContext(NULL));
1464   context->set_allowed_bytes_growth(
1465       ObfuscatedFileUtil::ComputeFilePathCost(dest_url.path()) -
1466       ObfuscatedFileUtil::ComputeFilePathCost(src_url.path()) - 1);
1467   EXPECT_EQ(base::File::FILE_ERROR_NO_SPACE,
1468             ofu()->CopyOrMoveFile(context.get(), src_url, dest_url,
1469                                   FileSystemOperation::OPTION_NONE, is_copy));
1470   context.reset(NewContext(NULL));
1471   context->set_allowed_bytes_growth(
1472       ObfuscatedFileUtil::ComputeFilePathCost(dest_url.path()) -
1473       ObfuscatedFileUtil::ComputeFilePathCost(src_url.path()));
1474   EXPECT_EQ(base::File::FILE_OK,
1475             ofu()->CopyOrMoveFile(context.get(), src_url, dest_url,
1476                                   FileSystemOperation::OPTION_NONE, is_copy));
1477
1478   context.reset(NewContext(NULL));
1479   ASSERT_EQ(base::File::FILE_OK,
1480             ofu()->EnsureFileExists(context.get(), src_url, &created));
1481
1482   // Move, rename, with overwrite.
1483   context.reset(NewContext(NULL));
1484   context->set_allowed_bytes_growth(0);
1485   EXPECT_EQ(base::File::FILE_OK,
1486             ofu()->CopyOrMoveFile(context.get(), src_url, dest_url,
1487                                   FileSystemOperation::OPTION_NONE, is_copy));
1488 }
1489
1490 TEST_F(ObfuscatedFileUtilTest, TestMovePathQuotasWithoutRename) {
1491   FileSystemURL src_url = CreateURLFromUTF8("src path");
1492   scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
1493   bool created = false;
1494   ASSERT_EQ(base::File::FILE_OK,
1495             ofu()->EnsureFileExists(context.get(), src_url, &created));
1496
1497   bool exclusive = true;
1498   bool recursive = false;
1499   FileSystemURL dir_url = CreateURLFromUTF8("directory path");
1500   context.reset(NewContext(NULL));
1501   ASSERT_EQ(base::File::FILE_OK,
1502             ofu()->CreateDirectory(context.get(), dir_url, exclusive,
1503                                    recursive));
1504
1505   FileSystemURL dest_url = FileSystemURLAppend(
1506       dir_url, src_url.path().value());
1507
1508   bool is_copy = false;
1509   int64 allowed_bytes_growth = -1000;  // Over quota, this should still work.
1510   // Move, no rename, no overwrite.
1511   context.reset(NewContext(NULL));
1512   context->set_allowed_bytes_growth(allowed_bytes_growth);
1513   EXPECT_EQ(base::File::FILE_OK,
1514             ofu()->CopyOrMoveFile(context.get(), src_url, dest_url,
1515                                   FileSystemOperation::OPTION_NONE, is_copy));
1516   EXPECT_EQ(allowed_bytes_growth, context->allowed_bytes_growth());
1517
1518   // Move, no rename, with overwrite.
1519   context.reset(NewContext(NULL));
1520   ASSERT_EQ(base::File::FILE_OK,
1521             ofu()->EnsureFileExists(context.get(), src_url, &created));
1522   context.reset(NewContext(NULL));
1523   context->set_allowed_bytes_growth(allowed_bytes_growth);
1524   EXPECT_EQ(base::File::FILE_OK,
1525             ofu()->CopyOrMoveFile(context.get(), src_url, dest_url,
1526                                   FileSystemOperation::OPTION_NONE, is_copy));
1527   EXPECT_EQ(
1528       allowed_bytes_growth +
1529           ObfuscatedFileUtil::ComputeFilePathCost(src_url.path()),
1530       context->allowed_bytes_growth());
1531 }
1532
1533 TEST_F(ObfuscatedFileUtilTest, TestCopyInForeignFile) {
1534   TestCopyInForeignFileHelper(false /* overwrite */);
1535   TestCopyInForeignFileHelper(true /* overwrite */);
1536 }
1537
1538 TEST_F(ObfuscatedFileUtilTest, TestEnumerator) {
1539   scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
1540   FileSystemURL src_url = CreateURLFromUTF8("source dir");
1541   bool exclusive = true;
1542   bool recursive = false;
1543   ASSERT_EQ(base::File::FILE_OK,
1544             ofu()->CreateDirectory(context.get(), src_url, exclusive,
1545                                    recursive));
1546
1547   std::set<base::FilePath::StringType> files;
1548   std::set<base::FilePath::StringType> directories;
1549   FillTestDirectory(src_url, &files, &directories);
1550
1551   FileSystemURL dest_url = CreateURLFromUTF8("destination dir");
1552
1553   EXPECT_FALSE(DirectoryExists(dest_url));
1554   ASSERT_EQ(base::File::FILE_OK,
1555             AsyncFileTestHelper::Copy(
1556                 file_system_context(), src_url, dest_url));
1557
1558   ValidateTestDirectory(dest_url, files, directories);
1559   EXPECT_TRUE(DirectoryExists(src_url));
1560   EXPECT_TRUE(DirectoryExists(dest_url));
1561   recursive = true;
1562   ASSERT_EQ(base::File::FILE_OK,
1563             AsyncFileTestHelper::Remove(
1564                 file_system_context(), dest_url, recursive));
1565   EXPECT_FALSE(DirectoryExists(dest_url));
1566 }
1567
1568 TEST_F(ObfuscatedFileUtilTest, TestOriginEnumerator) {
1569   scoped_ptr<ObfuscatedFileUtil::AbstractOriginEnumerator>
1570       enumerator(ofu()->CreateOriginEnumerator());
1571   // The test helper starts out with a single filesystem.
1572   EXPECT_TRUE(enumerator.get());
1573   EXPECT_EQ(origin(), enumerator->Next());
1574   ASSERT_TRUE(type() == kFileSystemTypeTemporary);
1575   EXPECT_TRUE(HasFileSystemType(enumerator.get(), kFileSystemTypeTemporary));
1576   EXPECT_FALSE(HasFileSystemType(enumerator.get(), kFileSystemTypePersistent));
1577   EXPECT_EQ(GURL(), enumerator->Next());
1578   EXPECT_FALSE(HasFileSystemType(enumerator.get(), kFileSystemTypeTemporary));
1579   EXPECT_FALSE(HasFileSystemType(enumerator.get(), kFileSystemTypePersistent));
1580
1581   std::set<GURL> origins_expected;
1582   origins_expected.insert(origin());
1583
1584   for (size_t i = 0; i < arraysize(kOriginEnumerationTestRecords); ++i) {
1585     SCOPED_TRACE(testing::Message() <<
1586         "Validating kOriginEnumerationTestRecords " << i);
1587     const OriginEnumerationTestRecord& record =
1588         kOriginEnumerationTestRecords[i];
1589     GURL origin_url(record.origin_url);
1590     origins_expected.insert(origin_url);
1591     if (record.has_temporary) {
1592       scoped_ptr<SandboxFileSystemTestHelper> file_system(
1593           NewFileSystem(origin_url, kFileSystemTypeTemporary));
1594       scoped_ptr<FileSystemOperationContext> context(
1595           NewContext(file_system.get()));
1596       bool created = false;
1597       ASSERT_EQ(base::File::FILE_OK,
1598                 ofu()->EnsureFileExists(
1599                     context.get(),
1600                     file_system->CreateURLFromUTF8("file"),
1601                     &created));
1602       EXPECT_TRUE(created);
1603     }
1604     if (record.has_persistent) {
1605       scoped_ptr<SandboxFileSystemTestHelper> file_system(
1606           NewFileSystem(origin_url, kFileSystemTypePersistent));
1607       scoped_ptr<FileSystemOperationContext> context(
1608           NewContext(file_system.get()));
1609       bool created = false;
1610       ASSERT_EQ(base::File::FILE_OK,
1611                 ofu()->EnsureFileExists(
1612                     context.get(),
1613                     file_system->CreateURLFromUTF8("file"),
1614                     &created));
1615       EXPECT_TRUE(created);
1616     }
1617   }
1618   enumerator.reset(ofu()->CreateOriginEnumerator());
1619   EXPECT_TRUE(enumerator.get());
1620   std::set<GURL> origins_found;
1621   GURL origin_url;
1622   while (!(origin_url = enumerator->Next()).is_empty()) {
1623     origins_found.insert(origin_url);
1624     SCOPED_TRACE(testing::Message() << "Handling " << origin_url.spec());
1625     bool found = false;
1626     for (size_t i = 0; !found && i < arraysize(kOriginEnumerationTestRecords);
1627         ++i) {
1628       const OriginEnumerationTestRecord& record =
1629           kOriginEnumerationTestRecords[i];
1630       if (GURL(record.origin_url) != origin_url)
1631         continue;
1632       found = true;
1633       EXPECT_EQ(record.has_temporary,
1634           HasFileSystemType(enumerator.get(), kFileSystemTypeTemporary));
1635       EXPECT_EQ(record.has_persistent,
1636           HasFileSystemType(enumerator.get(), kFileSystemTypePersistent));
1637     }
1638     // Deal with the default filesystem created by the test helper.
1639     if (!found && origin_url == origin()) {
1640       ASSERT_TRUE(type() == kFileSystemTypeTemporary);
1641       EXPECT_TRUE(HasFileSystemType(enumerator.get(),
1642                                     kFileSystemTypeTemporary));
1643       EXPECT_FALSE(HasFileSystemType(enumerator.get(),
1644                                      kFileSystemTypePersistent));
1645       found = true;
1646     }
1647     EXPECT_TRUE(found);
1648   }
1649
1650   std::set<GURL> diff;
1651   std::set_symmetric_difference(origins_expected.begin(),
1652       origins_expected.end(), origins_found.begin(), origins_found.end(),
1653       inserter(diff, diff.begin()));
1654   EXPECT_TRUE(diff.empty());
1655 }
1656
1657 TEST_F(ObfuscatedFileUtilTest, TestRevokeUsageCache) {
1658   scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
1659
1660   int64 expected_quota = 0;
1661
1662   for (size_t i = 0; i < kRegularFileSystemTestCaseSize; ++i) {
1663     SCOPED_TRACE(testing::Message() << "Creating kRegularTestCase " << i);
1664     const FileSystemTestCaseRecord& test_case =
1665         kRegularFileSystemTestCases[i];
1666     base::FilePath file_path(test_case.path);
1667     expected_quota += ObfuscatedFileUtil::ComputeFilePathCost(file_path);
1668     if (test_case.is_directory) {
1669       bool exclusive = true;
1670       bool recursive = false;
1671       ASSERT_EQ(base::File::FILE_OK,
1672                 ofu()->CreateDirectory(context.get(), CreateURL(file_path),
1673                                        exclusive, recursive));
1674     } else {
1675       bool created = false;
1676       ASSERT_EQ(base::File::FILE_OK,
1677                 ofu()->EnsureFileExists(context.get(), CreateURL(file_path),
1678                                         &created));
1679       ASSERT_TRUE(created);
1680       ASSERT_EQ(base::File::FILE_OK,
1681                 ofu()->Truncate(context.get(), CreateURL(file_path),
1682                                 test_case.data_file_size));
1683       expected_quota += test_case.data_file_size;
1684     }
1685   }
1686
1687   // Usually raw size in usage cache and the usage returned by QuotaUtil
1688   // should be same.
1689   EXPECT_EQ(expected_quota, SizeInUsageFile());
1690   EXPECT_EQ(expected_quota, SizeByQuotaUtil());
1691
1692   RevokeUsageCache();
1693   EXPECT_EQ(-1, SizeInUsageFile());
1694   EXPECT_EQ(expected_quota, SizeByQuotaUtil());
1695
1696   // This should reconstruct the cache.
1697   GetUsageFromQuotaManager();
1698   EXPECT_EQ(expected_quota, SizeInUsageFile());
1699   EXPECT_EQ(expected_quota, SizeByQuotaUtil());
1700   EXPECT_EQ(expected_quota, usage());
1701 }
1702
1703 TEST_F(ObfuscatedFileUtilTest, TestInconsistency) {
1704   const FileSystemURL kPath1 = CreateURLFromUTF8("hoge");
1705   const FileSystemURL kPath2 = CreateURLFromUTF8("fuga");
1706
1707   scoped_ptr<FileSystemOperationContext> context;
1708   base::File::Info file_info;
1709   base::FilePath data_path;
1710   bool created = false;
1711
1712   // Create a non-empty file.
1713   context.reset(NewContext(NULL));
1714   EXPECT_EQ(base::File::FILE_OK,
1715             ofu()->EnsureFileExists(context.get(), kPath1, &created));
1716   EXPECT_TRUE(created);
1717   context.reset(NewContext(NULL));
1718   EXPECT_EQ(base::File::FILE_OK,
1719             ofu()->Truncate(context.get(), kPath1, 10));
1720   context.reset(NewContext(NULL));
1721   EXPECT_EQ(base::File::FILE_OK,
1722             ofu()->GetFileInfo(
1723                 context.get(), kPath1, &file_info, &data_path));
1724   EXPECT_EQ(10, file_info.size);
1725
1726   // Destroy database to make inconsistency between database and filesystem.
1727   ofu()->DestroyDirectoryDatabase(origin(), type_string());
1728
1729   // Try to get file info of broken file.
1730   EXPECT_FALSE(PathExists(kPath1));
1731   context.reset(NewContext(NULL));
1732   EXPECT_EQ(base::File::FILE_OK,
1733             ofu()->EnsureFileExists(context.get(), kPath1, &created));
1734   EXPECT_TRUE(created);
1735   context.reset(NewContext(NULL));
1736   EXPECT_EQ(base::File::FILE_OK,
1737             ofu()->GetFileInfo(
1738                 context.get(), kPath1, &file_info, &data_path));
1739   EXPECT_EQ(0, file_info.size);
1740
1741   // Make another broken file to |kPath2|.
1742   context.reset(NewContext(NULL));
1743   EXPECT_EQ(base::File::FILE_OK,
1744             ofu()->EnsureFileExists(context.get(), kPath2, &created));
1745   EXPECT_TRUE(created);
1746
1747   // Destroy again.
1748   ofu()->DestroyDirectoryDatabase(origin(), type_string());
1749
1750   // Repair broken |kPath1|.
1751   context.reset(NewContext(NULL));
1752   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
1753             ofu()->Touch(context.get(), kPath1, base::Time::Now(),
1754                            base::Time::Now()));
1755   EXPECT_EQ(base::File::FILE_OK,
1756             ofu()->EnsureFileExists(context.get(), kPath1, &created));
1757   EXPECT_TRUE(created);
1758
1759   // Copy from sound |kPath1| to broken |kPath2|.
1760   context.reset(NewContext(NULL));
1761   EXPECT_EQ(base::File::FILE_OK,
1762             ofu()->CopyOrMoveFile(context.get(), kPath1, kPath2,
1763                                   FileSystemOperation::OPTION_NONE,
1764                                   true /* copy */));
1765
1766   ofu()->DestroyDirectoryDatabase(origin(), type_string());
1767   context.reset(NewContext(NULL));
1768   base::File file =
1769       ofu()->CreateOrOpen(context.get(), kPath1,
1770                           base::File::FLAG_READ | base::File::FLAG_CREATE);
1771   EXPECT_TRUE(file.IsValid());
1772   EXPECT_TRUE(file.created());
1773
1774   EXPECT_TRUE(file.GetInfo(&file_info));
1775   EXPECT_EQ(0, file_info.size);
1776 }
1777
1778 TEST_F(ObfuscatedFileUtilTest, TestIncompleteDirectoryReading) {
1779   const FileSystemURL kPath[] = {
1780     CreateURLFromUTF8("foo"),
1781     CreateURLFromUTF8("bar"),
1782     CreateURLFromUTF8("baz")
1783   };
1784   const FileSystemURL empty_path = CreateURL(base::FilePath());
1785   scoped_ptr<FileSystemOperationContext> context;
1786
1787   for (size_t i = 0; i < arraysize(kPath); ++i) {
1788     bool created = false;
1789     context.reset(NewContext(NULL));
1790     EXPECT_EQ(base::File::FILE_OK,
1791               ofu()->EnsureFileExists(context.get(), kPath[i], &created));
1792     EXPECT_TRUE(created);
1793   }
1794
1795   std::vector<storage::DirectoryEntry> entries;
1796   EXPECT_EQ(base::File::FILE_OK,
1797             AsyncFileTestHelper::ReadDirectory(
1798                 file_system_context(), empty_path, &entries));
1799   EXPECT_EQ(3u, entries.size());
1800
1801   base::FilePath local_path;
1802   EXPECT_EQ(base::File::FILE_OK,
1803             ofu()->GetLocalFilePath(context.get(), kPath[0], &local_path));
1804   EXPECT_TRUE(base::DeleteFile(local_path, false));
1805
1806   entries.clear();
1807   EXPECT_EQ(base::File::FILE_OK,
1808             AsyncFileTestHelper::ReadDirectory(
1809                 file_system_context(), empty_path, &entries));
1810   EXPECT_EQ(arraysize(kPath) - 1, entries.size());
1811 }
1812
1813 TEST_F(ObfuscatedFileUtilTest, TestDirectoryTimestampForCreation) {
1814   scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
1815   const FileSystemURL dir_url = CreateURLFromUTF8("foo_dir");
1816
1817   // Create working directory.
1818   EXPECT_EQ(base::File::FILE_OK,
1819             ofu()->CreateDirectory(context.get(), dir_url, false, false));
1820
1821   // EnsureFileExists, create case.
1822   FileSystemURL url(FileSystemURLAppendUTF8(dir_url, "EnsureFileExists_file"));
1823   bool created = false;
1824   ClearTimestamp(dir_url);
1825   context.reset(NewContext(NULL));
1826   EXPECT_EQ(base::File::FILE_OK,
1827             ofu()->EnsureFileExists(context.get(), url, &created));
1828   EXPECT_TRUE(created);
1829   EXPECT_NE(base::Time(), GetModifiedTime(dir_url));
1830
1831   // non create case.
1832   created = true;
1833   ClearTimestamp(dir_url);
1834   context.reset(NewContext(NULL));
1835   EXPECT_EQ(base::File::FILE_OK,
1836             ofu()->EnsureFileExists(context.get(), url, &created));
1837   EXPECT_FALSE(created);
1838   EXPECT_EQ(base::Time(), GetModifiedTime(dir_url));
1839
1840   // fail case.
1841   url = FileSystemURLAppendUTF8(dir_url, "EnsureFileExists_dir");
1842   context.reset(NewContext(NULL));
1843   EXPECT_EQ(base::File::FILE_OK,
1844             ofu()->CreateDirectory(context.get(), url, false, false));
1845
1846   ClearTimestamp(dir_url);
1847   context.reset(NewContext(NULL));
1848   EXPECT_EQ(base::File::FILE_ERROR_NOT_A_FILE,
1849             ofu()->EnsureFileExists(context.get(), url, &created));
1850   EXPECT_EQ(base::Time(), GetModifiedTime(dir_url));
1851
1852   // CreateOrOpen, create case.
1853   url = FileSystemURLAppendUTF8(dir_url, "CreateOrOpen_file");
1854   ClearTimestamp(dir_url);
1855   context.reset(NewContext(NULL));
1856   base::File file =
1857       ofu()->CreateOrOpen(context.get(), url,
1858                           base::File::FLAG_CREATE | base::File::FLAG_WRITE);
1859
1860   EXPECT_TRUE(file.IsValid());
1861   EXPECT_TRUE(file.created());
1862   file.Close();
1863   EXPECT_NE(base::Time(), GetModifiedTime(dir_url));
1864
1865   // open case.
1866   ClearTimestamp(dir_url);
1867   context.reset(NewContext(NULL));
1868   file = ofu()->CreateOrOpen(context.get(), url,
1869                              base::File::FLAG_OPEN | base::File::FLAG_WRITE);
1870   EXPECT_TRUE(file.IsValid());
1871   EXPECT_FALSE(file.created());
1872   file.Close();
1873   EXPECT_EQ(base::Time(), GetModifiedTime(dir_url));
1874
1875   // fail case
1876   ClearTimestamp(dir_url);
1877   context.reset(NewContext(NULL));
1878   file = ofu()->CreateOrOpen(context.get(), url,
1879                              base::File::FLAG_CREATE | base::File::FLAG_WRITE);
1880   EXPECT_FALSE(file.IsValid());
1881   EXPECT_EQ(base::File::FILE_ERROR_EXISTS, file.error_details());
1882   EXPECT_EQ(base::Time(), GetModifiedTime(dir_url));
1883
1884   // CreateDirectory, create case.
1885   // Creating CreateDirectory_dir and CreateDirectory_dir/subdir.
1886   url = FileSystemURLAppendUTF8(dir_url, "CreateDirectory_dir");
1887   FileSystemURL subdir_url(FileSystemURLAppendUTF8(url, "subdir"));
1888   ClearTimestamp(dir_url);
1889   context.reset(NewContext(NULL));
1890   EXPECT_EQ(base::File::FILE_OK,
1891             ofu()->CreateDirectory(context.get(), subdir_url,
1892                                    true /* exclusive */, true /* recursive */));
1893   EXPECT_NE(base::Time(), GetModifiedTime(dir_url));
1894
1895   // create subdir case.
1896   // Creating CreateDirectory_dir/subdir2.
1897   subdir_url = FileSystemURLAppendUTF8(url, "subdir2");
1898   ClearTimestamp(dir_url);
1899   ClearTimestamp(url);
1900   context.reset(NewContext(NULL));
1901   EXPECT_EQ(base::File::FILE_OK,
1902             ofu()->CreateDirectory(context.get(), subdir_url,
1903                                    true /* exclusive */, true /* recursive */));
1904   EXPECT_EQ(base::Time(), GetModifiedTime(dir_url));
1905   EXPECT_NE(base::Time(), GetModifiedTime(url));
1906
1907   // fail case.
1908   url = FileSystemURLAppendUTF8(dir_url, "CreateDirectory_dir");
1909   ClearTimestamp(dir_url);
1910   context.reset(NewContext(NULL));
1911   EXPECT_EQ(base::File::FILE_ERROR_EXISTS,
1912             ofu()->CreateDirectory(context.get(), url,
1913                                    true /* exclusive */, true /* recursive */));
1914   EXPECT_EQ(base::Time(), GetModifiedTime(dir_url));
1915
1916   // CopyInForeignFile, create case.
1917   url = FileSystemURLAppendUTF8(dir_url, "CopyInForeignFile_file");
1918   FileSystemURL src_path = FileSystemURLAppendUTF8(
1919       dir_url, "CopyInForeignFile_src_file");
1920   context.reset(NewContext(NULL));
1921   EXPECT_EQ(base::File::FILE_OK,
1922             ofu()->EnsureFileExists(context.get(), src_path, &created));
1923   EXPECT_TRUE(created);
1924   base::FilePath src_local_path;
1925   context.reset(NewContext(NULL));
1926   EXPECT_EQ(base::File::FILE_OK,
1927             ofu()->GetLocalFilePath(context.get(), src_path, &src_local_path));
1928
1929   ClearTimestamp(dir_url);
1930   context.reset(NewContext(NULL));
1931   EXPECT_EQ(base::File::FILE_OK,
1932             ofu()->CopyInForeignFile(context.get(),
1933                                      src_local_path,
1934                                      url));
1935   EXPECT_NE(base::Time(), GetModifiedTime(dir_url));
1936 }
1937
1938 TEST_F(ObfuscatedFileUtilTest, TestDirectoryTimestampForDeletion) {
1939   scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
1940   const FileSystemURL dir_url = CreateURLFromUTF8("foo_dir");
1941
1942   // Create working directory.
1943   EXPECT_EQ(base::File::FILE_OK,
1944             ofu()->CreateDirectory(context.get(), dir_url, false, false));
1945
1946   // DeleteFile, delete case.
1947   FileSystemURL url = FileSystemURLAppendUTF8(
1948       dir_url, "DeleteFile_file");
1949   bool created = false;
1950   context.reset(NewContext(NULL));
1951   EXPECT_EQ(base::File::FILE_OK,
1952             ofu()->EnsureFileExists(context.get(), url, &created));
1953   EXPECT_TRUE(created);
1954
1955   ClearTimestamp(dir_url);
1956   context.reset(NewContext(NULL));
1957   EXPECT_EQ(base::File::FILE_OK,
1958             ofu()->DeleteFile(context.get(), url));
1959   EXPECT_NE(base::Time(), GetModifiedTime(dir_url));
1960
1961   // fail case.
1962   ClearTimestamp(dir_url);
1963   context.reset(NewContext(NULL));
1964   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
1965             ofu()->DeleteFile(context.get(), url));
1966   EXPECT_EQ(base::Time(), GetModifiedTime(dir_url));
1967
1968   // DeleteDirectory, fail case.
1969   url = FileSystemURLAppendUTF8(dir_url, "DeleteDirectory_dir");
1970   FileSystemURL file_path(FileSystemURLAppendUTF8(url, "pakeratta"));
1971   context.reset(NewContext(NULL));
1972   EXPECT_EQ(base::File::FILE_OK,
1973             ofu()->CreateDirectory(context.get(), url, true, true));
1974   created = false;
1975   context.reset(NewContext(NULL));
1976   EXPECT_EQ(base::File::FILE_OK,
1977             ofu()->EnsureFileExists(context.get(), file_path, &created));
1978   EXPECT_TRUE(created);
1979
1980   ClearTimestamp(dir_url);
1981   context.reset(NewContext(NULL));
1982   EXPECT_EQ(base::File::FILE_ERROR_NOT_EMPTY,
1983             ofu()->DeleteDirectory(context.get(), url));
1984   EXPECT_EQ(base::Time(), GetModifiedTime(dir_url));
1985
1986   // delete case.
1987   context.reset(NewContext(NULL));
1988   EXPECT_EQ(base::File::FILE_OK,
1989             ofu()->DeleteFile(context.get(), file_path));
1990
1991   ClearTimestamp(dir_url);
1992   context.reset(NewContext(NULL));
1993   EXPECT_EQ(base::File::FILE_OK, ofu()->DeleteDirectory(context.get(), url));
1994   EXPECT_NE(base::Time(), GetModifiedTime(dir_url));
1995 }
1996
1997 TEST_F(ObfuscatedFileUtilTest, TestDirectoryTimestampForCopyAndMove) {
1998   TestDirectoryTimestampHelper(
1999       CreateURLFromUTF8("copy overwrite"), true, true);
2000   TestDirectoryTimestampHelper(
2001       CreateURLFromUTF8("copy non-overwrite"), true, false);
2002   TestDirectoryTimestampHelper(
2003       CreateURLFromUTF8("move overwrite"), false, true);
2004   TestDirectoryTimestampHelper(
2005       CreateURLFromUTF8("move non-overwrite"), false, false);
2006 }
2007
2008 TEST_F(ObfuscatedFileUtilTest, TestFileEnumeratorTimestamp) {
2009   FileSystemURL dir = CreateURLFromUTF8("foo");
2010   FileSystemURL url1 = FileSystemURLAppendUTF8(dir, "bar");
2011   FileSystemURL url2 = FileSystemURLAppendUTF8(dir, "baz");
2012
2013   scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
2014   EXPECT_EQ(base::File::FILE_OK,
2015             ofu()->CreateDirectory(context.get(), dir, false, false));
2016
2017   bool created = false;
2018   context.reset(NewContext(NULL));
2019   EXPECT_EQ(base::File::FILE_OK,
2020             ofu()->EnsureFileExists(context.get(), url1, &created));
2021   EXPECT_TRUE(created);
2022
2023   context.reset(NewContext(NULL));
2024   EXPECT_EQ(base::File::FILE_OK,
2025             ofu()->CreateDirectory(context.get(), url2, false, false));
2026
2027   base::FilePath file_path;
2028   context.reset(NewContext(NULL));
2029   EXPECT_EQ(base::File::FILE_OK,
2030             ofu()->GetLocalFilePath(context.get(), url1, &file_path));
2031   EXPECT_FALSE(file_path.empty());
2032
2033   context.reset(NewContext(NULL));
2034   EXPECT_EQ(base::File::FILE_OK,
2035             ofu()->Touch(context.get(), url1,
2036                          base::Time::Now() + base::TimeDelta::FromHours(1),
2037                          base::Time()));
2038
2039   context.reset(NewContext(NULL));
2040   scoped_ptr<storage::FileSystemFileUtil::AbstractFileEnumerator> file_enum(
2041       ofu()->CreateFileEnumerator(context.get(), dir, false));
2042
2043   int count = 0;
2044   base::FilePath file_path_each;
2045   while (!(file_path_each = file_enum->Next()).empty()) {
2046     context.reset(NewContext(NULL));
2047     base::File::Info file_info;
2048     base::FilePath file_path;
2049     EXPECT_EQ(base::File::FILE_OK,
2050               ofu()->GetFileInfo(context.get(),
2051                                  FileSystemURL::CreateForTest(
2052                                      dir.origin(),
2053                                      dir.mount_type(),
2054                                      file_path_each),
2055                                  &file_info, &file_path));
2056     EXPECT_EQ(file_info.is_directory, file_enum->IsDirectory());
2057     EXPECT_EQ(file_info.last_modified, file_enum->LastModifiedTime());
2058     EXPECT_EQ(file_info.size, file_enum->Size());
2059     ++count;
2060   }
2061   EXPECT_EQ(2, count);
2062 }
2063
2064 // crbug.com/176470
2065 #if defined(OS_WIN) || defined(OS_ANDROID)
2066 #define MAYBE_TestQuotaOnCopyFile DISABLED_TestQuotaOnCopyFile
2067 #else
2068 #define MAYBE_TestQuotaOnCopyFile TestQuotaOnCopyFile
2069 #endif
2070 TEST_F(ObfuscatedFileUtilTest, MAYBE_TestQuotaOnCopyFile) {
2071   FileSystemURL from_file(CreateURLFromUTF8("fromfile"));
2072   FileSystemURL obstacle_file(CreateURLFromUTF8("obstaclefile"));
2073   FileSystemURL to_file1(CreateURLFromUTF8("tofile1"));
2074   FileSystemURL to_file2(CreateURLFromUTF8("tofile2"));
2075   bool created;
2076
2077   int64 expected_total_file_size = 0;
2078   ASSERT_EQ(base::File::FILE_OK,
2079             ofu()->EnsureFileExists(
2080                 AllowUsageIncrease(PathCost(from_file))->context(),
2081                 from_file, &created));
2082   ASSERT_TRUE(created);
2083   ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize());
2084
2085   ASSERT_EQ(base::File::FILE_OK,
2086             ofu()->EnsureFileExists(
2087                 AllowUsageIncrease(PathCost(obstacle_file))->context(),
2088                 obstacle_file, &created));
2089   ASSERT_TRUE(created);
2090   ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize());
2091
2092   int64 from_file_size = 1020;
2093   expected_total_file_size += from_file_size;
2094   ASSERT_EQ(base::File::FILE_OK,
2095             ofu()->Truncate(
2096                 AllowUsageIncrease(from_file_size)->context(),
2097                 from_file, from_file_size));
2098   ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize());
2099
2100   int64 obstacle_file_size = 1;
2101   expected_total_file_size += obstacle_file_size;
2102   ASSERT_EQ(base::File::FILE_OK,
2103             ofu()->Truncate(
2104                 AllowUsageIncrease(obstacle_file_size)->context(),
2105                 obstacle_file, obstacle_file_size));
2106   ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize());
2107
2108   int64 to_file1_size = from_file_size;
2109   expected_total_file_size += to_file1_size;
2110   ASSERT_EQ(base::File::FILE_OK,
2111             ofu()->CopyOrMoveFile(
2112                 AllowUsageIncrease(
2113                     PathCost(to_file1) + to_file1_size)->context(),
2114                 from_file, to_file1,
2115                 FileSystemOperation::OPTION_NONE,
2116                 true /* copy */));
2117   ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize());
2118
2119   ASSERT_EQ(base::File::FILE_ERROR_NO_SPACE,
2120             ofu()->CopyOrMoveFile(
2121                 DisallowUsageIncrease(
2122                     PathCost(to_file2) + from_file_size)->context(),
2123                 from_file, to_file2, FileSystemOperation::OPTION_NONE,
2124                 true /* copy */));
2125   ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize());
2126
2127   int64 old_obstacle_file_size = obstacle_file_size;
2128   obstacle_file_size = from_file_size;
2129   expected_total_file_size += obstacle_file_size - old_obstacle_file_size;
2130   ASSERT_EQ(base::File::FILE_OK,
2131             ofu()->CopyOrMoveFile(
2132                 AllowUsageIncrease(
2133                     obstacle_file_size - old_obstacle_file_size)->context(),
2134                 from_file, obstacle_file,
2135                 FileSystemOperation::OPTION_NONE,
2136                 true /* copy */));
2137   ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize());
2138
2139   int64 old_from_file_size = from_file_size;
2140   from_file_size = old_from_file_size - 1;
2141   expected_total_file_size += from_file_size - old_from_file_size;
2142   ASSERT_EQ(base::File::FILE_OK,
2143             ofu()->Truncate(
2144                 AllowUsageIncrease(
2145                     from_file_size - old_from_file_size)->context(),
2146                 from_file, from_file_size));
2147   ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize());
2148
2149   // quota exceeded
2150   {
2151     old_obstacle_file_size = obstacle_file_size;
2152     obstacle_file_size = from_file_size;
2153     expected_total_file_size += obstacle_file_size - old_obstacle_file_size;
2154     scoped_ptr<UsageVerifyHelper> helper = AllowUsageIncrease(
2155         obstacle_file_size - old_obstacle_file_size);
2156     helper->context()->set_allowed_bytes_growth(
2157         helper->context()->allowed_bytes_growth() - 1);
2158     ASSERT_EQ(base::File::FILE_OK,
2159               ofu()->CopyOrMoveFile(
2160                   helper->context(),
2161                   from_file, obstacle_file,
2162                   FileSystemOperation::OPTION_NONE,
2163                   true /* copy */));
2164     ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize());
2165   }
2166 }
2167
2168 TEST_F(ObfuscatedFileUtilTest, TestQuotaOnMoveFile) {
2169   FileSystemURL from_file(CreateURLFromUTF8("fromfile"));
2170   FileSystemURL obstacle_file(CreateURLFromUTF8("obstaclefile"));
2171   FileSystemURL to_file(CreateURLFromUTF8("tofile"));
2172   bool created;
2173
2174   int64 expected_total_file_size = 0;
2175   ASSERT_EQ(base::File::FILE_OK,
2176             ofu()->EnsureFileExists(
2177                 AllowUsageIncrease(PathCost(from_file))->context(),
2178                 from_file, &created));
2179   ASSERT_TRUE(created);
2180   ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize());
2181
2182   int64 from_file_size = 1020;
2183   expected_total_file_size += from_file_size;
2184   ASSERT_EQ(base::File::FILE_OK,
2185             ofu()->Truncate(
2186                 AllowUsageIncrease(from_file_size)->context(),
2187                 from_file, from_file_size));
2188   ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize());
2189
2190   from_file_size = 0;
2191   ASSERT_EQ(base::File::FILE_OK,
2192             ofu()->CopyOrMoveFile(
2193                 AllowUsageIncrease(-PathCost(from_file) +
2194                                    PathCost(to_file))->context(),
2195                 from_file, to_file,
2196                 FileSystemOperation::OPTION_NONE,
2197                 false /* move */));
2198   ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize());
2199
2200   ASSERT_EQ(base::File::FILE_OK,
2201             ofu()->EnsureFileExists(
2202                 AllowUsageIncrease(PathCost(from_file))->context(),
2203                 from_file, &created));
2204   ASSERT_TRUE(created);
2205   ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize());
2206
2207   ASSERT_EQ(base::File::FILE_OK,
2208             ofu()->EnsureFileExists(
2209                 AllowUsageIncrease(PathCost(obstacle_file))->context(),
2210                 obstacle_file, &created));
2211   ASSERT_TRUE(created);
2212   ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize());
2213
2214   from_file_size = 1020;
2215   expected_total_file_size += from_file_size;
2216   ASSERT_EQ(base::File::FILE_OK,
2217             ofu()->Truncate(
2218                 AllowUsageIncrease(from_file_size)->context(),
2219                 from_file, from_file_size));
2220   ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize());
2221
2222   int64 obstacle_file_size = 1;
2223   expected_total_file_size += obstacle_file_size;
2224   ASSERT_EQ(base::File::FILE_OK,
2225             ofu()->Truncate(
2226                 AllowUsageIncrease(1)->context(),
2227                 obstacle_file, obstacle_file_size));
2228   ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize());
2229
2230   int64 old_obstacle_file_size = obstacle_file_size;
2231   obstacle_file_size = from_file_size;
2232   from_file_size = 0;
2233   expected_total_file_size -= old_obstacle_file_size;
2234   ASSERT_EQ(base::File::FILE_OK,
2235             ofu()->CopyOrMoveFile(
2236                 AllowUsageIncrease(
2237                     -old_obstacle_file_size - PathCost(from_file))->context(),
2238                 from_file, obstacle_file,
2239                 FileSystemOperation::OPTION_NONE,
2240                 false /* move */));
2241   ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize());
2242
2243   ASSERT_EQ(base::File::FILE_OK,
2244             ofu()->EnsureFileExists(
2245                 AllowUsageIncrease(PathCost(from_file))->context(),
2246                 from_file, &created));
2247   ASSERT_TRUE(created);
2248   ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize());
2249
2250   from_file_size = 10;
2251   expected_total_file_size += from_file_size;
2252   ASSERT_EQ(base::File::FILE_OK,
2253             ofu()->Truncate(
2254                 AllowUsageIncrease(from_file_size)->context(),
2255                 from_file, from_file_size));
2256   ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize());
2257
2258   // quota exceeded even after operation
2259   old_obstacle_file_size = obstacle_file_size;
2260   obstacle_file_size = from_file_size;
2261   from_file_size = 0;
2262   expected_total_file_size -= old_obstacle_file_size;
2263   scoped_ptr<FileSystemOperationContext> context =
2264       LimitedContext(-old_obstacle_file_size - PathCost(from_file) - 1);
2265   ASSERT_EQ(base::File::FILE_OK,
2266             ofu()->CopyOrMoveFile(
2267                 context.get(), from_file, obstacle_file,
2268                 FileSystemOperation::OPTION_NONE,
2269                 false /* move */));
2270   ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize());
2271   context.reset();
2272 }
2273
2274 TEST_F(ObfuscatedFileUtilTest, TestQuotaOnRemove) {
2275   FileSystemURL dir(CreateURLFromUTF8("dir"));
2276   FileSystemURL file(CreateURLFromUTF8("file"));
2277   FileSystemURL dfile1(CreateURLFromUTF8("dir/dfile1"));
2278   FileSystemURL dfile2(CreateURLFromUTF8("dir/dfile2"));
2279   bool created;
2280
2281   ASSERT_EQ(base::File::FILE_OK,
2282             ofu()->EnsureFileExists(
2283                 AllowUsageIncrease(PathCost(file))->context(),
2284                 file, &created));
2285   ASSERT_TRUE(created);
2286   ASSERT_EQ(0, ComputeTotalFileSize());
2287
2288   ASSERT_EQ(base::File::FILE_OK,
2289             ofu()->CreateDirectory(
2290                 AllowUsageIncrease(PathCost(dir))->context(),
2291                 dir, false, false));
2292   ASSERT_EQ(0, ComputeTotalFileSize());
2293
2294   ASSERT_EQ(base::File::FILE_OK,
2295             ofu()->EnsureFileExists(
2296                 AllowUsageIncrease(PathCost(dfile1))->context(),
2297                 dfile1, &created));
2298   ASSERT_TRUE(created);
2299   ASSERT_EQ(0, ComputeTotalFileSize());
2300
2301   ASSERT_EQ(base::File::FILE_OK,
2302             ofu()->EnsureFileExists(
2303                 AllowUsageIncrease(PathCost(dfile2))->context(),
2304                 dfile2, &created));
2305   ASSERT_TRUE(created);
2306   ASSERT_EQ(0, ComputeTotalFileSize());
2307
2308   ASSERT_EQ(base::File::FILE_OK,
2309             ofu()->Truncate(
2310                 AllowUsageIncrease(340)->context(),
2311                 file, 340));
2312   ASSERT_EQ(340, ComputeTotalFileSize());
2313
2314   ASSERT_EQ(base::File::FILE_OK,
2315             ofu()->Truncate(
2316                 AllowUsageIncrease(1020)->context(),
2317                 dfile1, 1020));
2318   ASSERT_EQ(1360, ComputeTotalFileSize());
2319
2320   ASSERT_EQ(base::File::FILE_OK,
2321             ofu()->Truncate(
2322                 AllowUsageIncrease(120)->context(),
2323                 dfile2, 120));
2324   ASSERT_EQ(1480, ComputeTotalFileSize());
2325
2326   ASSERT_EQ(base::File::FILE_OK,
2327             ofu()->DeleteFile(
2328                 AllowUsageIncrease(-PathCost(file) - 340)->context(),
2329                 file));
2330   ASSERT_EQ(1140, ComputeTotalFileSize());
2331
2332   ASSERT_EQ(base::File::FILE_OK,
2333             AsyncFileTestHelper::Remove(
2334                 file_system_context(), dir, true /* recursive */));
2335   ASSERT_EQ(0, ComputeTotalFileSize());
2336 }
2337
2338 TEST_F(ObfuscatedFileUtilTest, TestQuotaOnOpen) {
2339   FileSystemURL url(CreateURLFromUTF8("file"));
2340
2341   bool created;
2342   // Creating a file.
2343   ASSERT_EQ(base::File::FILE_OK,
2344             ofu()->EnsureFileExists(
2345                 AllowUsageIncrease(PathCost(url))->context(),
2346                 url, &created));
2347   ASSERT_TRUE(created);
2348   ASSERT_EQ(0, ComputeTotalFileSize());
2349
2350   // Opening it, which shouldn't change the usage.
2351   base::File file =
2352       ofu()->CreateOrOpen(AllowUsageIncrease(0)->context(), url,
2353                           base::File::FLAG_OPEN | base::File::FLAG_WRITE);
2354   ASSERT_TRUE(file.IsValid());
2355   ASSERT_EQ(0, ComputeTotalFileSize());
2356   file.Close();
2357
2358   const int length = 33;
2359   ASSERT_EQ(base::File::FILE_OK,
2360             ofu()->Truncate(
2361                 AllowUsageIncrease(length)->context(), url, length));
2362   ASSERT_EQ(length, ComputeTotalFileSize());
2363
2364   // Opening it with CREATE_ALWAYS flag, which should truncate the file size.
2365   file = ofu()->CreateOrOpen(
2366              AllowUsageIncrease(-length)->context(), url,
2367              base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
2368   ASSERT_TRUE(file.IsValid());
2369   ASSERT_EQ(0, ComputeTotalFileSize());
2370   file.Close();
2371
2372   // Extending the file again.
2373   ASSERT_EQ(base::File::FILE_OK,
2374             ofu()->Truncate(
2375                 AllowUsageIncrease(length)->context(), url, length));
2376   ASSERT_EQ(length, ComputeTotalFileSize());
2377
2378   // Opening it with TRUNCATED flag, which should truncate the file size.
2379   file = ofu()->CreateOrOpen(
2380              AllowUsageIncrease(-length)->context(), url,
2381              base::File::FLAG_OPEN_TRUNCATED | base::File::FLAG_WRITE);
2382   ASSERT_TRUE(file.IsValid());
2383   ASSERT_EQ(0, ComputeTotalFileSize());
2384   file.Close();
2385 }
2386
2387 TEST_F(ObfuscatedFileUtilTest, MaybeDropDatabasesAliveCase) {
2388   MaybeDropDatabasesAliveCaseTestBody();
2389 }
2390
2391 TEST_F(ObfuscatedFileUtilTest, MaybeDropDatabasesAlreadyDeletedCase) {
2392   MaybeDropDatabasesAlreadyDeletedCaseTestBody();
2393 }
2394
2395 TEST_F(ObfuscatedFileUtilTest, DestroyDirectoryDatabase_Isolated) {
2396   DestroyDirectoryDatabase_IsolatedTestBody();
2397 }
2398
2399 TEST_F(ObfuscatedFileUtilTest, GetDirectoryDatabase_Isolated) {
2400   GetDirectoryDatabase_IsolatedTestBody();
2401 }
2402
2403 TEST_F(ObfuscatedFileUtilTest, MigrationBackFromIsolated) {
2404   MigrationBackFromIsolatedTestBody();
2405 }
2406
2407 TEST_F(ObfuscatedFileUtilTest, OpenPathInNonDirectory) {
2408   FileSystemURL url(CreateURLFromUTF8("file"));
2409   FileSystemURL path_in_file(CreateURLFromUTF8("file/file"));
2410   bool created;
2411
2412   ASSERT_EQ(base::File::FILE_OK,
2413             ofu()->EnsureFileExists(UnlimitedContext().get(), url, &created));
2414   ASSERT_TRUE(created);
2415
2416   int file_flags = base::File::FLAG_CREATE | base::File::FLAG_WRITE;
2417   base::File file =
2418       ofu()->CreateOrOpen(UnlimitedContext().get(), path_in_file, file_flags);
2419   ASSERT_FALSE(file.IsValid());
2420   ASSERT_EQ(base::File::FILE_ERROR_NOT_A_DIRECTORY, file.error_details());
2421
2422   ASSERT_EQ(base::File::FILE_ERROR_NOT_A_DIRECTORY,
2423             ofu()->CreateDirectory(UnlimitedContext().get(),
2424                                    path_in_file,
2425                                    false /* exclusive */,
2426                                    false /* recursive */));
2427 }
2428
2429 TEST_F(ObfuscatedFileUtilTest, CreateDirectory_NotADirectoryInRecursive) {
2430   FileSystemURL file(CreateURLFromUTF8("file"));
2431   FileSystemURL path_in_file(CreateURLFromUTF8("file/child"));
2432   FileSystemURL path_in_file_in_file(
2433       CreateURLFromUTF8("file/child/grandchild"));
2434   bool created;
2435
2436   ASSERT_EQ(base::File::FILE_OK,
2437             ofu()->EnsureFileExists(UnlimitedContext().get(), file, &created));
2438   ASSERT_TRUE(created);
2439
2440   ASSERT_EQ(base::File::FILE_ERROR_NOT_A_DIRECTORY,
2441             ofu()->CreateDirectory(UnlimitedContext().get(),
2442                                    path_in_file,
2443                                    false /* exclusive */,
2444                                    true /* recursive */));
2445   ASSERT_EQ(base::File::FILE_ERROR_NOT_A_DIRECTORY,
2446             ofu()->CreateDirectory(UnlimitedContext().get(),
2447                                    path_in_file_in_file,
2448                                    false /* exclusive */,
2449                                    true /* recursive */));
2450 }
2451
2452 TEST_F(ObfuscatedFileUtilTest, DeleteDirectoryForOriginAndType) {
2453   const GURL origin1("http://www.example.com:12");
2454   const GURL origin2("http://www.example.com:1234");
2455
2456   // Create origin directories.
2457   scoped_ptr<SandboxFileSystemTestHelper> fs1(
2458       NewFileSystem(origin1, kFileSystemTypeTemporary));
2459   scoped_ptr<SandboxFileSystemTestHelper> fs2(
2460       NewFileSystem(origin1, kFileSystemTypePersistent));
2461   scoped_ptr<SandboxFileSystemTestHelper> fs3(
2462       NewFileSystem(origin2, kFileSystemTypeTemporary));
2463   scoped_ptr<SandboxFileSystemTestHelper> fs4(
2464       NewFileSystem(origin2, kFileSystemTypePersistent));
2465
2466   // Make sure directories for origin1 exist.
2467   base::File::Error error = base::File::FILE_ERROR_FAILED;
2468   ofu()->GetDirectoryForOriginAndType(
2469       origin1, GetTypeString(kFileSystemTypeTemporary), false, &error);
2470   ASSERT_EQ(base::File::FILE_OK, error);
2471   error = base::File::FILE_ERROR_FAILED;
2472   ofu()->GetDirectoryForOriginAndType(
2473       origin1, GetTypeString(kFileSystemTypePersistent), false, &error);
2474   ASSERT_EQ(base::File::FILE_OK, error);
2475
2476   // Make sure directories for origin2 exist.
2477   error = base::File::FILE_ERROR_FAILED;
2478   ofu()->GetDirectoryForOriginAndType(
2479       origin2, GetTypeString(kFileSystemTypeTemporary), false, &error);
2480   ASSERT_EQ(base::File::FILE_OK, error);
2481   error = base::File::FILE_ERROR_FAILED;
2482   ofu()->GetDirectoryForOriginAndType(
2483       origin2, GetTypeString(kFileSystemTypePersistent), false, &error);
2484   ASSERT_EQ(base::File::FILE_OK, error);
2485
2486   // Delete a directory for origin1's persistent filesystem.
2487   ofu()->DeleteDirectoryForOriginAndType(
2488       origin1, GetTypeString(kFileSystemTypePersistent));
2489
2490   // The directory for origin1's temporary filesystem should not be removed.
2491   error = base::File::FILE_ERROR_FAILED;
2492   ofu()->GetDirectoryForOriginAndType(
2493       origin1, GetTypeString(kFileSystemTypeTemporary), false, &error);
2494   ASSERT_EQ(base::File::FILE_OK, error);
2495
2496   // The directory for origin1's persistent filesystem should be removed.
2497   error = base::File::FILE_ERROR_FAILED;
2498   ofu()->GetDirectoryForOriginAndType(
2499       origin1, GetTypeString(kFileSystemTypePersistent), false, &error);
2500   ASSERT_EQ(base::File::FILE_ERROR_NOT_FOUND, error);
2501
2502   // The directories for origin2 should not be removed.
2503   error = base::File::FILE_ERROR_FAILED;
2504   ofu()->GetDirectoryForOriginAndType(
2505       origin2, GetTypeString(kFileSystemTypeTemporary), false, &error);
2506   ASSERT_EQ(base::File::FILE_OK, error);
2507   error = base::File::FILE_ERROR_FAILED;
2508   ofu()->GetDirectoryForOriginAndType(
2509       origin2, GetTypeString(kFileSystemTypePersistent), false, &error);
2510   ASSERT_EQ(base::File::FILE_OK, error);
2511 }
2512
2513 TEST_F(ObfuscatedFileUtilTest, DeleteDirectoryForOriginAndType_DeleteAll) {
2514   const GURL origin1("http://www.example.com:12");
2515   const GURL origin2("http://www.example.com:1234");
2516
2517   // Create origin directories.
2518   scoped_ptr<SandboxFileSystemTestHelper> fs1(
2519       NewFileSystem(origin1, kFileSystemTypeTemporary));
2520   scoped_ptr<SandboxFileSystemTestHelper> fs2(
2521       NewFileSystem(origin1, kFileSystemTypePersistent));
2522   scoped_ptr<SandboxFileSystemTestHelper> fs3(
2523       NewFileSystem(origin2, kFileSystemTypeTemporary));
2524   scoped_ptr<SandboxFileSystemTestHelper> fs4(
2525       NewFileSystem(origin2, kFileSystemTypePersistent));
2526
2527   // Make sure directories for origin1 exist.
2528   base::File::Error error = base::File::FILE_ERROR_FAILED;
2529   ofu()->GetDirectoryForOriginAndType(
2530       origin1, GetTypeString(kFileSystemTypeTemporary), false, &error);
2531   ASSERT_EQ(base::File::FILE_OK, error);
2532   error = base::File::FILE_ERROR_FAILED;
2533   ofu()->GetDirectoryForOriginAndType(
2534       origin1, GetTypeString(kFileSystemTypePersistent), false, &error);
2535   ASSERT_EQ(base::File::FILE_OK, error);
2536
2537   // Make sure directories for origin2 exist.
2538   error = base::File::FILE_ERROR_FAILED;
2539   ofu()->GetDirectoryForOriginAndType(
2540       origin2, GetTypeString(kFileSystemTypeTemporary), false, &error);
2541   ASSERT_EQ(base::File::FILE_OK, error);
2542   error = base::File::FILE_ERROR_FAILED;
2543   ofu()->GetDirectoryForOriginAndType(
2544       origin2, GetTypeString(kFileSystemTypePersistent), false, &error);
2545   ASSERT_EQ(base::File::FILE_OK, error);
2546
2547   // Delete all directories for origin1.
2548   ofu()->DeleteDirectoryForOriginAndType(origin1, std::string());
2549
2550   // The directories for origin1 should be removed.
2551   error = base::File::FILE_ERROR_FAILED;
2552   ofu()->GetDirectoryForOriginAndType(
2553       origin1, GetTypeString(kFileSystemTypeTemporary), false, &error);
2554   ASSERT_EQ(base::File::FILE_ERROR_NOT_FOUND, error);
2555   error = base::File::FILE_ERROR_FAILED;
2556   ofu()->GetDirectoryForOriginAndType(
2557       origin1, GetTypeString(kFileSystemTypePersistent), false, &error);
2558   ASSERT_EQ(base::File::FILE_ERROR_NOT_FOUND, error);
2559
2560   // The directories for origin2 should not be removed.
2561   error = base::File::FILE_ERROR_FAILED;
2562   ofu()->GetDirectoryForOriginAndType(
2563       origin2, GetTypeString(kFileSystemTypeTemporary), false, &error);
2564   ASSERT_EQ(base::File::FILE_OK, error);
2565   error = base::File::FILE_ERROR_FAILED;
2566   ofu()->GetDirectoryForOriginAndType(
2567       origin2, GetTypeString(kFileSystemTypePersistent), false, &error);
2568   ASSERT_EQ(base::File::FILE_OK, error);
2569 }
2570
2571 }  // namespace content