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 "chrome/browser/sync_file_system/local/local_file_change_tracker.h"
10 #include "base/basictypes.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/message_loop/message_loop_proxy.h"
15 #include "base/stl_util.h"
16 #include "chrome/browser/sync_file_system/local/canned_syncable_file_system.h"
17 #include "chrome/browser/sync_file_system/local/local_file_sync_context.h"
18 #include "chrome/browser/sync_file_system/local/sync_file_system_backend.h"
19 #include "chrome/browser/sync_file_system/sync_status_code.h"
20 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 #include "webkit/browser/blob/mock_blob_url_request_context.h"
23 #include "webkit/browser/fileapi/file_system_context.h"
24 #include "webkit/browser/quota/quota_manager.h"
26 using fileapi::FileSystemContext
;
27 using fileapi::FileSystemURL
;
28 using fileapi::FileSystemURLSet
;
29 using webkit_blob::MockBlobURLRequestContext
;
30 using webkit_blob::ScopedTextBlob
;
32 namespace sync_file_system
{
34 class LocalFileChangeTrackerTest
: public testing::Test
{
36 LocalFileChangeTrackerTest()
37 : file_system_(GURL("http://example.com"),
38 base::MessageLoopProxy::current().get(),
39 base::MessageLoopProxy::current().get()) {}
41 virtual void SetUp() OVERRIDE
{
45 new LocalFileSyncContext(base::FilePath(),
46 base::MessageLoopProxy::current().get(),
47 base::MessageLoopProxy::current().get());
49 sync_file_system::SYNC_STATUS_OK
,
50 file_system_
.MaybeInitializeFileSystemContext(sync_context_
.get()));
53 virtual void TearDown() OVERRIDE
{
54 if (sync_context_
.get())
55 sync_context_
->ShutdownOnUIThread();
58 message_loop_
.RunUntilIdle();
59 file_system_
.TearDown();
60 // Make sure we don't leave the external filesystem.
61 // (CannedSyncableFileSystem::TearDown does not do this as there may be
62 // multiple syncable file systems registered for the name)
63 RevokeSyncableFileSystem();
67 FileSystemURL
URL(const std::string
& path
) {
68 return file_system_
.URL(path
);
71 FileSystemContext
* file_system_context() {
72 return file_system_
.file_system_context();
75 LocalFileChangeTracker
* change_tracker() {
76 return file_system_
.backend()->change_tracker();
79 void VerifyAndClearChange(const FileSystemURL
& url
,
80 const FileChange
& expected_change
) {
81 SCOPED_TRACE(testing::Message() << url
.DebugString() <<
82 " expecting:" << expected_change
.DebugString());
83 // Get the changes for URL and verify.
84 FileChangeList changes
;
85 change_tracker()->GetChangesForURL(url
, &changes
);
86 ASSERT_EQ(1U, changes
.size());
87 SCOPED_TRACE(testing::Message() << url
.DebugString() <<
88 " actual:" << changes
.DebugString());
89 EXPECT_EQ(expected_change
, changes
.list()[0]);
91 // Clear the URL from the change tracker.
92 change_tracker()->ClearChangesForURL(url
);
95 void DropChangesInTracker() {
96 change_tracker()->DropAllChanges();
99 void RestoreChangesFromTrackerDB() {
100 change_tracker()->CollectLastDirtyChanges(file_system_context());
103 void GetAllChangedURLs(fileapi::FileSystemURLSet
* urls
) {
104 change_tracker()->GetAllChangedURLs(urls
);
107 ScopedEnableSyncFSDirectoryOperation enable_directory_operation_
;
108 base::MessageLoopForIO message_loop_
;
109 CannedSyncableFileSystem file_system_
;
112 scoped_refptr
<LocalFileSyncContext
> sync_context_
;
114 DISALLOW_COPY_AND_ASSIGN(LocalFileChangeTrackerTest
);
117 TEST_F(LocalFileChangeTrackerTest
, GetChanges
) {
118 EXPECT_EQ(base::PLATFORM_FILE_OK
, file_system_
.OpenFileSystem());
120 // Test URLs (no parent/child relationships, as we test such cases
121 // mainly in LocalFileSyncStatusTest).
122 const char kPath0
[] = "test/dir a/dir";
123 const char kPath1
[] = "test/dir b";
124 const char kPath2
[] = "test/foo.txt";
125 const char kPath3
[] = "test/bar";
126 const char kPath4
[] = "temporary/dir a";
127 const char kPath5
[] = "temporary/foo";
129 change_tracker()->OnCreateDirectory(URL(kPath0
));
130 change_tracker()->OnRemoveDirectory(URL(kPath0
)); // Offset the create.
131 change_tracker()->OnRemoveDirectory(URL(kPath1
));
132 change_tracker()->OnCreateDirectory(URL(kPath2
));
133 change_tracker()->OnRemoveFile(URL(kPath3
));
134 change_tracker()->OnModifyFile(URL(kPath4
));
135 change_tracker()->OnCreateFile(URL(kPath5
));
136 change_tracker()->OnRemoveFile(URL(kPath5
)); // Recorded as 'delete'.
138 FileSystemURLSet urls
;
139 file_system_
.GetChangedURLsInTracker(&urls
);
141 EXPECT_EQ(5U, urls
.size());
142 EXPECT_TRUE(ContainsKey(urls
, URL(kPath1
)));
143 EXPECT_TRUE(ContainsKey(urls
, URL(kPath2
)));
144 EXPECT_TRUE(ContainsKey(urls
, URL(kPath3
)));
145 EXPECT_TRUE(ContainsKey(urls
, URL(kPath4
)));
146 EXPECT_TRUE(ContainsKey(urls
, URL(kPath5
)));
148 // Changes for kPath0 must have been offset and removed.
149 EXPECT_FALSE(ContainsKey(urls
, URL(kPath0
)));
151 // GetNextChangedURLs only returns up to max_urls (i.e. 3) urls.
152 std::deque
<FileSystemURL
> urls_to_process
;
153 change_tracker()->GetNextChangedURLs(&urls_to_process
, 3);
154 ASSERT_EQ(3U, urls_to_process
.size());
156 // Let it return all.
157 urls_to_process
.clear();
158 change_tracker()->GetNextChangedURLs(&urls_to_process
, 0);
159 ASSERT_EQ(5U, urls_to_process
.size());
161 // The changes must be in the last-modified-time order.
162 EXPECT_EQ(URL(kPath1
), urls_to_process
[0]);
163 EXPECT_EQ(URL(kPath2
), urls_to_process
[1]);
164 EXPECT_EQ(URL(kPath3
), urls_to_process
[2]);
165 EXPECT_EQ(URL(kPath4
), urls_to_process
[3]);
166 EXPECT_EQ(URL(kPath5
), urls_to_process
[4]);
168 // Modify kPath4 again.
169 change_tracker()->OnModifyFile(URL(kPath4
));
171 // Now the order must be changed.
172 urls_to_process
.clear();
173 change_tracker()->GetNextChangedURLs(&urls_to_process
, 0);
174 ASSERT_EQ(5U, urls_to_process
.size());
175 EXPECT_EQ(URL(kPath1
), urls_to_process
[0]);
176 EXPECT_EQ(URL(kPath2
), urls_to_process
[1]);
177 EXPECT_EQ(URL(kPath3
), urls_to_process
[2]);
178 EXPECT_EQ(URL(kPath5
), urls_to_process
[3]);
179 EXPECT_EQ(URL(kPath4
), urls_to_process
[4]);
181 // No changes to promote yet, we've demoted no changes.
182 EXPECT_FALSE(change_tracker()->PromoteDemotedChanges());
184 // Demote changes for kPath1 and kPath3.
185 change_tracker()->DemoteChangesForURL(URL(kPath1
));
186 change_tracker()->DemoteChangesForURL(URL(kPath3
));
188 // Now we'll get no changes for kPath1 and kPath3 (it's in a separate queue).
189 urls_to_process
.clear();
190 change_tracker()->GetNextChangedURLs(&urls_to_process
, 0);
191 ASSERT_EQ(3U, urls_to_process
.size());
192 EXPECT_EQ(URL(kPath2
), urls_to_process
[0]);
193 EXPECT_EQ(URL(kPath5
), urls_to_process
[1]);
194 EXPECT_EQ(URL(kPath4
), urls_to_process
[2]);
197 EXPECT_TRUE(change_tracker()->PromoteDemotedChanges());
199 // Now we should have kPath1 and kPath3.
200 urls_to_process
.clear();
201 change_tracker()->GetNextChangedURLs(&urls_to_process
, 0);
202 ASSERT_EQ(5U, urls_to_process
.size());
203 EXPECT_EQ(URL(kPath2
), urls_to_process
[0]);
204 EXPECT_EQ(URL(kPath5
), urls_to_process
[1]);
205 EXPECT_EQ(URL(kPath4
), urls_to_process
[2]);
206 EXPECT_TRUE(URL(kPath1
) == urls_to_process
[3] ||
207 URL(kPath1
) == urls_to_process
[4]);
208 EXPECT_TRUE(URL(kPath3
) == urls_to_process
[3] ||
209 URL(kPath3
) == urls_to_process
[4]);
211 // No changes to promote any more.
212 EXPECT_FALSE(change_tracker()->PromoteDemotedChanges());
215 VerifyAndClearChange(URL(kPath1
),
216 FileChange(FileChange::FILE_CHANGE_DELETE
,
217 sync_file_system::SYNC_FILE_TYPE_DIRECTORY
));
218 VerifyAndClearChange(URL(kPath2
),
219 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
220 sync_file_system::SYNC_FILE_TYPE_DIRECTORY
));
221 VerifyAndClearChange(URL(kPath3
),
222 FileChange(FileChange::FILE_CHANGE_DELETE
,
223 sync_file_system::SYNC_FILE_TYPE_FILE
));
224 VerifyAndClearChange(URL(kPath4
),
225 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
226 sync_file_system::SYNC_FILE_TYPE_FILE
));
227 VerifyAndClearChange(URL(kPath5
),
228 FileChange(FileChange::FILE_CHANGE_DELETE
,
229 sync_file_system::SYNC_FILE_TYPE_FILE
));
232 TEST_F(LocalFileChangeTrackerTest
, RestoreCreateAndModifyChanges
) {
233 EXPECT_EQ(base::PLATFORM_FILE_OK
, file_system_
.OpenFileSystem());
235 FileSystemURLSet urls
;
237 const char kPath0
[] = "file a";
238 const char kPath1
[] = "dir a";
239 const char kPath2
[] = "dir a/dir";
240 const char kPath3
[] = "dir a/file a";
241 const char kPath4
[] = "dir a/file b";
243 file_system_
.GetChangedURLsInTracker(&urls
);
244 ASSERT_EQ(0U, urls
.size());
246 const std::string
kData("Lorem ipsum.");
247 MockBlobURLRequestContext
url_request_context(file_system_context());
248 ScopedTextBlob
blob(url_request_context
, "blob_id:test", kData
);
250 // Create files and nested directories.
251 EXPECT_EQ(base::PLATFORM_FILE_OK
,
252 file_system_
.CreateFile(URL(kPath0
))); // Creates a file.
253 EXPECT_EQ(base::PLATFORM_FILE_OK
,
254 file_system_
.CreateDirectory(URL(kPath1
))); // Creates a dir.
255 EXPECT_EQ(base::PLATFORM_FILE_OK
,
256 file_system_
.CreateDirectory(URL(kPath2
))); // Creates another dir.
257 EXPECT_EQ(base::PLATFORM_FILE_OK
,
258 file_system_
.CreateFile(URL(kPath3
))); // Creates a file.
259 EXPECT_EQ(base::PLATFORM_FILE_OK
,
260 file_system_
.TruncateFile(URL(kPath3
), 1)); // Modifies the file.
261 EXPECT_EQ(base::PLATFORM_FILE_OK
,
262 file_system_
.CreateFile(URL(kPath4
))); // Creates another file.
263 EXPECT_EQ(static_cast<int64
>(kData
.size()), // Modifies the file.
264 file_system_
.Write(&url_request_context
,
265 URL(kPath4
), blob
.GetBlobDataHandle()));
267 // Verify the changes.
268 file_system_
.GetChangedURLsInTracker(&urls
);
269 EXPECT_EQ(5U, urls
.size());
271 // Reset the changes in in-memory tracker.
272 DropChangesInTracker();
274 // Make sure we have no in-memory changes in the tracker.
275 file_system_
.GetChangedURLsInTracker(&urls
);
276 ASSERT_EQ(0U, urls
.size());
278 RestoreChangesFromTrackerDB();
280 // Make sure the changes are restored from the DB.
281 file_system_
.GetChangedURLsInTracker(&urls
);
282 EXPECT_EQ(5U, urls
.size());
284 VerifyAndClearChange(URL(kPath0
),
285 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
286 sync_file_system::SYNC_FILE_TYPE_FILE
));
287 VerifyAndClearChange(URL(kPath1
),
288 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
289 sync_file_system::SYNC_FILE_TYPE_DIRECTORY
));
290 VerifyAndClearChange(URL(kPath2
),
291 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
292 sync_file_system::SYNC_FILE_TYPE_DIRECTORY
));
293 VerifyAndClearChange(URL(kPath3
),
294 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
295 sync_file_system::SYNC_FILE_TYPE_FILE
));
296 VerifyAndClearChange(URL(kPath4
),
297 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
298 sync_file_system::SYNC_FILE_TYPE_FILE
));
301 TEST_F(LocalFileChangeTrackerTest
, RestoreRemoveChanges
) {
302 EXPECT_EQ(base::PLATFORM_FILE_OK
, file_system_
.OpenFileSystem());
304 FileSystemURLSet urls
;
306 const char kPath0
[] = "file";
307 const char kPath1
[] = "dir a";
308 const char kPath2
[] = "dir b";
309 const char kPath3
[] = "dir b/file";
310 const char kPath4
[] = "dir b/dir c";
311 const char kPath5
[] = "dir b/dir c/file";
313 file_system_
.GetChangedURLsInTracker(&urls
);
314 ASSERT_EQ(0U, urls
.size());
316 // Creates and removes a same file.
317 EXPECT_EQ(base::PLATFORM_FILE_OK
,
318 file_system_
.CreateFile(URL(kPath0
)));
319 EXPECT_EQ(base::PLATFORM_FILE_OK
,
320 file_system_
.Remove(URL(kPath0
), false /* recursive */));
322 // Creates and removes a same directory.
323 EXPECT_EQ(base::PLATFORM_FILE_OK
,
324 file_system_
.CreateDirectory(URL(kPath1
)));
325 EXPECT_EQ(base::PLATFORM_FILE_OK
,
326 file_system_
.Remove(URL(kPath1
), false /* recursive */));
328 // Creates files and nested directories, then removes the parent directory.
329 EXPECT_EQ(base::PLATFORM_FILE_OK
,
330 file_system_
.CreateDirectory(URL(kPath2
)));
331 EXPECT_EQ(base::PLATFORM_FILE_OK
,
332 file_system_
.CreateFile(URL(kPath3
)));
333 EXPECT_EQ(base::PLATFORM_FILE_OK
,
334 file_system_
.CreateDirectory(URL(kPath4
)));
335 EXPECT_EQ(base::PLATFORM_FILE_OK
,
336 file_system_
.CreateFile(URL(kPath5
)));
337 EXPECT_EQ(base::PLATFORM_FILE_OK
,
338 file_system_
.Remove(URL(kPath2
), true /* recursive */));
340 file_system_
.GetChangedURLsInTracker(&urls
);
341 EXPECT_EQ(3U, urls
.size());
343 DropChangesInTracker();
345 // Make sure we have no in-memory changes in the tracker.
346 file_system_
.GetChangedURLsInTracker(&urls
);
347 ASSERT_EQ(0U, urls
.size());
349 RestoreChangesFromTrackerDB();
351 // Make sure the changes are restored from the DB.
352 file_system_
.GetChangedURLsInTracker(&urls
);
353 // Since directories to have been reverted (kPath1, kPath2, kPath4) are
354 // treated as FILE_CHANGE_DELETE, the number of changes should be 6.
355 EXPECT_EQ(6U, urls
.size());
357 VerifyAndClearChange(URL(kPath0
),
358 FileChange(FileChange::FILE_CHANGE_DELETE
,
359 sync_file_system::SYNC_FILE_TYPE_UNKNOWN
));
360 VerifyAndClearChange(URL(kPath1
),
361 FileChange(FileChange::FILE_CHANGE_DELETE
,
362 sync_file_system::SYNC_FILE_TYPE_UNKNOWN
));
363 VerifyAndClearChange(URL(kPath2
),
364 FileChange(FileChange::FILE_CHANGE_DELETE
,
365 sync_file_system::SYNC_FILE_TYPE_UNKNOWN
));
366 VerifyAndClearChange(URL(kPath3
),
367 FileChange(FileChange::FILE_CHANGE_DELETE
,
368 sync_file_system::SYNC_FILE_TYPE_UNKNOWN
));
369 VerifyAndClearChange(URL(kPath4
),
370 FileChange(FileChange::FILE_CHANGE_DELETE
,
371 sync_file_system::SYNC_FILE_TYPE_UNKNOWN
));
372 VerifyAndClearChange(URL(kPath5
),
373 FileChange(FileChange::FILE_CHANGE_DELETE
,
374 sync_file_system::SYNC_FILE_TYPE_UNKNOWN
));
377 TEST_F(LocalFileChangeTrackerTest
, RestoreCopyChanges
) {
378 EXPECT_EQ(base::PLATFORM_FILE_OK
, file_system_
.OpenFileSystem());
380 FileSystemURLSet urls
;
382 const char kPath0
[] = "file a";
383 const char kPath1
[] = "dir a";
384 const char kPath2
[] = "dir a/dir";
385 const char kPath3
[] = "dir a/file a";
386 const char kPath4
[] = "dir a/file b";
388 const char kPath0Copy
[] = "file b"; // To be copied from kPath0
389 const char kPath1Copy
[] = "dir b"; // To be copied from kPath1
390 const char kPath2Copy
[] = "dir b/dir"; // To be copied from kPath2
391 const char kPath3Copy
[] = "dir b/file a"; // To be copied from kPath3
392 const char kPath4Copy
[] = "dir b/file b"; // To be copied from kPath4
394 file_system_
.GetChangedURLsInTracker(&urls
);
395 ASSERT_EQ(0U, urls
.size());
397 const std::string
kData("Lorem ipsum.");
398 MockBlobURLRequestContext
url_request_context(file_system_context());
399 ScopedTextBlob
blob(url_request_context
, "blob_id:test", kData
);
401 // Create files and nested directories.
402 EXPECT_EQ(base::PLATFORM_FILE_OK
,
403 file_system_
.CreateFile(URL(kPath0
))); // Creates a file.
404 EXPECT_EQ(base::PLATFORM_FILE_OK
,
405 file_system_
.CreateDirectory(URL(kPath1
))); // Creates a dir.
406 EXPECT_EQ(base::PLATFORM_FILE_OK
,
407 file_system_
.CreateDirectory(URL(kPath2
))); // Creates another dir.
408 EXPECT_EQ(base::PLATFORM_FILE_OK
,
409 file_system_
.CreateFile(URL(kPath3
))); // Creates a file.
410 EXPECT_EQ(base::PLATFORM_FILE_OK
,
411 file_system_
.TruncateFile(URL(kPath3
), 1)); // Modifies the file.
412 EXPECT_EQ(base::PLATFORM_FILE_OK
,
413 file_system_
.CreateFile(URL(kPath4
))); // Creates another file.
414 EXPECT_EQ(static_cast<int64
>(kData
.size()),
415 file_system_
.Write(&url_request_context
, // Modifies the file.
416 URL(kPath4
), blob
.GetBlobDataHandle()));
418 // Verify we have 5 changes for preparation.
419 file_system_
.GetChangedURLsInTracker(&urls
);
420 EXPECT_EQ(5U, urls
.size());
421 change_tracker()->ClearChangesForURL(URL(kPath0
));
422 change_tracker()->ClearChangesForURL(URL(kPath1
));
423 change_tracker()->ClearChangesForURL(URL(kPath2
));
424 change_tracker()->ClearChangesForURL(URL(kPath3
));
425 change_tracker()->ClearChangesForURL(URL(kPath4
));
427 // Make sure we have no changes.
428 file_system_
.GetChangedURLsInTracker(&urls
);
429 EXPECT_TRUE(urls
.empty());
431 // Copy the file and the parent directory.
432 EXPECT_EQ(base::PLATFORM_FILE_OK
,
433 file_system_
.Copy(URL(kPath0
), URL(kPath0Copy
))); // Copy the file.
434 EXPECT_EQ(base::PLATFORM_FILE_OK
,
435 file_system_
.Copy(URL(kPath1
), URL(kPath1Copy
))); // Copy the dir.
437 file_system_
.GetChangedURLsInTracker(&urls
);
438 EXPECT_EQ(5U, urls
.size());
439 DropChangesInTracker();
441 // Make sure we have no in-memory changes in the tracker.
442 file_system_
.GetChangedURLsInTracker(&urls
);
443 ASSERT_EQ(0U, urls
.size());
445 RestoreChangesFromTrackerDB();
447 // Make sure the changes are restored from the DB.
448 file_system_
.GetChangedURLsInTracker(&urls
);
449 EXPECT_EQ(5U, urls
.size());
451 VerifyAndClearChange(URL(kPath0Copy
),
452 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
453 sync_file_system::SYNC_FILE_TYPE_FILE
));
454 VerifyAndClearChange(URL(kPath1Copy
),
455 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
456 sync_file_system::SYNC_FILE_TYPE_DIRECTORY
));
457 VerifyAndClearChange(URL(kPath2Copy
),
458 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
459 sync_file_system::SYNC_FILE_TYPE_DIRECTORY
));
460 VerifyAndClearChange(URL(kPath3Copy
),
461 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
462 sync_file_system::SYNC_FILE_TYPE_FILE
));
463 VerifyAndClearChange(URL(kPath4Copy
),
464 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
465 sync_file_system::SYNC_FILE_TYPE_FILE
));
468 TEST_F(LocalFileChangeTrackerTest
, RestoreMoveChanges
) {
469 EXPECT_EQ(base::PLATFORM_FILE_OK
, file_system_
.OpenFileSystem());
471 FileSystemURLSet urls
;
473 const char kPath0
[] = "file a";
474 const char kPath1
[] = "dir a";
475 const char kPath2
[] = "dir a/file";
476 const char kPath3
[] = "dir a/dir";
477 const char kPath4
[] = "dir a/dir/file";
479 const char kPath5
[] = "file b"; // To be moved from kPath0.
480 const char kPath6
[] = "dir b"; // To be moved from kPath1.
481 const char kPath7
[] = "dir b/file"; // To be moved from kPath2.
482 const char kPath8
[] = "dir b/dir"; // To be moved from kPath3.
483 const char kPath9
[] = "dir b/dir/file"; // To be moved from kPath4.
485 file_system_
.GetChangedURLsInTracker(&urls
);
486 ASSERT_EQ(0U, urls
.size());
488 // Create files and nested directories.
489 EXPECT_EQ(base::PLATFORM_FILE_OK
,
490 file_system_
.CreateFile(URL(kPath0
)));
491 EXPECT_EQ(base::PLATFORM_FILE_OK
,
492 file_system_
.CreateDirectory(URL(kPath1
)));
493 EXPECT_EQ(base::PLATFORM_FILE_OK
,
494 file_system_
.CreateFile(URL(kPath2
)));
495 EXPECT_EQ(base::PLATFORM_FILE_OK
,
496 file_system_
.CreateDirectory(URL(kPath3
)));
497 EXPECT_EQ(base::PLATFORM_FILE_OK
,
498 file_system_
.CreateFile(URL(kPath4
)));
500 // Verify we have 5 changes for preparation.
501 file_system_
.GetChangedURLsInTracker(&urls
);
502 EXPECT_EQ(5U, urls
.size());
503 change_tracker()->ClearChangesForURL(URL(kPath0
));
504 change_tracker()->ClearChangesForURL(URL(kPath1
));
505 change_tracker()->ClearChangesForURL(URL(kPath2
));
506 change_tracker()->ClearChangesForURL(URL(kPath3
));
507 change_tracker()->ClearChangesForURL(URL(kPath4
));
509 // Make sure we have no changes.
510 file_system_
.GetChangedURLsInTracker(&urls
);
511 EXPECT_TRUE(urls
.empty());
513 // Move the file and the parent directory.
514 EXPECT_EQ(base::PLATFORM_FILE_OK
,
515 file_system_
.Move(URL(kPath0
), URL(kPath5
)));
516 EXPECT_EQ(base::PLATFORM_FILE_OK
,
517 file_system_
.Move(URL(kPath1
), URL(kPath6
)));
519 file_system_
.GetChangedURLsInTracker(&urls
);
520 EXPECT_EQ(10U, urls
.size());
522 DropChangesInTracker();
524 // Make sure we have no in-memory changes in the tracker.
525 file_system_
.GetChangedURLsInTracker(&urls
);
526 ASSERT_EQ(0U, urls
.size());
528 RestoreChangesFromTrackerDB();
530 // Make sure the changes are restored from the DB.
531 file_system_
.GetChangedURLsInTracker(&urls
);
532 // Deletion for child files in the deleted directory cannot be restored,
533 // so we will only have 8 changes.
534 EXPECT_EQ(8U, urls
.size());
536 VerifyAndClearChange(URL(kPath0
),
537 FileChange(FileChange::FILE_CHANGE_DELETE
,
538 sync_file_system::SYNC_FILE_TYPE_UNKNOWN
));
539 VerifyAndClearChange(URL(kPath1
),
540 FileChange(FileChange::FILE_CHANGE_DELETE
,
541 sync_file_system::SYNC_FILE_TYPE_UNKNOWN
));
542 VerifyAndClearChange(URL(kPath3
),
543 FileChange(FileChange::FILE_CHANGE_DELETE
,
544 sync_file_system::SYNC_FILE_TYPE_UNKNOWN
));
545 VerifyAndClearChange(URL(kPath5
),
546 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
547 sync_file_system::SYNC_FILE_TYPE_FILE
));
548 VerifyAndClearChange(URL(kPath6
),
549 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
550 sync_file_system::SYNC_FILE_TYPE_DIRECTORY
));
551 VerifyAndClearChange(URL(kPath7
),
552 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
553 sync_file_system::SYNC_FILE_TYPE_FILE
));
554 VerifyAndClearChange(URL(kPath8
),
555 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
556 sync_file_system::SYNC_FILE_TYPE_DIRECTORY
));
557 VerifyAndClearChange(URL(kPath9
),
558 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE
,
559 sync_file_system::SYNC_FILE_TYPE_FILE
));
562 TEST_F(LocalFileChangeTrackerTest
, NextChangedURLsWithRecursiveCopy
) {
563 EXPECT_EQ(base::PLATFORM_FILE_OK
, file_system_
.OpenFileSystem());
565 FileSystemURLSet urls
;
567 const char kPath0
[] = "dir a";
568 const char kPath1
[] = "dir a/file";
569 const char kPath2
[] = "dir a/dir";
571 const char kPath0Copy
[] = "dir b";
572 const char kPath1Copy
[] = "dir b/file";
573 const char kPath2Copy
[] = "dir b/dir";
575 // Creates kPath0,1,2 and then copies them all.
576 EXPECT_EQ(base::PLATFORM_FILE_OK
,
577 file_system_
.CreateDirectory(URL(kPath0
)));
578 EXPECT_EQ(base::PLATFORM_FILE_OK
,
579 file_system_
.CreateFile(URL(kPath1
)));
580 EXPECT_EQ(base::PLATFORM_FILE_OK
,
581 file_system_
.CreateDirectory(URL(kPath2
)));
582 EXPECT_EQ(base::PLATFORM_FILE_OK
,
583 file_system_
.Copy(URL(kPath0
), URL(kPath0Copy
)));
585 std::deque
<FileSystemURL
> urls_to_process
;
586 change_tracker()->GetNextChangedURLs(&urls_to_process
, 0);
587 ASSERT_EQ(6U, urls_to_process
.size());
589 // Creation must have occured first.
590 EXPECT_EQ(URL(kPath0
), urls_to_process
[0]);
591 EXPECT_EQ(URL(kPath1
), urls_to_process
[1]);
592 EXPECT_EQ(URL(kPath2
), urls_to_process
[2]);
594 // Then recursive copy took place. The exact order cannot be determined
595 // but the parent directory must have been created first.
596 EXPECT_EQ(URL(kPath0Copy
), urls_to_process
[3]);
597 EXPECT_TRUE(URL(kPath1Copy
) == urls_to_process
[4] ||
598 URL(kPath2Copy
) == urls_to_process
[4]);
599 EXPECT_TRUE(URL(kPath1Copy
) == urls_to_process
[5] ||
600 URL(kPath2Copy
) == urls_to_process
[5]);
603 TEST_F(LocalFileChangeTrackerTest
, NextChangedURLsWithRecursiveRemove
) {
604 EXPECT_EQ(base::PLATFORM_FILE_OK
, file_system_
.OpenFileSystem());
606 const char kPath0
[] = "dir a";
607 const char kPath1
[] = "dir a/file1";
608 const char kPath2
[] = "dir a/file2";
610 // Creates kPath0,1,2 and then removes them all.
611 EXPECT_EQ(base::PLATFORM_FILE_OK
,
612 file_system_
.CreateDirectory(URL(kPath0
)));
613 EXPECT_EQ(base::PLATFORM_FILE_OK
,
614 file_system_
.CreateFile(URL(kPath1
)));
615 EXPECT_EQ(base::PLATFORM_FILE_OK
,
616 file_system_
.CreateFile(URL(kPath2
)));
617 EXPECT_EQ(base::PLATFORM_FILE_OK
,
618 file_system_
.Remove(URL(kPath0
), true /* recursive */));
620 FileSystemURLSet urls
;
621 GetAllChangedURLs(&urls
);
623 // This is actually not really desirable, but since the directory
624 // creation and deletion have been offset now we only have two
625 // file deletion changes.
627 // NOTE: This will cause 2 local sync for deleting nonexistent files
628 // on the remote side.
630 // TODO(kinuko): For micro optimization we could probably restore the ADD
631 // change type (other than ADD_OR_UPDATE) and offset file ADD+DELETE
633 ASSERT_EQ(2U, urls
.size());
635 // The exact order of recursive removal cannot be determined.
636 EXPECT_TRUE(ContainsKey(urls
, URL(kPath1
)));
637 EXPECT_TRUE(ContainsKey(urls
, URL(kPath2
)));
640 TEST_F(LocalFileChangeTrackerTest
, ResetForFileSystem
) {
641 EXPECT_EQ(base::PLATFORM_FILE_OK
, file_system_
.OpenFileSystem());
643 const char kPath0
[] = "dir a";
644 const char kPath1
[] = "dir a/file";
645 const char kPath2
[] = "dir a/subdir";
646 const char kPath3
[] = "dir b";
648 EXPECT_EQ(base::PLATFORM_FILE_OK
,
649 file_system_
.CreateDirectory(URL(kPath0
)));
650 EXPECT_EQ(base::PLATFORM_FILE_OK
,
651 file_system_
.CreateFile(URL(kPath1
)));
652 EXPECT_EQ(base::PLATFORM_FILE_OK
,
653 file_system_
.CreateDirectory(URL(kPath2
)));
654 EXPECT_EQ(base::PLATFORM_FILE_OK
,
655 file_system_
.CreateDirectory(URL(kPath3
)));
657 FileSystemURLSet urls
;
658 GetAllChangedURLs(&urls
);
659 EXPECT_EQ(4u, urls
.size());
660 EXPECT_TRUE(ContainsKey(urls
, URL(kPath0
)));
661 EXPECT_TRUE(ContainsKey(urls
, URL(kPath1
)));
662 EXPECT_TRUE(ContainsKey(urls
, URL(kPath2
)));
663 EXPECT_TRUE(ContainsKey(urls
, URL(kPath3
)));
665 // Reset all changes for the file system.
666 change_tracker()->ResetForFileSystem(
667 file_system_
.origin(), file_system_
.type());
669 GetAllChangedURLs(&urls
);
670 EXPECT_TRUE(urls
.empty());
672 // Make sure they're gone from the database too.
673 DropChangesInTracker();
674 RestoreChangesFromTrackerDB();
676 GetAllChangedURLs(&urls
);
677 EXPECT_TRUE(urls
.empty());
680 } // namespace sync_file_system