OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "webkit/fileapi/syncable/local_file_change_tracker.h" | |
6 | |
7 #include <deque> | |
8 #include <set> | |
9 | |
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.h" | |
14 #include "base/message_loop_proxy.h" | |
15 #include "base/stl_util.h" | |
16 #include "testing/gtest/include/gtest/gtest.h" | |
17 #include "webkit/blob/mock_blob_url_request_context.h" | |
18 #include "webkit/browser/fileapi/file_system_context.h" | |
19 #include "webkit/browser/fileapi/file_system_task_runners.h" | |
20 #include "webkit/fileapi/syncable/canned_syncable_file_system.h" | |
21 #include "webkit/fileapi/syncable/local_file_sync_context.h" | |
22 #include "webkit/fileapi/syncable/sync_status_code.h" | |
23 #include "webkit/fileapi/syncable/syncable_file_system_util.h" | |
24 #include "webkit/quota/quota_manager.h" | |
25 | |
26 using fileapi::FileSystemContext; | |
27 using fileapi::FileSystemURL; | |
28 using fileapi::FileSystemURLSet; | |
29 using webkit_blob::MockBlobURLRequestContext; | |
30 using webkit_blob::ScopedTextBlob; | |
31 | |
32 namespace sync_file_system { | |
33 | |
34 class LocalFileChangeTrackerTest : public testing::Test { | |
35 public: | |
36 LocalFileChangeTrackerTest() | |
37 : message_loop_(base::MessageLoop::TYPE_IO), | |
38 file_system_(GURL("http://example.com"), | |
39 "test", | |
40 base::MessageLoopProxy::current(), | |
41 base::MessageLoopProxy::current()) {} | |
42 | |
43 virtual void SetUp() OVERRIDE { | |
44 file_system_.SetUp(); | |
45 | |
46 sync_context_ = new LocalFileSyncContext(base::MessageLoopProxy::current(), | |
47 base::MessageLoopProxy::current()); | |
48 ASSERT_EQ(sync_file_system::SYNC_STATUS_OK, | |
49 file_system_.MaybeInitializeFileSystemContext(sync_context_)); | |
50 } | |
51 | |
52 virtual void TearDown() OVERRIDE { | |
53 if (sync_context_) | |
54 sync_context_->ShutdownOnUIThread(); | |
55 sync_context_ = NULL; | |
56 | |
57 message_loop_.RunUntilIdle(); | |
58 file_system_.TearDown(); | |
59 // Make sure we don't leave the external filesystem. | |
60 // (CannedSyncableFileSystem::TearDown does not do this as there may be | |
61 // multiple syncable file systems registered for the name) | |
62 RevokeSyncableFileSystem("test"); | |
63 } | |
64 | |
65 protected: | |
66 FileSystemURL URL(const std::string& path) { | |
67 return file_system_.URL(path); | |
68 } | |
69 | |
70 FileSystemContext* file_system_context() { | |
71 return file_system_.file_system_context(); | |
72 } | |
73 | |
74 LocalFileChangeTracker* change_tracker() { | |
75 return file_system_context()->change_tracker(); | |
76 } | |
77 | |
78 void VerifyAndClearChange(const FileSystemURL& url, | |
79 const FileChange& expected_change) { | |
80 SCOPED_TRACE(testing::Message() << url.DebugString() << | |
81 " expecting:" << expected_change.DebugString()); | |
82 // Get the changes for URL and verify. | |
83 FileChangeList changes; | |
84 change_tracker()->GetChangesForURL(url, &changes); | |
85 ASSERT_EQ(1U, changes.size()); | |
86 SCOPED_TRACE(testing::Message() << url.DebugString() << | |
87 " actual:" << changes.DebugString()); | |
88 EXPECT_EQ(expected_change, changes.list()[0]); | |
89 | |
90 // Clear the URL from the change tracker. | |
91 change_tracker()->ClearChangesForURL(url); | |
92 } | |
93 | |
94 void DropChangesInTracker() { | |
95 change_tracker()->DropAllChanges(); | |
96 } | |
97 | |
98 void RestoreChangesFromTrackerDB() { | |
99 change_tracker()->CollectLastDirtyChanges(file_system_context()); | |
100 } | |
101 | |
102 base::MessageLoop message_loop_; | |
103 | |
104 CannedSyncableFileSystem file_system_; | |
105 scoped_refptr<LocalFileSyncContext> sync_context_; | |
106 | |
107 DISALLOW_COPY_AND_ASSIGN(LocalFileChangeTrackerTest); | |
108 }; | |
109 | |
110 TEST_F(LocalFileChangeTrackerTest, GetChanges) { | |
111 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_.OpenFileSystem()); | |
112 | |
113 // Test URLs (no parent/child relationships, as we test such cases | |
114 // mainly in LocalFileSyncStatusTest). | |
115 const char kPath0[] = "test/dir a/dir"; | |
116 const char kPath1[] = "test/dir b"; | |
117 const char kPath2[] = "test/foo.txt"; | |
118 const char kPath3[] = "test/bar"; | |
119 const char kPath4[] = "temporary/dir a"; | |
120 const char kPath5[] = "temporary/foo"; | |
121 | |
122 change_tracker()->OnCreateDirectory(URL(kPath0)); | |
123 change_tracker()->OnRemoveDirectory(URL(kPath0)); // Offset the create. | |
124 change_tracker()->OnRemoveDirectory(URL(kPath1)); | |
125 change_tracker()->OnCreateDirectory(URL(kPath2)); | |
126 change_tracker()->OnRemoveFile(URL(kPath3)); | |
127 change_tracker()->OnModifyFile(URL(kPath4)); | |
128 change_tracker()->OnCreateFile(URL(kPath5)); | |
129 change_tracker()->OnRemoveFile(URL(kPath5)); // Recorded as 'delete'. | |
130 | |
131 FileSystemURLSet urls; | |
132 file_system_.GetChangedURLsInTracker(&urls); | |
133 | |
134 EXPECT_EQ(5U, urls.size()); | |
135 EXPECT_TRUE(ContainsKey(urls, URL(kPath1))); | |
136 EXPECT_TRUE(ContainsKey(urls, URL(kPath2))); | |
137 EXPECT_TRUE(ContainsKey(urls, URL(kPath3))); | |
138 EXPECT_TRUE(ContainsKey(urls, URL(kPath4))); | |
139 EXPECT_TRUE(ContainsKey(urls, URL(kPath5))); | |
140 | |
141 // Changes for kPath0 must have been offset and removed. | |
142 EXPECT_FALSE(ContainsKey(urls, URL(kPath0))); | |
143 | |
144 // GetNextChangedURLs only returns up to max_urls (i.e. 3) urls. | |
145 std::deque<FileSystemURL> urls_to_process; | |
146 change_tracker()->GetNextChangedURLs(&urls_to_process, 3); | |
147 ASSERT_EQ(3U, urls_to_process.size()); | |
148 | |
149 // Let it return all. | |
150 urls_to_process.clear(); | |
151 change_tracker()->GetNextChangedURLs(&urls_to_process, 0); | |
152 ASSERT_EQ(5U, urls_to_process.size()); | |
153 | |
154 // The changes must be in the last-modified-time order. | |
155 EXPECT_EQ(URL(kPath1), urls_to_process[0]); | |
156 EXPECT_EQ(URL(kPath2), urls_to_process[1]); | |
157 EXPECT_EQ(URL(kPath3), urls_to_process[2]); | |
158 EXPECT_EQ(URL(kPath4), urls_to_process[3]); | |
159 EXPECT_EQ(URL(kPath5), urls_to_process[4]); | |
160 | |
161 // Modify kPath4 again. | |
162 change_tracker()->OnModifyFile(URL(kPath4)); | |
163 | |
164 // Now the order must be changed. | |
165 urls_to_process.clear(); | |
166 change_tracker()->GetNextChangedURLs(&urls_to_process, 0); | |
167 ASSERT_EQ(5U, urls_to_process.size()); | |
168 EXPECT_EQ(URL(kPath1), urls_to_process[0]); | |
169 EXPECT_EQ(URL(kPath2), urls_to_process[1]); | |
170 EXPECT_EQ(URL(kPath3), urls_to_process[2]); | |
171 EXPECT_EQ(URL(kPath5), urls_to_process[3]); | |
172 EXPECT_EQ(URL(kPath4), urls_to_process[4]); | |
173 | |
174 VerifyAndClearChange(URL(kPath1), | |
175 FileChange(FileChange::FILE_CHANGE_DELETE, | |
176 sync_file_system::SYNC_FILE_TYPE_DIRECTORY)); | |
177 VerifyAndClearChange(URL(kPath2), | |
178 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, | |
179 sync_file_system::SYNC_FILE_TYPE_DIRECTORY)); | |
180 VerifyAndClearChange(URL(kPath3), | |
181 FileChange(FileChange::FILE_CHANGE_DELETE, | |
182 sync_file_system::SYNC_FILE_TYPE_FILE)); | |
183 VerifyAndClearChange(URL(kPath4), | |
184 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, | |
185 sync_file_system::SYNC_FILE_TYPE_FILE)); | |
186 VerifyAndClearChange(URL(kPath5), | |
187 FileChange(FileChange::FILE_CHANGE_DELETE, | |
188 sync_file_system::SYNC_FILE_TYPE_FILE)); | |
189 } | |
190 | |
191 TEST_F(LocalFileChangeTrackerTest, RestoreCreateAndModifyChanges) { | |
192 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_.OpenFileSystem()); | |
193 | |
194 FileSystemURLSet urls; | |
195 | |
196 const char kPath0[] = "file a"; | |
197 const char kPath1[] = "dir a"; | |
198 const char kPath2[] = "dir a/dir"; | |
199 const char kPath3[] = "dir a/file a"; | |
200 const char kPath4[] = "dir a/file b"; | |
201 | |
202 file_system_.GetChangedURLsInTracker(&urls); | |
203 ASSERT_EQ(0U, urls.size()); | |
204 | |
205 const GURL blob_url("blob:test"); | |
206 const std::string kData("Lorem ipsum."); | |
207 MockBlobURLRequestContext url_request_context(file_system_context()); | |
208 ScopedTextBlob blob(url_request_context, blob_url, kData); | |
209 | |
210 // Create files and nested directories. | |
211 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
212 file_system_.CreateFile(URL(kPath0))); // Creates a file. | |
213 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
214 file_system_.CreateDirectory(URL(kPath1))); // Creates a dir. | |
215 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
216 file_system_.CreateDirectory(URL(kPath2))); // Creates another dir. | |
217 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
218 file_system_.CreateFile(URL(kPath3))); // Creates a file. | |
219 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
220 file_system_.TruncateFile(URL(kPath3), 1)); // Modifies the file. | |
221 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
222 file_system_.CreateFile(URL(kPath4))); // Creates another file. | |
223 EXPECT_EQ(static_cast<int64>(kData.size()), | |
224 file_system_.Write(&url_request_context, | |
225 URL(kPath4), blob_url)); // Modifies the file. | |
226 | |
227 // Verify the changes. | |
228 file_system_.GetChangedURLsInTracker(&urls); | |
229 EXPECT_EQ(5U, urls.size()); | |
230 | |
231 // Reset the changes in in-memory tracker. | |
232 DropChangesInTracker(); | |
233 | |
234 // Make sure we have no in-memory changes in the tracker. | |
235 file_system_.GetChangedURLsInTracker(&urls); | |
236 ASSERT_EQ(0U, urls.size()); | |
237 | |
238 RestoreChangesFromTrackerDB(); | |
239 | |
240 // Make sure the changes are restored from the DB. | |
241 file_system_.GetChangedURLsInTracker(&urls); | |
242 EXPECT_EQ(5U, urls.size()); | |
243 | |
244 VerifyAndClearChange(URL(kPath0), | |
245 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, | |
246 sync_file_system::SYNC_FILE_TYPE_FILE)); | |
247 VerifyAndClearChange(URL(kPath1), | |
248 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, | |
249 sync_file_system::SYNC_FILE_TYPE_DIRECTORY)); | |
250 VerifyAndClearChange(URL(kPath2), | |
251 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, | |
252 sync_file_system::SYNC_FILE_TYPE_DIRECTORY)); | |
253 VerifyAndClearChange(URL(kPath3), | |
254 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, | |
255 sync_file_system::SYNC_FILE_TYPE_FILE)); | |
256 VerifyAndClearChange(URL(kPath4), | |
257 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, | |
258 sync_file_system::SYNC_FILE_TYPE_FILE)); | |
259 } | |
260 | |
261 TEST_F(LocalFileChangeTrackerTest, RestoreRemoveChanges) { | |
262 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_.OpenFileSystem()); | |
263 | |
264 FileSystemURLSet urls; | |
265 | |
266 const char kPath0[] = "file"; | |
267 const char kPath1[] = "dir a"; | |
268 const char kPath2[] = "dir b"; | |
269 const char kPath3[] = "dir b/file"; | |
270 const char kPath4[] = "dir b/dir c"; | |
271 const char kPath5[] = "dir b/dir c/file"; | |
272 | |
273 file_system_.GetChangedURLsInTracker(&urls); | |
274 ASSERT_EQ(0U, urls.size()); | |
275 | |
276 // Creates and removes a same file. | |
277 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
278 file_system_.CreateFile(URL(kPath0))); | |
279 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
280 file_system_.Remove(URL(kPath0), false /* recursive */)); | |
281 | |
282 // Creates and removes a same directory. | |
283 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
284 file_system_.CreateDirectory(URL(kPath1))); | |
285 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
286 file_system_.Remove(URL(kPath1), false /* recursive */)); | |
287 | |
288 // Creates files and nested directories, then removes the parent directory. | |
289 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
290 file_system_.CreateDirectory(URL(kPath2))); | |
291 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
292 file_system_.CreateFile(URL(kPath3))); | |
293 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
294 file_system_.CreateDirectory(URL(kPath4))); | |
295 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
296 file_system_.CreateFile(URL(kPath5))); | |
297 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
298 file_system_.Remove(URL(kPath2), true /* recursive */)); | |
299 | |
300 file_system_.GetChangedURLsInTracker(&urls); | |
301 EXPECT_EQ(3U, urls.size()); | |
302 | |
303 DropChangesInTracker(); | |
304 | |
305 // Make sure we have no in-memory changes in the tracker. | |
306 file_system_.GetChangedURLsInTracker(&urls); | |
307 ASSERT_EQ(0U, urls.size()); | |
308 | |
309 RestoreChangesFromTrackerDB(); | |
310 | |
311 // Make sure the changes are restored from the DB. | |
312 file_system_.GetChangedURLsInTracker(&urls); | |
313 // Since directories to have been reverted (kPath1, kPath2, kPath4) are | |
314 // treated as FILE_CHANGE_DELETE, the number of changes should be 6. | |
315 EXPECT_EQ(6U, urls.size()); | |
316 | |
317 VerifyAndClearChange(URL(kPath0), | |
318 FileChange(FileChange::FILE_CHANGE_DELETE, | |
319 sync_file_system::SYNC_FILE_TYPE_UNKNOWN)); | |
320 VerifyAndClearChange(URL(kPath1), | |
321 FileChange(FileChange::FILE_CHANGE_DELETE, | |
322 sync_file_system::SYNC_FILE_TYPE_UNKNOWN)); | |
323 VerifyAndClearChange(URL(kPath2), | |
324 FileChange(FileChange::FILE_CHANGE_DELETE, | |
325 sync_file_system::SYNC_FILE_TYPE_UNKNOWN)); | |
326 VerifyAndClearChange(URL(kPath3), | |
327 FileChange(FileChange::FILE_CHANGE_DELETE, | |
328 sync_file_system::SYNC_FILE_TYPE_UNKNOWN)); | |
329 VerifyAndClearChange(URL(kPath4), | |
330 FileChange(FileChange::FILE_CHANGE_DELETE, | |
331 sync_file_system::SYNC_FILE_TYPE_UNKNOWN)); | |
332 VerifyAndClearChange(URL(kPath5), | |
333 FileChange(FileChange::FILE_CHANGE_DELETE, | |
334 sync_file_system::SYNC_FILE_TYPE_UNKNOWN)); | |
335 } | |
336 | |
337 TEST_F(LocalFileChangeTrackerTest, RestoreCopyChanges) { | |
338 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_.OpenFileSystem()); | |
339 | |
340 FileSystemURLSet urls; | |
341 | |
342 const char kPath0[] = "file a"; | |
343 const char kPath1[] = "dir a"; | |
344 const char kPath2[] = "dir a/dir"; | |
345 const char kPath3[] = "dir a/file a"; | |
346 const char kPath4[] = "dir a/file b"; | |
347 | |
348 const char kPath0Copy[] = "file b"; // To be copied from kPath0 | |
349 const char kPath1Copy[] = "dir b"; // To be copied from kPath1 | |
350 const char kPath2Copy[] = "dir b/dir"; // To be copied from kPath2 | |
351 const char kPath3Copy[] = "dir b/file a"; // To be copied from kPath3 | |
352 const char kPath4Copy[] = "dir b/file b"; // To be copied from kPath4 | |
353 | |
354 file_system_.GetChangedURLsInTracker(&urls); | |
355 ASSERT_EQ(0U, urls.size()); | |
356 | |
357 const GURL blob_url("blob:test"); | |
358 const std::string kData("Lorem ipsum."); | |
359 MockBlobURLRequestContext url_request_context(file_system_context()); | |
360 ScopedTextBlob blob(url_request_context, blob_url, kData); | |
361 | |
362 // Create files and nested directories. | |
363 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
364 file_system_.CreateFile(URL(kPath0))); // Creates a file. | |
365 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
366 file_system_.CreateDirectory(URL(kPath1))); // Creates a dir. | |
367 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
368 file_system_.CreateDirectory(URL(kPath2))); // Creates another dir. | |
369 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
370 file_system_.CreateFile(URL(kPath3))); // Creates a file. | |
371 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
372 file_system_.TruncateFile(URL(kPath3), 1)); // Modifies the file. | |
373 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
374 file_system_.CreateFile(URL(kPath4))); // Creates another file. | |
375 EXPECT_EQ(static_cast<int64>(kData.size()), | |
376 file_system_.Write(&url_request_context, | |
377 URL(kPath4), blob_url)); // Modifies the file. | |
378 | |
379 // Verify we have 5 changes for preparation. | |
380 file_system_.GetChangedURLsInTracker(&urls); | |
381 EXPECT_EQ(5U, urls.size()); | |
382 change_tracker()->ClearChangesForURL(URL(kPath0)); | |
383 change_tracker()->ClearChangesForURL(URL(kPath1)); | |
384 change_tracker()->ClearChangesForURL(URL(kPath2)); | |
385 change_tracker()->ClearChangesForURL(URL(kPath3)); | |
386 change_tracker()->ClearChangesForURL(URL(kPath4)); | |
387 | |
388 // Make sure we have no changes. | |
389 file_system_.GetChangedURLsInTracker(&urls); | |
390 EXPECT_TRUE(urls.empty()); | |
391 | |
392 // Copy the file and the parent directory. | |
393 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
394 file_system_.Copy(URL(kPath0), URL(kPath0Copy))); // Copy the file. | |
395 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
396 file_system_.Copy(URL(kPath1), URL(kPath1Copy))); // Copy the dir. | |
397 | |
398 file_system_.GetChangedURLsInTracker(&urls); | |
399 EXPECT_EQ(5U, urls.size()); | |
400 DropChangesInTracker(); | |
401 | |
402 // Make sure we have no in-memory changes in the tracker. | |
403 file_system_.GetChangedURLsInTracker(&urls); | |
404 ASSERT_EQ(0U, urls.size()); | |
405 | |
406 RestoreChangesFromTrackerDB(); | |
407 | |
408 // Make sure the changes are restored from the DB. | |
409 file_system_.GetChangedURLsInTracker(&urls); | |
410 EXPECT_EQ(5U, urls.size()); | |
411 | |
412 VerifyAndClearChange(URL(kPath0Copy), | |
413 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, | |
414 sync_file_system::SYNC_FILE_TYPE_FILE)); | |
415 VerifyAndClearChange(URL(kPath1Copy), | |
416 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, | |
417 sync_file_system::SYNC_FILE_TYPE_DIRECTORY)); | |
418 VerifyAndClearChange(URL(kPath2Copy), | |
419 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, | |
420 sync_file_system::SYNC_FILE_TYPE_DIRECTORY)); | |
421 VerifyAndClearChange(URL(kPath3Copy), | |
422 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, | |
423 sync_file_system::SYNC_FILE_TYPE_FILE)); | |
424 VerifyAndClearChange(URL(kPath4Copy), | |
425 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, | |
426 sync_file_system::SYNC_FILE_TYPE_FILE)); | |
427 } | |
428 | |
429 TEST_F(LocalFileChangeTrackerTest, RestoreMoveChanges) { | |
430 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_.OpenFileSystem()); | |
431 | |
432 FileSystemURLSet urls; | |
433 | |
434 const char kPath0[] = "file a"; | |
435 const char kPath1[] = "dir a"; | |
436 const char kPath2[] = "dir a/file"; | |
437 const char kPath3[] = "dir a/dir"; | |
438 const char kPath4[] = "dir a/dir/file"; | |
439 | |
440 const char kPath5[] = "file b"; // To be moved from kPath0. | |
441 const char kPath6[] = "dir b"; // To be moved from kPath1. | |
442 const char kPath7[] = "dir b/file"; // To be moved from kPath2. | |
443 const char kPath8[] = "dir b/dir"; // To be moved from kPath3. | |
444 const char kPath9[] = "dir b/dir/file"; // To be moved from kPath4. | |
445 | |
446 file_system_.GetChangedURLsInTracker(&urls); | |
447 ASSERT_EQ(0U, urls.size()); | |
448 | |
449 // Create files and nested directories. | |
450 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
451 file_system_.CreateFile(URL(kPath0))); | |
452 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
453 file_system_.CreateDirectory(URL(kPath1))); | |
454 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
455 file_system_.CreateFile(URL(kPath2))); | |
456 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
457 file_system_.CreateDirectory(URL(kPath3))); | |
458 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
459 file_system_.CreateFile(URL(kPath4))); | |
460 | |
461 // Verify we have 5 changes for preparation. | |
462 file_system_.GetChangedURLsInTracker(&urls); | |
463 EXPECT_EQ(5U, urls.size()); | |
464 change_tracker()->ClearChangesForURL(URL(kPath0)); | |
465 change_tracker()->ClearChangesForURL(URL(kPath1)); | |
466 change_tracker()->ClearChangesForURL(URL(kPath2)); | |
467 change_tracker()->ClearChangesForURL(URL(kPath3)); | |
468 change_tracker()->ClearChangesForURL(URL(kPath4)); | |
469 | |
470 // Make sure we have no changes. | |
471 file_system_.GetChangedURLsInTracker(&urls); | |
472 EXPECT_TRUE(urls.empty()); | |
473 | |
474 // Move the file and the parent directory. | |
475 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
476 file_system_.Move(URL(kPath0), URL(kPath5))); | |
477 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
478 file_system_.Move(URL(kPath1), URL(kPath6))); | |
479 | |
480 file_system_.GetChangedURLsInTracker(&urls); | |
481 EXPECT_EQ(10U, urls.size()); | |
482 | |
483 DropChangesInTracker(); | |
484 | |
485 // Make sure we have no in-memory changes in the tracker. | |
486 file_system_.GetChangedURLsInTracker(&urls); | |
487 ASSERT_EQ(0U, urls.size()); | |
488 | |
489 RestoreChangesFromTrackerDB(); | |
490 | |
491 // Make sure the changes are restored from the DB. | |
492 file_system_.GetChangedURLsInTracker(&urls); | |
493 // Deletion for children in the deleted directory cannot be restored, | |
494 // so we will only have 7 changes. | |
495 EXPECT_EQ(7U, urls.size()); | |
496 | |
497 VerifyAndClearChange(URL(kPath0), | |
498 FileChange(FileChange::FILE_CHANGE_DELETE, | |
499 sync_file_system::SYNC_FILE_TYPE_UNKNOWN)); | |
500 VerifyAndClearChange(URL(kPath1), | |
501 FileChange(FileChange::FILE_CHANGE_DELETE, | |
502 sync_file_system::SYNC_FILE_TYPE_UNKNOWN)); | |
503 VerifyAndClearChange(URL(kPath5), | |
504 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, | |
505 sync_file_system::SYNC_FILE_TYPE_FILE)); | |
506 VerifyAndClearChange(URL(kPath6), | |
507 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, | |
508 sync_file_system::SYNC_FILE_TYPE_DIRECTORY)); | |
509 VerifyAndClearChange(URL(kPath7), | |
510 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, | |
511 sync_file_system::SYNC_FILE_TYPE_FILE)); | |
512 VerifyAndClearChange(URL(kPath8), | |
513 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, | |
514 sync_file_system::SYNC_FILE_TYPE_DIRECTORY)); | |
515 VerifyAndClearChange(URL(kPath9), | |
516 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, | |
517 sync_file_system::SYNC_FILE_TYPE_FILE)); | |
518 } | |
519 | |
520 TEST_F(LocalFileChangeTrackerTest, NextChangedURLsWithRecursiveCopy) { | |
521 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_.OpenFileSystem()); | |
522 | |
523 FileSystemURLSet urls; | |
524 | |
525 const char kPath0[] = "dir a"; | |
526 const char kPath1[] = "dir a/file"; | |
527 const char kPath2[] = "dir a/dir"; | |
528 | |
529 const char kPath0Copy[] = "dir b"; | |
530 const char kPath1Copy[] = "dir b/file"; | |
531 const char kPath2Copy[] = "dir b/dir"; | |
532 | |
533 // Creates kPath0,1,2 and then copies them all. | |
534 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
535 file_system_.CreateDirectory(URL(kPath0))); | |
536 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
537 file_system_.CreateFile(URL(kPath1))); | |
538 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
539 file_system_.CreateDirectory(URL(kPath2))); | |
540 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
541 file_system_.Copy(URL(kPath0), URL(kPath0Copy))); | |
542 | |
543 std::deque<FileSystemURL> urls_to_process; | |
544 change_tracker()->GetNextChangedURLs(&urls_to_process, 0); | |
545 ASSERT_EQ(6U, urls_to_process.size()); | |
546 | |
547 // Creation must have occured first. | |
548 EXPECT_EQ(URL(kPath0), urls_to_process[0]); | |
549 EXPECT_EQ(URL(kPath1), urls_to_process[1]); | |
550 EXPECT_EQ(URL(kPath2), urls_to_process[2]); | |
551 | |
552 // Then recursive copy took place. The exact order cannot be determined | |
553 // but the parent directory must have been created first. | |
554 EXPECT_EQ(URL(kPath0Copy), urls_to_process[3]); | |
555 EXPECT_TRUE(URL(kPath1Copy) == urls_to_process[4] || | |
556 URL(kPath2Copy) == urls_to_process[4]); | |
557 EXPECT_TRUE(URL(kPath1Copy) == urls_to_process[5] || | |
558 URL(kPath2Copy) == urls_to_process[5]); | |
559 } | |
560 | |
561 TEST_F(LocalFileChangeTrackerTest, NextChangedURLsWithRecursiveRemove) { | |
562 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_.OpenFileSystem()); | |
563 | |
564 FileSystemURLSet urls; | |
565 | |
566 const char kPath0[] = "dir a"; | |
567 const char kPath1[] = "dir a/file1"; | |
568 const char kPath2[] = "dir a/file2"; | |
569 | |
570 // Creates kPath0,1,2 and then removes them all. | |
571 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
572 file_system_.CreateDirectory(URL(kPath0))); | |
573 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
574 file_system_.CreateFile(URL(kPath1))); | |
575 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
576 file_system_.CreateFile(URL(kPath2))); | |
577 EXPECT_EQ(base::PLATFORM_FILE_OK, | |
578 file_system_.Remove(URL(kPath0), true /* recursive */)); | |
579 | |
580 std::deque<FileSystemURL> urls_to_process; | |
581 change_tracker()->GetNextChangedURLs(&urls_to_process, 0); | |
582 | |
583 // This is actually not really desirable, but since the directory | |
584 // creation and deletion have been offset now we only have two | |
585 // file deletion changes. | |
586 // | |
587 // NOTE: This will cause 2 local sync for deleting nonexistent files | |
588 // on the remote side. | |
589 // | |
590 // TODO(kinuko): For micro optimization we could probably restore the ADD | |
591 // change type (other than ADD_OR_UPDATE) and offset file ADD+DELETE | |
592 // changes too. | |
593 ASSERT_EQ(2U, urls_to_process.size()); | |
594 | |
595 // The exact order of recursive removal cannot be determined. | |
596 EXPECT_TRUE(URL(kPath1) == urls_to_process[0] || | |
597 URL(kPath2) == urls_to_process[0]); | |
598 EXPECT_TRUE(URL(kPath1) == urls_to_process[1] || | |
599 URL(kPath2) == urls_to_process[1]); | |
600 } | |
601 | |
602 } // namespace sync_file_system | |
OLD | NEW |