Home | History | Annotate | Download | only in local
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/stl_util.h"
      6 #include "chrome/browser/sync_file_system/local/canned_syncable_file_system.h"
      7 #include "chrome/browser/sync_file_system/local/local_file_change_tracker.h"
      8 #include "chrome/browser/sync_file_system/local/local_file_sync_context.h"
      9 #include "chrome/browser/sync_file_system/local/sync_file_system_backend.h"
     10 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
     11 #include "testing/gtest/include/gtest/gtest.h"
     12 #include "webkit/browser/fileapi/file_system_context.h"
     13 #include "webkit/browser/fileapi/file_system_file_util.h"
     14 #include "webkit/browser/fileapi/file_system_operation_context.h"
     15 #include "webkit/browser/fileapi/isolated_context.h"
     16 #include "webkit/browser/fileapi/sandbox_file_system_test_helper.h"
     17 #include "webkit/browser/quota/quota_manager.h"
     18 #include "webkit/common/fileapi/file_system_types.h"
     19 #include "webkit/common/quota/quota_types.h"
     20 
     21 using base::PlatformFileError;
     22 using fileapi::FileSystemContext;
     23 using fileapi::FileSystemOperationContext;
     24 using fileapi::FileSystemURL;
     25 using fileapi::FileSystemURLSet;
     26 using fileapi::SandboxFileSystemTestHelper;
     27 using quota::QuotaManager;
     28 using quota::QuotaStatusCode;
     29 
     30 namespace sync_file_system {
     31 
     32 class SyncableFileSystemTest : public testing::Test {
     33  public:
     34   SyncableFileSystemTest()
     35       : file_system_(GURL("http://example.com/"),
     36                      base::MessageLoopProxy::current().get(),
     37                      base::MessageLoopProxy::current().get()),
     38         weak_factory_(this) {}
     39 
     40   virtual void SetUp() {
     41     file_system_.SetUp();
     42 
     43     sync_context_ =
     44         new LocalFileSyncContext(base::MessageLoopProxy::current().get(),
     45                                  base::MessageLoopProxy::current().get());
     46     ASSERT_EQ(
     47         sync_file_system::SYNC_STATUS_OK,
     48         file_system_.MaybeInitializeFileSystemContext(sync_context_.get()));
     49   }
     50 
     51   virtual void TearDown() {
     52     if (sync_context_.get())
     53       sync_context_->ShutdownOnUIThread();
     54     sync_context_ = NULL;
     55 
     56     file_system_.TearDown();
     57 
     58     // Make sure we don't leave the external filesystem.
     59     // (CannedSyncableFileSystem::TearDown does not do this as there may be
     60     // multiple syncable file systems registered for the name)
     61     RevokeSyncableFileSystem();
     62   }
     63 
     64  protected:
     65   void VerifyAndClearChange(const FileSystemURL& url,
     66                             const FileChange& expected_change) {
     67     SCOPED_TRACE(testing::Message() << url.DebugString() <<
     68                  " expecting:" << expected_change.DebugString());
     69     // Get the changes for URL and verify.
     70     FileChangeList changes;
     71     change_tracker()->GetChangesForURL(url, &changes);
     72     ASSERT_EQ(1U, changes.size());
     73     SCOPED_TRACE(testing::Message() << url.DebugString() <<
     74                  " actual:" << changes.DebugString());
     75     EXPECT_EQ(expected_change, changes.front());
     76 
     77     // Clear the URL from the change tracker.
     78     change_tracker()->ClearChangesForURL(url);
     79   }
     80 
     81   FileSystemURL URL(const std::string& path) {
     82     return file_system_.URL(path);
     83   }
     84 
     85   FileSystemContext* file_system_context() {
     86     return file_system_.file_system_context();
     87   }
     88 
     89   LocalFileChangeTracker* change_tracker() {
     90     return file_system_.backend()->change_tracker();
     91   }
     92 
     93   ScopedEnableSyncFSDirectoryOperation enable_directory_operation_;
     94 
     95   base::ScopedTempDir data_dir_;
     96   base::MessageLoop message_loop_;
     97 
     98   CannedSyncableFileSystem file_system_;
     99   scoped_refptr<LocalFileSyncContext> sync_context_;
    100 
    101   base::WeakPtrFactory<SyncableFileSystemTest> weak_factory_;
    102 
    103   DISALLOW_COPY_AND_ASSIGN(SyncableFileSystemTest);
    104 };
    105 
    106 // Brief combined testing. Just see if all the sandbox feature works.
    107 TEST_F(SyncableFileSystemTest, SyncableLocalSandboxCombined) {
    108   // Opens a syncable file system.
    109   EXPECT_EQ(base::PLATFORM_FILE_OK,
    110             file_system_.OpenFileSystem());
    111 
    112   // Do some operations.
    113   EXPECT_EQ(base::PLATFORM_FILE_OK,
    114             file_system_.CreateDirectory(URL("dir")));
    115   EXPECT_EQ(base::PLATFORM_FILE_OK,
    116             file_system_.CreateFile(URL("dir/foo")));
    117 
    118   const int64 kOriginalQuota = QuotaManager::kSyncableStorageDefaultHostQuota;
    119 
    120   const int64 kQuota = 12345 * 1024;
    121   QuotaManager::kSyncableStorageDefaultHostQuota = kQuota;
    122   int64 usage, quota;
    123   EXPECT_EQ(quota::kQuotaStatusOk,
    124             file_system_.GetUsageAndQuota(&usage, &quota));
    125 
    126   // Returned quota must be what we overrode. Usage must be greater than 0
    127   // as creating a file or directory consumes some space.
    128   EXPECT_EQ(kQuota, quota);
    129   EXPECT_GT(usage, 0);
    130 
    131   // Truncate to extend an existing file and see if the usage reflects it.
    132   const int64 kFileSizeToExtend = 333;
    133   EXPECT_EQ(base::PLATFORM_FILE_OK,
    134             file_system_.CreateFile(URL("dir/foo")));
    135 
    136   EXPECT_EQ(base::PLATFORM_FILE_OK,
    137             file_system_.TruncateFile(URL("dir/foo"), kFileSizeToExtend));
    138 
    139   int64 new_usage;
    140   EXPECT_EQ(quota::kQuotaStatusOk,
    141             file_system_.GetUsageAndQuota(&new_usage, &quota));
    142   EXPECT_EQ(kFileSizeToExtend, new_usage - usage);
    143 
    144   // Shrink the quota to the current usage, try to extend the file further
    145   // and see if it fails.
    146   QuotaManager::kSyncableStorageDefaultHostQuota = new_usage;
    147   EXPECT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE,
    148             file_system_.TruncateFile(URL("dir/foo"), kFileSizeToExtend + 1));
    149 
    150   usage = new_usage;
    151   EXPECT_EQ(quota::kQuotaStatusOk,
    152             file_system_.GetUsageAndQuota(&new_usage, &quota));
    153   EXPECT_EQ(usage, new_usage);
    154 
    155   // Deletes the file system.
    156   EXPECT_EQ(base::PLATFORM_FILE_OK,
    157             file_system_.DeleteFileSystem());
    158 
    159   // Now the usage must be zero.
    160   EXPECT_EQ(quota::kQuotaStatusOk,
    161             file_system_.GetUsageAndQuota(&usage, &quota));
    162   EXPECT_EQ(0, usage);
    163 
    164   // Restore the system default quota.
    165   QuotaManager::kSyncableStorageDefaultHostQuota = kOriginalQuota;
    166 }
    167 
    168 // Combined testing with LocalFileChangeTracker.
    169 TEST_F(SyncableFileSystemTest, ChangeTrackerSimple) {
    170   EXPECT_EQ(base::PLATFORM_FILE_OK,
    171             file_system_.OpenFileSystem());
    172 
    173   const char kPath0[] = "dir a";
    174   const char kPath1[] = "dir a/dir";   // child of kPath0
    175   const char kPath2[] = "dir a/file";  // child of kPath0
    176   const char kPath3[] = "dir b";
    177 
    178   // Do some operations.
    179   EXPECT_EQ(base::PLATFORM_FILE_OK,
    180             file_system_.CreateDirectory(URL(kPath0)));  // Creates a dir.
    181   EXPECT_EQ(base::PLATFORM_FILE_OK,
    182             file_system_.CreateDirectory(URL(kPath1)));  // Creates another.
    183   EXPECT_EQ(base::PLATFORM_FILE_OK,
    184             file_system_.CreateFile(URL(kPath2)));       // Creates a file.
    185   EXPECT_EQ(base::PLATFORM_FILE_OK,
    186             file_system_.TruncateFile(URL(kPath2), 1));  // Modifies the file.
    187   EXPECT_EQ(base::PLATFORM_FILE_OK,
    188             file_system_.TruncateFile(URL(kPath2), 2));  // Modifies it again.
    189 
    190   FileSystemURLSet urls;
    191   file_system_.GetChangedURLsInTracker(&urls);
    192 
    193   EXPECT_EQ(3U, urls.size());
    194   EXPECT_TRUE(ContainsKey(urls, URL(kPath0)));
    195   EXPECT_TRUE(ContainsKey(urls, URL(kPath1)));
    196   EXPECT_TRUE(ContainsKey(urls, URL(kPath2)));
    197 
    198   VerifyAndClearChange(URL(kPath0),
    199                        FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
    200                                   sync_file_system::SYNC_FILE_TYPE_DIRECTORY));
    201   VerifyAndClearChange(URL(kPath1),
    202                        FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
    203                                   sync_file_system::SYNC_FILE_TYPE_DIRECTORY));
    204   VerifyAndClearChange(URL(kPath2),
    205                        FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
    206                                   sync_file_system::SYNC_FILE_TYPE_FILE));
    207 
    208   // Creates and removes a same directory.
    209   EXPECT_EQ(base::PLATFORM_FILE_OK,
    210             file_system_.CreateDirectory(URL(kPath3)));
    211   EXPECT_EQ(base::PLATFORM_FILE_OK,
    212             file_system_.Remove(URL(kPath3), false /* recursive */));
    213 
    214   // The changes will be offset.
    215   urls.clear();
    216   file_system_.GetChangedURLsInTracker(&urls);
    217   EXPECT_TRUE(urls.empty());
    218 
    219   // Recursively removes the kPath0 directory.
    220   EXPECT_EQ(base::PLATFORM_FILE_OK,
    221             file_system_.Remove(URL(kPath0), true /* recursive */));
    222 
    223   urls.clear();
    224   file_system_.GetChangedURLsInTracker(&urls);
    225 
    226   // kPath0 and its all chidren (kPath1 and kPath2) must have been deleted.
    227   EXPECT_EQ(3U, urls.size());
    228   EXPECT_TRUE(ContainsKey(urls, URL(kPath0)));
    229   EXPECT_TRUE(ContainsKey(urls, URL(kPath1)));
    230   EXPECT_TRUE(ContainsKey(urls, URL(kPath2)));
    231 
    232   VerifyAndClearChange(URL(kPath0),
    233                        FileChange(FileChange::FILE_CHANGE_DELETE,
    234                                   sync_file_system::SYNC_FILE_TYPE_DIRECTORY));
    235   VerifyAndClearChange(URL(kPath1),
    236                        FileChange(FileChange::FILE_CHANGE_DELETE,
    237                                   sync_file_system::SYNC_FILE_TYPE_DIRECTORY));
    238   VerifyAndClearChange(URL(kPath2),
    239                        FileChange(FileChange::FILE_CHANGE_DELETE,
    240                                   sync_file_system::SYNC_FILE_TYPE_FILE));
    241 }
    242 
    243 // Make sure directory operation is disabled (when it's configured so).
    244 TEST_F(SyncableFileSystemTest, DisableDirectoryOperations) {
    245   bool was_enabled = IsSyncFSDirectoryOperationEnabled();
    246   SetEnableSyncFSDirectoryOperation(false);
    247   EXPECT_EQ(base::PLATFORM_FILE_OK,
    248             file_system_.OpenFileSystem());
    249 
    250   // Try some directory operations (which should fail).
    251   EXPECT_EQ(base::PLATFORM_FILE_ERROR_INVALID_OPERATION,
    252             file_system_.CreateDirectory(URL("dir")));
    253 
    254   // Set up another (non-syncable) local file system.
    255   SandboxFileSystemTestHelper other_file_system_(
    256       GURL("http://foo.com/"), fileapi::kFileSystemTypeTemporary);
    257   other_file_system_.SetUp(file_system_.file_system_context());
    258 
    259   // Create directory '/a' and file '/a/b' in the other file system.
    260   const FileSystemURL kSrcDir = other_file_system_.CreateURLFromUTF8("/a");
    261   const FileSystemURL kSrcChild = other_file_system_.CreateURLFromUTF8("/a/b");
    262 
    263   bool created = false;
    264   scoped_ptr<FileSystemOperationContext> operation_context;
    265 
    266   operation_context.reset(other_file_system_.NewOperationContext());
    267   operation_context->set_allowed_bytes_growth(1024);
    268   EXPECT_EQ(base::PLATFORM_FILE_OK,
    269             other_file_system_.file_util()->CreateDirectory(
    270                 operation_context.get(),
    271                 kSrcDir, false /* exclusive */, false /* recursive */));
    272 
    273   operation_context.reset(other_file_system_.NewOperationContext());
    274   operation_context->set_allowed_bytes_growth(1024);
    275   EXPECT_EQ(base::PLATFORM_FILE_OK,
    276             other_file_system_.file_util()->EnsureFileExists(
    277                 operation_context.get(), kSrcChild, &created));
    278   EXPECT_TRUE(created);
    279 
    280   // Now try copying the directory into the syncable file system, which should
    281   // fail if directory operation is disabled. (http://crbug.com/161442)
    282   EXPECT_NE(base::PLATFORM_FILE_OK,
    283             file_system_.Copy(kSrcDir, URL("dest")));
    284 
    285   other_file_system_.TearDown();
    286   SetEnableSyncFSDirectoryOperation(was_enabled);
    287 }
    288 
    289 }  // namespace sync_file_system
    290