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