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