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