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.
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"
24 using base::PlatformFileError
;
25 using content::SandboxFileSystemTestHelper
;
26 using fileapi::FileSystemContext
;
27 using fileapi::FileSystemOperationContext
;
28 using fileapi::FileSystemURL
;
29 using fileapi::FileSystemURLSet
;
30 using quota::QuotaManager
;
31 using quota::QuotaStatusCode
;
33 namespace sync_file_system
{
35 class SyncableFileSystemTest
: public testing::Test
{
37 SyncableFileSystemTest()
38 : in_memory_env_(leveldb::NewMemEnv(leveldb::Env::Default())),
39 file_system_(GURL("http://example.com/"),
41 base::MessageLoopProxy::current().get(),
42 base::MessageLoopProxy::current().get()),
43 weak_factory_(this) {}
45 virtual void SetUp() {
46 ASSERT_TRUE(data_dir_
.CreateUniqueTempDir());
47 file_system_
.SetUp(CannedSyncableFileSystem::QUOTA_ENABLED
);
50 new LocalFileSyncContext(data_dir_
.path(),
52 base::MessageLoopProxy::current().get(),
53 base::MessageLoopProxy::current().get());
55 sync_file_system::SYNC_STATUS_OK
,
56 file_system_
.MaybeInitializeFileSystemContext(sync_context_
.get()));
59 virtual void TearDown() {
60 if (sync_context_
.get())
61 sync_context_
->ShutdownOnUIThread();
64 file_system_
.TearDown();
66 // Make sure we don't leave the external filesystem.
67 // (CannedSyncableFileSystem::TearDown does not do this as there may be
68 // multiple syncable file systems registered for the name)
69 RevokeSyncableFileSystem();
73 void VerifyAndClearChange(const FileSystemURL
& url
,
74 const FileChange
& expected_change
) {
75 SCOPED_TRACE(testing::Message() << url
.DebugString() <<
76 " expecting:" << expected_change
.DebugString());
77 // Get the changes for URL and verify.
78 FileChangeList changes
;
79 change_tracker()->GetChangesForURL(url
, &changes
);
80 ASSERT_EQ(1U, changes
.size());
81 SCOPED_TRACE(testing::Message() << url
.DebugString() <<
82 " actual:" << changes
.DebugString());
83 EXPECT_EQ(expected_change
, changes
.front());
85 // Clear the URL from the change tracker.
86 change_tracker()->ClearChangesForURL(url
);
89 FileSystemURL
URL(const std::string
& path
) {
90 return file_system_
.URL(path
);
93 FileSystemContext
* file_system_context() {
94 return file_system_
.file_system_context();
97 LocalFileChangeTracker
* change_tracker() {
98 return file_system_
.backend()->change_tracker();
101 ScopedEnableSyncFSDirectoryOperation enable_directory_operation_
;
103 base::ScopedTempDir data_dir_
;
104 content::TestBrowserThreadBundle thread_bundle_
;
105 scoped_ptr
<leveldb::Env
> in_memory_env_
;
106 CannedSyncableFileSystem file_system_
;
109 scoped_refptr
<LocalFileSyncContext
> sync_context_
;
111 base::WeakPtrFactory
<SyncableFileSystemTest
> weak_factory_
;
113 DISALLOW_COPY_AND_ASSIGN(SyncableFileSystemTest
);
116 // Brief combined testing. Just see if all the sandbox feature works.
117 TEST_F(SyncableFileSystemTest
, SyncableLocalSandboxCombined
) {
118 // Opens a syncable file system.
119 EXPECT_EQ(base::File::FILE_OK
,
120 file_system_
.OpenFileSystem());
122 // Do some operations.
123 EXPECT_EQ(base::File::FILE_OK
,
124 file_system_
.CreateDirectory(URL("dir")));
125 EXPECT_EQ(base::File::FILE_OK
,
126 file_system_
.CreateFile(URL("dir/foo")));
128 const int64 kOriginalQuota
= QuotaManager::kSyncableStorageDefaultHostQuota
;
130 const int64 kQuota
= 12345 * 1024;
131 QuotaManager::kSyncableStorageDefaultHostQuota
= kQuota
;
133 EXPECT_EQ(quota::kQuotaStatusOk
,
134 file_system_
.GetUsageAndQuota(&usage
, "a
));
136 // Returned quota must be what we overrode. Usage must be greater than 0
137 // as creating a file or directory consumes some space.
138 EXPECT_EQ(kQuota
, quota
);
141 // Truncate to extend an existing file and see if the usage reflects it.
142 const int64 kFileSizeToExtend
= 333;
143 EXPECT_EQ(base::File::FILE_OK
,
144 file_system_
.CreateFile(URL("dir/foo")));
146 EXPECT_EQ(base::File::FILE_OK
,
147 file_system_
.TruncateFile(URL("dir/foo"), kFileSizeToExtend
));
150 EXPECT_EQ(quota::kQuotaStatusOk
,
151 file_system_
.GetUsageAndQuota(&new_usage
, "a
));
152 EXPECT_EQ(kFileSizeToExtend
, new_usage
- usage
);
154 // Shrink the quota to the current usage, try to extend the file further
155 // and see if it fails.
156 QuotaManager::kSyncableStorageDefaultHostQuota
= new_usage
;
157 EXPECT_EQ(base::File::FILE_ERROR_NO_SPACE
,
158 file_system_
.TruncateFile(URL("dir/foo"), kFileSizeToExtend
+ 1));
161 EXPECT_EQ(quota::kQuotaStatusOk
,
162 file_system_
.GetUsageAndQuota(&new_usage
, "a
));
163 EXPECT_EQ(usage
, new_usage
);
165 // Deletes the file system.
166 EXPECT_EQ(base::File::FILE_OK
,
167 file_system_
.DeleteFileSystem());
169 // Now the usage must be zero.
170 EXPECT_EQ(quota::kQuotaStatusOk
,
171 file_system_
.GetUsageAndQuota(&usage
, "a
));
174 // Restore the system default quota.
175 QuotaManager::kSyncableStorageDefaultHostQuota
= kOriginalQuota
;
178 // Combined testing with LocalFileChangeTracker.
179 TEST_F(SyncableFileSystemTest
, ChangeTrackerSimple
) {
180 EXPECT_EQ(base::File::FILE_OK
,
181 file_system_
.OpenFileSystem());
183 const char kPath0
[] = "dir a";
184 const char kPath1
[] = "dir a/dir"; // child of kPath0
185 const char kPath2
[] = "dir a/file"; // child of kPath0
186 const char kPath3
[] = "dir b";
188 // Do some operations.
189 EXPECT_EQ(base::File::FILE_OK
,
190 file_system_
.CreateDirectory(URL(kPath0
))); // Creates a dir.
191 EXPECT_EQ(base::File::FILE_OK
,
192 file_system_
.CreateDirectory(URL(kPath1
))); // Creates another.
193 EXPECT_EQ(base::File::FILE_OK
,
194 file_system_
.CreateFile(URL(kPath2
))); // Creates a file.
195 EXPECT_EQ(base::File::FILE_OK
,
196 file_system_
.TruncateFile(URL(kPath2
), 1)); // Modifies the file.
197 EXPECT_EQ(base::File::FILE_OK
,
198 file_system_
.TruncateFile(URL(kPath2
), 2)); // Modifies it again.
200 FileSystemURLSet urls
;
201 file_system_
.GetChangedURLsInTracker(&urls
);
203 EXPECT_EQ(3U, urls
.size());
204 EXPECT_TRUE(ContainsKey(urls
, URL(kPath0
)));
205 EXPECT_TRUE(ContainsKey(urls
, URL(kPath1
)));
206 EXPECT_TRUE(ContainsKey(urls
, URL(kPath2
)));
208 VerifyAndClearChange(URL(kPath0
),
209 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
210 sync_file_system::SYNC_FILE_TYPE_DIRECTORY
));
211 VerifyAndClearChange(URL(kPath1
),
212 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
213 sync_file_system::SYNC_FILE_TYPE_DIRECTORY
));
214 VerifyAndClearChange(URL(kPath2
),
215 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
216 sync_file_system::SYNC_FILE_TYPE_FILE
));
218 // Creates and removes a same directory.
219 EXPECT_EQ(base::File::FILE_OK
,
220 file_system_
.CreateDirectory(URL(kPath3
)));
221 EXPECT_EQ(base::File::FILE_OK
,
222 file_system_
.Remove(URL(kPath3
), false /* recursive */));
224 // The changes will be offset.
226 file_system_
.GetChangedURLsInTracker(&urls
);
227 EXPECT_TRUE(urls
.empty());
229 // Recursively removes the kPath0 directory.
230 EXPECT_EQ(base::File::FILE_OK
,
231 file_system_
.Remove(URL(kPath0
), true /* recursive */));
234 file_system_
.GetChangedURLsInTracker(&urls
);
236 // kPath0 and its all chidren (kPath1 and kPath2) must have been deleted.
237 EXPECT_EQ(3U, urls
.size());
238 EXPECT_TRUE(ContainsKey(urls
, URL(kPath0
)));
239 EXPECT_TRUE(ContainsKey(urls
, URL(kPath1
)));
240 EXPECT_TRUE(ContainsKey(urls
, URL(kPath2
)));
242 VerifyAndClearChange(URL(kPath0
),
243 FileChange(FileChange::FILE_CHANGE_DELETE
,
244 sync_file_system::SYNC_FILE_TYPE_DIRECTORY
));
245 VerifyAndClearChange(URL(kPath1
),
246 FileChange(FileChange::FILE_CHANGE_DELETE
,
247 sync_file_system::SYNC_FILE_TYPE_DIRECTORY
));
248 VerifyAndClearChange(URL(kPath2
),
249 FileChange(FileChange::FILE_CHANGE_DELETE
,
250 sync_file_system::SYNC_FILE_TYPE_FILE
));
253 // Make sure directory operation is disabled (when it's configured so).
254 TEST_F(SyncableFileSystemTest
, DisableDirectoryOperations
) {
255 bool was_enabled
= IsSyncFSDirectoryOperationEnabled();
256 SetEnableSyncFSDirectoryOperation(false);
257 EXPECT_EQ(base::File::FILE_OK
,
258 file_system_
.OpenFileSystem());
260 // Try some directory operations (which should fail).
261 EXPECT_EQ(base::File::FILE_ERROR_INVALID_OPERATION
,
262 file_system_
.CreateDirectory(URL("dir")));
264 // Set up another (non-syncable) local file system.
265 SandboxFileSystemTestHelper
other_file_system_(
266 GURL("http://foo.com/"), fileapi::kFileSystemTypeTemporary
);
267 other_file_system_
.SetUp(file_system_
.file_system_context());
269 // Create directory '/a' and file '/a/b' in the other file system.
270 const FileSystemURL kSrcDir
= other_file_system_
.CreateURLFromUTF8("/a");
271 const FileSystemURL kSrcChild
= other_file_system_
.CreateURLFromUTF8("/a/b");
273 EXPECT_EQ(base::File::FILE_OK
,
274 content::AsyncFileTestHelper::CreateDirectory(
275 other_file_system_
.file_system_context(), kSrcDir
));
276 EXPECT_EQ(base::File::FILE_OK
,
277 content::AsyncFileTestHelper::CreateFile(
278 other_file_system_
.file_system_context(), kSrcChild
));
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::File::FILE_OK
,
283 file_system_
.Copy(kSrcDir
, URL("dest")));
285 other_file_system_
.TearDown();
286 SetEnableSyncFSDirectoryOperation(was_enabled
);
289 } // namespace sync_file_system