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, "a)); 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, "a)); 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, "a)); 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, "a)); 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