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