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