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 "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::MessageLoopProxy::current().get(),
     47                                  base::MessageLoopProxy::current().get());
     48     ASSERT_EQ(
     49         sync_file_system::SYNC_STATUS_OK,
     50         file_system_.MaybeInitializeFileSystemContext(sync_context_.get()));
     51   }
     52 
     53   virtual void TearDown() OVERRIDE {
     54     if (sync_context_.get())
     55       sync_context_->ShutdownOnUIThread();
     56     sync_context_ = NULL;
     57 
     58     message_loop_.RunUntilIdle();
     59     file_system_.TearDown();
     60     // Make sure we don't leave the external filesystem.
     61     // (CannedSyncableFileSystem::TearDown does not do this as there may be
     62     // multiple syncable file systems registered for the name)
     63     RevokeSyncableFileSystem();
     64   }
     65 
     66  protected:
     67   FileSystemURL URL(const std::string& path) {
     68     return file_system_.URL(path);
     69   }
     70 
     71   FileSystemContext* file_system_context() {
     72     return file_system_.file_system_context();
     73   }
     74 
     75   LocalFileChangeTracker* change_tracker() {
     76     return file_system_.backend()->change_tracker();
     77   }
     78 
     79   void VerifyAndClearChange(const FileSystemURL& url,
     80                             const FileChange& expected_change) {
     81     SCOPED_TRACE(testing::Message() << url.DebugString() <<
     82                  " expecting:" << expected_change.DebugString());
     83     // Get the changes for URL and verify.
     84     FileChangeList changes;
     85     change_tracker()->GetChangesForURL(url, &changes);
     86     ASSERT_EQ(1U, changes.size());
     87     SCOPED_TRACE(testing::Message() << url.DebugString() <<
     88                  " actual:" << changes.DebugString());
     89     EXPECT_EQ(expected_change, changes.list()[0]);
     90 
     91     // Clear the URL from the change tracker.
     92     change_tracker()->ClearChangesForURL(url);
     93   }
     94 
     95   void DropChangesInTracker() {
     96     change_tracker()->DropAllChanges();
     97   }
     98 
     99   void RestoreChangesFromTrackerDB() {
    100     change_tracker()->CollectLastDirtyChanges(file_system_context());
    101   }
    102 
    103   ScopedEnableSyncFSDirectoryOperation enable_directory_operation_;
    104   base::MessageLoop message_loop_;
    105 
    106   CannedSyncableFileSystem file_system_;
    107   scoped_refptr<LocalFileSyncContext> sync_context_;
    108 
    109   DISALLOW_COPY_AND_ASSIGN(LocalFileChangeTrackerTest);
    110 };
    111 
    112 TEST_F(LocalFileChangeTrackerTest, GetChanges) {
    113   EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_.OpenFileSystem());
    114 
    115   // Test URLs (no parent/child relationships, as we test such cases
    116   // mainly in LocalFileSyncStatusTest).
    117   const char kPath0[] = "test/dir a/dir";
    118   const char kPath1[] = "test/dir b";
    119   const char kPath2[] = "test/foo.txt";
    120   const char kPath3[] = "test/bar";
    121   const char kPath4[] = "temporary/dir a";
    122   const char kPath5[] = "temporary/foo";
    123 
    124   change_tracker()->OnCreateDirectory(URL(kPath0));
    125   change_tracker()->OnRemoveDirectory(URL(kPath0));  // Offset the create.
    126   change_tracker()->OnRemoveDirectory(URL(kPath1));
    127   change_tracker()->OnCreateDirectory(URL(kPath2));
    128   change_tracker()->OnRemoveFile(URL(kPath3));
    129   change_tracker()->OnModifyFile(URL(kPath4));
    130   change_tracker()->OnCreateFile(URL(kPath5));
    131   change_tracker()->OnRemoveFile(URL(kPath5));  // Recorded as 'delete'.
    132 
    133   FileSystemURLSet urls;
    134   file_system_.GetChangedURLsInTracker(&urls);
    135 
    136   EXPECT_EQ(5U, urls.size());
    137   EXPECT_TRUE(ContainsKey(urls, URL(kPath1)));
    138   EXPECT_TRUE(ContainsKey(urls, URL(kPath2)));
    139   EXPECT_TRUE(ContainsKey(urls, URL(kPath3)));
    140   EXPECT_TRUE(ContainsKey(urls, URL(kPath4)));
    141   EXPECT_TRUE(ContainsKey(urls, URL(kPath5)));
    142 
    143   // Changes for kPath0 must have been offset and removed.
    144   EXPECT_FALSE(ContainsKey(urls, URL(kPath0)));
    145 
    146   // GetNextChangedURLs only returns up to max_urls (i.e. 3) urls.
    147   std::deque<FileSystemURL> urls_to_process;
    148   change_tracker()->GetNextChangedURLs(&urls_to_process, 3);
    149   ASSERT_EQ(3U, urls_to_process.size());
    150 
    151   // Let it return all.
    152   urls_to_process.clear();
    153   change_tracker()->GetNextChangedURLs(&urls_to_process, 0);
    154   ASSERT_EQ(5U, urls_to_process.size());
    155 
    156   // The changes must be in the last-modified-time order.
    157   EXPECT_EQ(URL(kPath1), urls_to_process[0]);
    158   EXPECT_EQ(URL(kPath2), urls_to_process[1]);
    159   EXPECT_EQ(URL(kPath3), urls_to_process[2]);
    160   EXPECT_EQ(URL(kPath4), urls_to_process[3]);
    161   EXPECT_EQ(URL(kPath5), urls_to_process[4]);
    162 
    163   // Modify kPath4 again.
    164   change_tracker()->OnModifyFile(URL(kPath4));
    165 
    166   // Now the order must be changed.
    167   urls_to_process.clear();
    168   change_tracker()->GetNextChangedURLs(&urls_to_process, 0);
    169   ASSERT_EQ(5U, urls_to_process.size());
    170   EXPECT_EQ(URL(kPath1), urls_to_process[0]);
    171   EXPECT_EQ(URL(kPath2), urls_to_process[1]);
    172   EXPECT_EQ(URL(kPath3), urls_to_process[2]);
    173   EXPECT_EQ(URL(kPath5), urls_to_process[3]);
    174   EXPECT_EQ(URL(kPath4), urls_to_process[4]);
    175 
    176   VerifyAndClearChange(URL(kPath1),
    177                FileChange(FileChange::FILE_CHANGE_DELETE,
    178                           sync_file_system::SYNC_FILE_TYPE_DIRECTORY));
    179   VerifyAndClearChange(URL(kPath2),
    180                FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
    181                           sync_file_system::SYNC_FILE_TYPE_DIRECTORY));
    182   VerifyAndClearChange(URL(kPath3),
    183                FileChange(FileChange::FILE_CHANGE_DELETE,
    184                           sync_file_system::SYNC_FILE_TYPE_FILE));
    185   VerifyAndClearChange(URL(kPath4),
    186                FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
    187                           sync_file_system::SYNC_FILE_TYPE_FILE));
    188   VerifyAndClearChange(URL(kPath5),
    189                FileChange(FileChange::FILE_CHANGE_DELETE,
    190                           sync_file_system::SYNC_FILE_TYPE_FILE));
    191 }
    192 
    193 TEST_F(LocalFileChangeTrackerTest, RestoreCreateAndModifyChanges) {
    194   EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_.OpenFileSystem());
    195 
    196   FileSystemURLSet urls;
    197 
    198   const char kPath0[] = "file a";
    199   const char kPath1[] = "dir a";
    200   const char kPath2[] = "dir a/dir";
    201   const char kPath3[] = "dir a/file a";
    202   const char kPath4[] = "dir a/file b";
    203 
    204   file_system_.GetChangedURLsInTracker(&urls);
    205   ASSERT_EQ(0U, urls.size());
    206 
    207   const GURL blob_url("blob:test");
    208   const std::string kData("Lorem ipsum.");
    209   MockBlobURLRequestContext url_request_context(file_system_context());
    210   ScopedTextBlob blob(url_request_context, blob_url, kData);
    211 
    212   // Create files and nested directories.
    213   EXPECT_EQ(base::PLATFORM_FILE_OK,
    214             file_system_.CreateFile(URL(kPath0)));       // Creates a file.
    215   EXPECT_EQ(base::PLATFORM_FILE_OK,
    216             file_system_.CreateDirectory(URL(kPath1)));  // Creates a dir.
    217   EXPECT_EQ(base::PLATFORM_FILE_OK,
    218             file_system_.CreateDirectory(URL(kPath2)));  // Creates another dir.
    219   EXPECT_EQ(base::PLATFORM_FILE_OK,
    220             file_system_.CreateFile(URL(kPath3)));       // Creates a file.
    221   EXPECT_EQ(base::PLATFORM_FILE_OK,
    222             file_system_.TruncateFile(URL(kPath3), 1));  // Modifies the file.
    223   EXPECT_EQ(base::PLATFORM_FILE_OK,
    224             file_system_.CreateFile(URL(kPath4)));    // Creates another file.
    225   EXPECT_EQ(static_cast<int64>(kData.size()),
    226             file_system_.Write(&url_request_context,
    227                                URL(kPath4), blob_url));  // Modifies the file.
    228 
    229   // Verify the changes.
    230   file_system_.GetChangedURLsInTracker(&urls);
    231   EXPECT_EQ(5U, urls.size());
    232 
    233   // Reset the changes in in-memory tracker.
    234   DropChangesInTracker();
    235 
    236   // Make sure we have no in-memory changes in the tracker.
    237   file_system_.GetChangedURLsInTracker(&urls);
    238   ASSERT_EQ(0U, urls.size());
    239 
    240   RestoreChangesFromTrackerDB();
    241 
    242   // Make sure the changes are restored from the DB.
    243   file_system_.GetChangedURLsInTracker(&urls);
    244   EXPECT_EQ(5U, urls.size());
    245 
    246   VerifyAndClearChange(URL(kPath0),
    247                        FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
    248                                   sync_file_system::SYNC_FILE_TYPE_FILE));
    249   VerifyAndClearChange(URL(kPath1),
    250                        FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
    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_ADD_OR_UPDATE,
    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 }
    262 
    263 TEST_F(LocalFileChangeTrackerTest, RestoreRemoveChanges) {
    264   EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_.OpenFileSystem());
    265 
    266   FileSystemURLSet urls;
    267 
    268   const char kPath0[] = "file";
    269   const char kPath1[] = "dir a";
    270   const char kPath2[] = "dir b";
    271   const char kPath3[] = "dir b/file";
    272   const char kPath4[] = "dir b/dir c";
    273   const char kPath5[] = "dir b/dir c/file";
    274 
    275   file_system_.GetChangedURLsInTracker(&urls);
    276   ASSERT_EQ(0U, urls.size());
    277 
    278   // Creates and removes a same file.
    279   EXPECT_EQ(base::PLATFORM_FILE_OK,
    280             file_system_.CreateFile(URL(kPath0)));
    281   EXPECT_EQ(base::PLATFORM_FILE_OK,
    282             file_system_.Remove(URL(kPath0), false /* recursive */));
    283 
    284   // Creates and removes a same directory.
    285   EXPECT_EQ(base::PLATFORM_FILE_OK,
    286             file_system_.CreateDirectory(URL(kPath1)));
    287   EXPECT_EQ(base::PLATFORM_FILE_OK,
    288             file_system_.Remove(URL(kPath1), false /* recursive */));
    289 
    290   // Creates files and nested directories, then removes the parent directory.
    291   EXPECT_EQ(base::PLATFORM_FILE_OK,
    292             file_system_.CreateDirectory(URL(kPath2)));
    293   EXPECT_EQ(base::PLATFORM_FILE_OK,
    294             file_system_.CreateFile(URL(kPath3)));
    295   EXPECT_EQ(base::PLATFORM_FILE_OK,
    296             file_system_.CreateDirectory(URL(kPath4)));
    297   EXPECT_EQ(base::PLATFORM_FILE_OK,
    298             file_system_.CreateFile(URL(kPath5)));
    299   EXPECT_EQ(base::PLATFORM_FILE_OK,
    300             file_system_.Remove(URL(kPath2), true /* recursive */));
    301 
    302   file_system_.GetChangedURLsInTracker(&urls);
    303   EXPECT_EQ(3U, urls.size());
    304 
    305   DropChangesInTracker();
    306 
    307   // Make sure we have no in-memory changes in the tracker.
    308   file_system_.GetChangedURLsInTracker(&urls);
    309   ASSERT_EQ(0U, urls.size());
    310 
    311   RestoreChangesFromTrackerDB();
    312 
    313   // Make sure the changes are restored from the DB.
    314   file_system_.GetChangedURLsInTracker(&urls);
    315   // Since directories to have been reverted (kPath1, kPath2, kPath4) are
    316   // treated as FILE_CHANGE_DELETE, the number of changes should be 6.
    317   EXPECT_EQ(6U, urls.size());
    318 
    319   VerifyAndClearChange(URL(kPath0),
    320                        FileChange(FileChange::FILE_CHANGE_DELETE,
    321                                   sync_file_system::SYNC_FILE_TYPE_UNKNOWN));
    322   VerifyAndClearChange(URL(kPath1),
    323                        FileChange(FileChange::FILE_CHANGE_DELETE,
    324                                   sync_file_system::SYNC_FILE_TYPE_UNKNOWN));
    325   VerifyAndClearChange(URL(kPath2),
    326                        FileChange(FileChange::FILE_CHANGE_DELETE,
    327                                   sync_file_system::SYNC_FILE_TYPE_UNKNOWN));
    328   VerifyAndClearChange(URL(kPath3),
    329                        FileChange(FileChange::FILE_CHANGE_DELETE,
    330                                   sync_file_system::SYNC_FILE_TYPE_UNKNOWN));
    331   VerifyAndClearChange(URL(kPath4),
    332                        FileChange(FileChange::FILE_CHANGE_DELETE,
    333                                   sync_file_system::SYNC_FILE_TYPE_UNKNOWN));
    334   VerifyAndClearChange(URL(kPath5),
    335                        FileChange(FileChange::FILE_CHANGE_DELETE,
    336                                   sync_file_system::SYNC_FILE_TYPE_UNKNOWN));
    337 }
    338 
    339 TEST_F(LocalFileChangeTrackerTest, RestoreCopyChanges) {
    340   EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_.OpenFileSystem());
    341 
    342   FileSystemURLSet urls;
    343 
    344   const char kPath0[] = "file a";
    345   const char kPath1[] = "dir a";
    346   const char kPath2[] = "dir a/dir";
    347   const char kPath3[] = "dir a/file a";
    348   const char kPath4[] = "dir a/file b";
    349 
    350   const char kPath0Copy[] = "file b";      // To be copied from kPath0
    351   const char kPath1Copy[] = "dir b";       // To be copied from kPath1
    352   const char kPath2Copy[] = "dir b/dir";   // To be copied from kPath2
    353   const char kPath3Copy[] = "dir b/file a";  // To be copied from kPath3
    354   const char kPath4Copy[] = "dir b/file b";  // To be copied from kPath4
    355 
    356   file_system_.GetChangedURLsInTracker(&urls);
    357   ASSERT_EQ(0U, urls.size());
    358 
    359   const GURL blob_url("blob:test");
    360   const std::string kData("Lorem ipsum.");
    361   MockBlobURLRequestContext url_request_context(file_system_context());
    362   ScopedTextBlob blob(url_request_context, blob_url, 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,
    379                                URL(kPath4), blob_url));  // Modifies the file.
    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 children in the deleted directory cannot be restored,
    496   // so we will only have 7 changes.
    497   EXPECT_EQ(7U, 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(kPath5),
    506                        FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
    507                                   sync_file_system::SYNC_FILE_TYPE_FILE));
    508   VerifyAndClearChange(URL(kPath6),
    509                        FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
    510                                   sync_file_system::SYNC_FILE_TYPE_DIRECTORY));
    511   VerifyAndClearChange(URL(kPath7),
    512                        FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
    513                                   sync_file_system::SYNC_FILE_TYPE_FILE));
    514   VerifyAndClearChange(URL(kPath8),
    515                        FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
    516                                   sync_file_system::SYNC_FILE_TYPE_DIRECTORY));
    517   VerifyAndClearChange(URL(kPath9),
    518                        FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
    519                                   sync_file_system::SYNC_FILE_TYPE_FILE));
    520 }
    521 
    522 TEST_F(LocalFileChangeTrackerTest, NextChangedURLsWithRecursiveCopy) {
    523   EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_.OpenFileSystem());
    524 
    525   FileSystemURLSet urls;
    526 
    527   const char kPath0[] = "dir a";
    528   const char kPath1[] = "dir a/file";
    529   const char kPath2[] = "dir a/dir";
    530 
    531   const char kPath0Copy[] = "dir b";
    532   const char kPath1Copy[] = "dir b/file";
    533   const char kPath2Copy[] = "dir b/dir";
    534 
    535   // Creates kPath0,1,2 and then copies them all.
    536   EXPECT_EQ(base::PLATFORM_FILE_OK,
    537             file_system_.CreateDirectory(URL(kPath0)));
    538   EXPECT_EQ(base::PLATFORM_FILE_OK,
    539             file_system_.CreateFile(URL(kPath1)));
    540   EXPECT_EQ(base::PLATFORM_FILE_OK,
    541             file_system_.CreateDirectory(URL(kPath2)));
    542   EXPECT_EQ(base::PLATFORM_FILE_OK,
    543             file_system_.Copy(URL(kPath0), URL(kPath0Copy)));
    544 
    545   std::deque<FileSystemURL> urls_to_process;
    546   change_tracker()->GetNextChangedURLs(&urls_to_process, 0);
    547   ASSERT_EQ(6U, urls_to_process.size());
    548 
    549   // Creation must have occured first.
    550   EXPECT_EQ(URL(kPath0), urls_to_process[0]);
    551   EXPECT_EQ(URL(kPath1), urls_to_process[1]);
    552   EXPECT_EQ(URL(kPath2), urls_to_process[2]);
    553 
    554   // Then recursive copy took place. The exact order cannot be determined
    555   // but the parent directory must have been created first.
    556   EXPECT_EQ(URL(kPath0Copy), urls_to_process[3]);
    557   EXPECT_TRUE(URL(kPath1Copy) == urls_to_process[4] ||
    558               URL(kPath2Copy) == urls_to_process[4]);
    559   EXPECT_TRUE(URL(kPath1Copy) == urls_to_process[5] ||
    560               URL(kPath2Copy) == urls_to_process[5]);
    561 }
    562 
    563 TEST_F(LocalFileChangeTrackerTest, NextChangedURLsWithRecursiveRemove) {
    564   EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_.OpenFileSystem());
    565 
    566   FileSystemURLSet urls;
    567 
    568   const char kPath0[] = "dir a";
    569   const char kPath1[] = "dir a/file1";
    570   const char kPath2[] = "dir a/file2";
    571 
    572   // Creates kPath0,1,2 and then removes them all.
    573   EXPECT_EQ(base::PLATFORM_FILE_OK,
    574             file_system_.CreateDirectory(URL(kPath0)));
    575   EXPECT_EQ(base::PLATFORM_FILE_OK,
    576             file_system_.CreateFile(URL(kPath1)));
    577   EXPECT_EQ(base::PLATFORM_FILE_OK,
    578             file_system_.CreateFile(URL(kPath2)));
    579   EXPECT_EQ(base::PLATFORM_FILE_OK,
    580             file_system_.Remove(URL(kPath0), true /* recursive */));
    581 
    582   std::deque<FileSystemURL> urls_to_process;
    583   change_tracker()->GetNextChangedURLs(&urls_to_process, 0);
    584 
    585   // This is actually not really desirable, but since the directory
    586   // creation and deletion have been offset now we only have two
    587   // file deletion changes.
    588   //
    589   // NOTE: This will cause 2 local sync for deleting nonexistent files
    590   // on the remote side.
    591   //
    592   // TODO(kinuko): For micro optimization we could probably restore the ADD
    593   // change type (other than ADD_OR_UPDATE) and offset file ADD+DELETE
    594   // changes too.
    595   ASSERT_EQ(2U, urls_to_process.size());
    596 
    597   // The exact order of recursive removal cannot be determined.
    598   EXPECT_TRUE(URL(kPath1) == urls_to_process[0] ||
    599               URL(kPath2) == urls_to_process[0]);
    600   EXPECT_TRUE(URL(kPath1) == urls_to_process[1] ||
    601               URL(kPath2) == urls_to_process[1]);
    602 }
    603 
    604 }  // namespace sync_file_system
    605