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