1 // Copyright (c) 2012 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 "testing/gtest/include/gtest/gtest.h"
7 #include "webkit/fileapi/file_system_context.h"
8 #include "webkit/fileapi/file_system_file_util.h"
9 #include "webkit/fileapi/file_system_operation_context.h"
10 #include "webkit/fileapi/file_system_task_runners.h"
11 #include "webkit/fileapi/file_system_types.h"
12 #include "webkit/fileapi/isolated_context.h"
13 #include "webkit/fileapi/local_file_system_operation.h"
14 #include "webkit/fileapi/local_file_system_test_helper.h"
15 #include "webkit/fileapi/syncable/canned_syncable_file_system.h"
16 #include "webkit/fileapi/syncable/local_file_change_tracker.h"
17 #include "webkit/fileapi/syncable/local_file_sync_context.h"
18 #include "webkit/fileapi/syncable/syncable_file_system_util.h"
19 #include "webkit/quota/quota_manager.h"
20 #include "webkit/quota/quota_types.h"
22 using base::PlatformFileError
;
23 using fileapi::FileSystemContext
;
24 using fileapi::FileSystemOperationContext
;
25 using fileapi::FileSystemURL
;
26 using fileapi::FileSystemURLSet
;
27 using fileapi::LocalFileSystemTestOriginHelper
;
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/"), "test",
37 base::MessageLoopProxy::current(),
38 base::MessageLoopProxy::current()),
39 weak_factory_(this) {}
41 virtual void SetUp() {
44 sync_context_
= new LocalFileSyncContext(base::MessageLoopProxy::current(),
45 base::MessageLoopProxy::current());
46 ASSERT_EQ(sync_file_system::SYNC_STATUS_OK
,
47 file_system_
.MaybeInitializeFileSystemContext(sync_context_
));
50 virtual void TearDown() {
52 sync_context_
->ShutdownOnUIThread();
55 file_system_
.TearDown();
57 // Make sure we don't leave the external filesystem.
58 // (CannedSyncableFileSystem::TearDown does not do this as there may be
59 // multiple syncable file systems registered for the name)
60 RevokeSyncableFileSystem("test");
64 void VerifyAndClearChange(const FileSystemURL
& url
,
65 const FileChange
& expected_change
) {
66 SCOPED_TRACE(testing::Message() << url
.DebugString() <<
67 " expecting:" << expected_change
.DebugString());
68 // Get the changes for URL and verify.
69 FileChangeList changes
;
70 change_tracker()->GetChangesForURL(url
, &changes
);
71 ASSERT_EQ(1U, changes
.size());
72 SCOPED_TRACE(testing::Message() << url
.DebugString() <<
73 " actual:" << changes
.DebugString());
74 EXPECT_EQ(expected_change
, changes
.front());
76 // Clear the URL from the change tracker.
77 change_tracker()->ClearChangesForURL(url
);
80 FileSystemURL
URL(const std::string
& path
) {
81 return file_system_
.URL(path
);
84 FileSystemContext
* file_system_context() {
85 return file_system_
.file_system_context();
88 LocalFileChangeTracker
* change_tracker() {
89 return file_system_context()->change_tracker();
92 base::ScopedTempDir data_dir_
;
93 base::MessageLoop message_loop_
;
95 CannedSyncableFileSystem file_system_
;
96 scoped_refptr
<LocalFileSyncContext
> sync_context_
;
98 base::WeakPtrFactory
<SyncableFileSystemTest
> weak_factory_
;
100 DISALLOW_COPY_AND_ASSIGN(SyncableFileSystemTest
);
103 // Brief combined testing. Just see if all the sandbox feature works.
104 TEST_F(SyncableFileSystemTest
, SyncableLocalSandboxCombined
) {
105 // Opens a syncable file system.
106 EXPECT_EQ(base::PLATFORM_FILE_OK
,
107 file_system_
.OpenFileSystem());
109 // Do some operations.
110 EXPECT_EQ(base::PLATFORM_FILE_OK
,
111 file_system_
.CreateDirectory(URL("dir")));
112 EXPECT_EQ(base::PLATFORM_FILE_OK
,
113 file_system_
.CreateFile(URL("dir/foo")));
115 const int64 kOriginalQuota
= QuotaManager::kSyncableStorageDefaultHostQuota
;
117 const int64 kQuota
= 12345 * 1024;
118 QuotaManager::kSyncableStorageDefaultHostQuota
= kQuota
;
120 EXPECT_EQ(quota::kQuotaStatusOk
,
121 file_system_
.GetUsageAndQuota(&usage
, "a
));
123 // Returned quota must be what we overrode. Usage must be greater than 0
124 // as creating a file or directory consumes some space.
125 EXPECT_EQ(kQuota
, quota
);
128 // Truncate to extend an existing file and see if the usage reflects it.
129 const int64 kFileSizeToExtend
= 333;
130 EXPECT_EQ(base::PLATFORM_FILE_OK
,
131 file_system_
.CreateFile(URL("dir/foo")));
133 EXPECT_EQ(base::PLATFORM_FILE_OK
,
134 file_system_
.TruncateFile(URL("dir/foo"), kFileSizeToExtend
));
137 EXPECT_EQ(quota::kQuotaStatusOk
,
138 file_system_
.GetUsageAndQuota(&new_usage
, "a
));
139 EXPECT_EQ(kFileSizeToExtend
, new_usage
- usage
);
141 // Shrink the quota to the current usage, try to extend the file further
142 // and see if it fails.
143 QuotaManager::kSyncableStorageDefaultHostQuota
= new_usage
;
144 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE
,
145 file_system_
.TruncateFile(URL("dir/foo"), kFileSizeToExtend
+ 1));
148 EXPECT_EQ(quota::kQuotaStatusOk
,
149 file_system_
.GetUsageAndQuota(&new_usage
, "a
));
150 EXPECT_EQ(usage
, new_usage
);
152 // Deletes the file system.
153 EXPECT_EQ(base::PLATFORM_FILE_OK
,
154 file_system_
.DeleteFileSystem());
156 // Now the usage must be zero.
157 EXPECT_EQ(quota::kQuotaStatusOk
,
158 file_system_
.GetUsageAndQuota(&usage
, "a
));
161 // Restore the system default quota.
162 QuotaManager::kSyncableStorageDefaultHostQuota
= kOriginalQuota
;
165 // Combined testing with LocalFileChangeTracker.
166 TEST_F(SyncableFileSystemTest
, ChangeTrackerSimple
) {
167 EXPECT_EQ(base::PLATFORM_FILE_OK
,
168 file_system_
.OpenFileSystem());
170 const char kPath0
[] = "dir a";
171 const char kPath1
[] = "dir a/dir"; // child of kPath0
172 const char kPath2
[] = "dir a/file"; // child of kPath0
173 const char kPath3
[] = "dir b";
175 // Do some operations.
176 EXPECT_EQ(base::PLATFORM_FILE_OK
,
177 file_system_
.CreateDirectory(URL(kPath0
))); // Creates a dir.
178 EXPECT_EQ(base::PLATFORM_FILE_OK
,
179 file_system_
.CreateDirectory(URL(kPath1
))); // Creates another.
180 EXPECT_EQ(base::PLATFORM_FILE_OK
,
181 file_system_
.CreateFile(URL(kPath2
))); // Creates a file.
182 EXPECT_EQ(base::PLATFORM_FILE_OK
,
183 file_system_
.TruncateFile(URL(kPath2
), 1)); // Modifies the file.
184 EXPECT_EQ(base::PLATFORM_FILE_OK
,
185 file_system_
.TruncateFile(URL(kPath2
), 2)); // Modifies it again.
187 FileSystemURLSet urls
;
188 file_system_
.GetChangedURLsInTracker(&urls
);
190 EXPECT_EQ(3U, urls
.size());
191 EXPECT_TRUE(ContainsKey(urls
, URL(kPath0
)));
192 EXPECT_TRUE(ContainsKey(urls
, URL(kPath1
)));
193 EXPECT_TRUE(ContainsKey(urls
, URL(kPath2
)));
195 VerifyAndClearChange(URL(kPath0
),
196 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
197 sync_file_system::SYNC_FILE_TYPE_DIRECTORY
));
198 VerifyAndClearChange(URL(kPath1
),
199 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
200 sync_file_system::SYNC_FILE_TYPE_DIRECTORY
));
201 VerifyAndClearChange(URL(kPath2
),
202 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
203 sync_file_system::SYNC_FILE_TYPE_FILE
));
205 // Creates and removes a same directory.
206 EXPECT_EQ(base::PLATFORM_FILE_OK
,
207 file_system_
.CreateDirectory(URL(kPath3
)));
208 EXPECT_EQ(base::PLATFORM_FILE_OK
,
209 file_system_
.Remove(URL(kPath3
), false /* recursive */));
211 // The changes will be offset.
213 file_system_
.GetChangedURLsInTracker(&urls
);
214 EXPECT_TRUE(urls
.empty());
216 // Recursively removes the kPath0 directory.
217 EXPECT_EQ(base::PLATFORM_FILE_OK
,
218 file_system_
.Remove(URL(kPath0
), true /* recursive */));
221 file_system_
.GetChangedURLsInTracker(&urls
);
223 // kPath0 and its all chidren (kPath1 and kPath2) must have been deleted.
224 EXPECT_EQ(3U, urls
.size());
225 EXPECT_TRUE(ContainsKey(urls
, URL(kPath0
)));
226 EXPECT_TRUE(ContainsKey(urls
, URL(kPath1
)));
227 EXPECT_TRUE(ContainsKey(urls
, URL(kPath2
)));
229 VerifyAndClearChange(URL(kPath0
),
230 FileChange(FileChange::FILE_CHANGE_DELETE
,
231 sync_file_system::SYNC_FILE_TYPE_DIRECTORY
));
232 VerifyAndClearChange(URL(kPath1
),
233 FileChange(FileChange::FILE_CHANGE_DELETE
,
234 sync_file_system::SYNC_FILE_TYPE_DIRECTORY
));
235 VerifyAndClearChange(URL(kPath2
),
236 FileChange(FileChange::FILE_CHANGE_DELETE
,
237 sync_file_system::SYNC_FILE_TYPE_FILE
));
240 // Make sure directory operation is disabled (when it's configured so).
241 TEST_F(SyncableFileSystemTest
, DisableDirectoryOperations
) {
242 SetEnableSyncFSDirectoryOperation(false);
243 EXPECT_EQ(base::PLATFORM_FILE_OK
,
244 file_system_
.OpenFileSystem());
246 // Try some directory operations (which should fail).
247 EXPECT_EQ(base::PLATFORM_FILE_ERROR_INVALID_OPERATION
,
248 file_system_
.CreateDirectory(URL("dir")));
250 // Set up another (non-syncable) local file system.
251 LocalFileSystemTestOriginHelper
other_file_system_(
252 GURL("http://foo.com/"), fileapi::kFileSystemTypeTemporary
);
253 other_file_system_
.SetUp(file_system_
.file_system_context());
255 // Create directory '/a' and file '/a/b' in the other file system.
256 const FileSystemURL kSrcDir
= other_file_system_
.CreateURLFromUTF8("/a");
257 const FileSystemURL kSrcChild
= other_file_system_
.CreateURLFromUTF8("/a/b");
259 bool created
= false;
260 scoped_ptr
<FileSystemOperationContext
> operation_context
;
262 operation_context
.reset(other_file_system_
.NewOperationContext());
263 operation_context
->set_allowed_bytes_growth(1024);
264 EXPECT_EQ(base::PLATFORM_FILE_OK
,
265 other_file_system_
.file_util()->CreateDirectory(
266 operation_context
.get(),
267 kSrcDir
, false /* exclusive */, false /* recursive */));
269 operation_context
.reset(other_file_system_
.NewOperationContext());
270 operation_context
->set_allowed_bytes_growth(1024);
271 EXPECT_EQ(base::PLATFORM_FILE_OK
,
272 other_file_system_
.file_util()->EnsureFileExists(
273 operation_context
.get(), kSrcChild
, &created
));
274 EXPECT_TRUE(created
);
276 // Now try copying the directory into the syncable file system, which should
277 // fail if directory operation is disabled. (http://crbug.com/161442)
278 EXPECT_NE(base::PLATFORM_FILE_OK
,
279 file_system_
.Copy(kSrcDir
, URL("dest")));
281 other_file_system_
.TearDown();
284 } // namespace sync_file_system