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