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