Home | History | Annotate | Download | only in drive_backend
      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/drive_backend/remote_to_local_syncer.h"
      6 
      7 #include <map>
      8 
      9 #include "base/bind.h"
     10 #include "base/callback.h"
     11 #include "base/files/scoped_temp_dir.h"
     12 #include "base/logging.h"
     13 #include "base/run_loop.h"
     14 #include "base/thread_task_runner_handle.h"
     15 #include "chrome/browser/drive/drive_uploader.h"
     16 #include "chrome/browser/drive/fake_drive_service.h"
     17 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h"
     18 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_test_util.h"
     19 #include "chrome/browser/sync_file_system/drive_backend/fake_drive_service_helper.h"
     20 #include "chrome/browser/sync_file_system/drive_backend/list_changes_task.h"
     21 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
     22 #include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h"
     23 #include "chrome/browser/sync_file_system/drive_backend/sync_engine_initializer.h"
     24 #include "chrome/browser/sync_file_system/drive_backend/sync_task_manager.h"
     25 #include "chrome/browser/sync_file_system/drive_backend/sync_task_token.h"
     26 #include "chrome/browser/sync_file_system/fake_remote_change_processor.h"
     27 #include "chrome/browser/sync_file_system/sync_file_system_test_util.h"
     28 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
     29 #include "content/public/test/test_browser_thread_bundle.h"
     30 #include "google_apis/drive/gdata_errorcode.h"
     31 #include "testing/gtest/include/gtest/gtest.h"
     32 #include "third_party/leveldatabase/src/helpers/memenv/memenv.h"
     33 #include "third_party/leveldatabase/src/include/leveldb/env.h"
     34 
     35 namespace sync_file_system {
     36 namespace drive_backend {
     37 
     38 namespace {
     39 
     40 storage::FileSystemURL URL(const GURL& origin, const std::string& path) {
     41   return CreateSyncableFileSystemURL(
     42       origin, base::FilePath::FromUTF8Unsafe(path));
     43 }
     44 
     45 }  // namespace
     46 
     47 class RemoteToLocalSyncerTest : public testing::Test {
     48  public:
     49   typedef FakeRemoteChangeProcessor::URLToFileChangesMap URLToFileChangesMap;
     50 
     51   RemoteToLocalSyncerTest()
     52       : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
     53   virtual ~RemoteToLocalSyncerTest() {}
     54 
     55   virtual void SetUp() OVERRIDE {
     56     ASSERT_TRUE(database_dir_.CreateUniqueTempDir());
     57     in_memory_env_.reset(leveldb::NewMemEnv(leveldb::Env::Default()));
     58 
     59     scoped_ptr<drive::FakeDriveService>
     60         fake_drive_service(new drive::FakeDriveService);
     61 
     62     scoped_ptr<drive::DriveUploaderInterface>
     63         drive_uploader(new drive::DriveUploader(
     64             fake_drive_service.get(),
     65             base::ThreadTaskRunnerHandle::Get().get()));
     66     fake_drive_helper_.reset(
     67         new FakeDriveServiceHelper(fake_drive_service.get(),
     68                                    drive_uploader.get(),
     69                                    kSyncRootFolderTitle));
     70     remote_change_processor_.reset(new FakeRemoteChangeProcessor);
     71 
     72     context_.reset(new SyncEngineContext(
     73         fake_drive_service.PassAs<drive::DriveServiceInterface>(),
     74         drive_uploader.Pass(),
     75         NULL,
     76         base::ThreadTaskRunnerHandle::Get(),
     77         base::ThreadTaskRunnerHandle::Get()));
     78     context_->SetRemoteChangeProcessor(remote_change_processor_.get());
     79 
     80     RegisterSyncableFileSystem();
     81 
     82     sync_task_manager_.reset(new SyncTaskManager(
     83         base::WeakPtr<SyncTaskManager::Client>(),
     84         10 /* max_parallel_task */,
     85         base::ThreadTaskRunnerHandle::Get()));
     86     sync_task_manager_->Initialize(SYNC_STATUS_OK);
     87   }
     88 
     89   virtual void TearDown() OVERRIDE {
     90     sync_task_manager_.reset();
     91     RevokeSyncableFileSystem();
     92     fake_drive_helper_.reset();
     93     context_.reset();
     94     base::RunLoop().RunUntilIdle();
     95   }
     96 
     97   void InitializeMetadataDatabase() {
     98     SyncEngineInitializer* initializer =
     99         new SyncEngineInitializer(context_.get(),
    100                                   database_dir_.path(),
    101                                   in_memory_env_.get());
    102     SyncStatusCode status = SYNC_STATUS_UNKNOWN;
    103     sync_task_manager_->ScheduleSyncTask(
    104         FROM_HERE,
    105         scoped_ptr<SyncTask>(initializer),
    106         SyncTaskManager::PRIORITY_MED,
    107         base::Bind(&RemoteToLocalSyncerTest::DidInitializeMetadataDatabase,
    108                    base::Unretained(this),
    109                    initializer, &status));
    110 
    111     base::RunLoop().RunUntilIdle();
    112     EXPECT_EQ(SYNC_STATUS_OK, status);
    113   }
    114 
    115   void DidInitializeMetadataDatabase(SyncEngineInitializer* initializer,
    116                                      SyncStatusCode* status_out,
    117                                      SyncStatusCode status) {
    118     *status_out = status;
    119     context_->SetMetadataDatabase(initializer->PassMetadataDatabase());
    120   }
    121 
    122 
    123   void RegisterApp(const std::string& app_id,
    124                    const std::string& app_root_folder_id) {
    125     SyncStatusCode status = context_->GetMetadataDatabase()->RegisterApp(
    126         app_id, app_root_folder_id);
    127     EXPECT_EQ(SYNC_STATUS_OK, status);
    128   }
    129 
    130   MetadataDatabase* GetMetadataDatabase() {
    131     return context_->GetMetadataDatabase();
    132   }
    133 
    134  protected:
    135   std::string CreateSyncRoot() {
    136     std::string sync_root_folder_id;
    137     EXPECT_EQ(google_apis::HTTP_CREATED,
    138               fake_drive_helper_->AddOrphanedFolder(
    139                   kSyncRootFolderTitle, &sync_root_folder_id));
    140     return sync_root_folder_id;
    141   }
    142 
    143   std::string CreateRemoteFolder(const std::string& parent_folder_id,
    144                                  const std::string& title) {
    145     std::string folder_id;
    146     EXPECT_EQ(google_apis::HTTP_CREATED,
    147               fake_drive_helper_->AddFolder(
    148                   parent_folder_id, title, &folder_id));
    149     return folder_id;
    150   }
    151 
    152   std::string CreateRemoteFile(const std::string& parent_folder_id,
    153                                const std::string& title,
    154                                const std::string& content) {
    155     std::string file_id;
    156     EXPECT_EQ(google_apis::HTTP_SUCCESS,
    157               fake_drive_helper_->AddFile(
    158                   parent_folder_id, title, content, &file_id));
    159     return file_id;
    160   }
    161 
    162   void DeleteRemoteFile(const std::string& file_id) {
    163     EXPECT_EQ(google_apis::HTTP_NO_CONTENT,
    164               fake_drive_helper_->DeleteResource(file_id));
    165   }
    166 
    167   void CreateLocalFolder(const storage::FileSystemURL& url) {
    168     remote_change_processor_->UpdateLocalFileMetadata(
    169         url, FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
    170                         SYNC_FILE_TYPE_DIRECTORY));
    171   }
    172 
    173   void CreateLocalFile(const storage::FileSystemURL& url) {
    174     remote_change_processor_->UpdateLocalFileMetadata(
    175         url, FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
    176                         SYNC_FILE_TYPE_FILE));
    177   }
    178 
    179   SyncStatusCode RunSyncer() {
    180     SyncStatusCode status = SYNC_STATUS_UNKNOWN;
    181     scoped_ptr<RemoteToLocalSyncer>
    182         syncer(new RemoteToLocalSyncer(context_.get()));
    183     syncer->RunPreflight(SyncTaskToken::CreateForTesting(
    184         CreateResultReceiver(&status)));
    185     base::RunLoop().RunUntilIdle();
    186     return status;
    187   }
    188 
    189   SyncStatusCode RunSyncerUntilIdle() {
    190     const int kRetryLimit = 100;
    191     SyncStatusCode status = SYNC_STATUS_UNKNOWN;
    192     int count = 0;
    193     do {
    194       if (count++ > kRetryLimit)
    195         return status;
    196       status = RunSyncer();
    197     } while (status == SYNC_STATUS_OK ||
    198              status == SYNC_STATUS_RETRY);
    199     return status;
    200   }
    201 
    202   SyncStatusCode RunSyncerAndPromoteUntilIdle() {
    203     const int kRetryLimit = 100;
    204     SyncStatusCode status = SYNC_STATUS_UNKNOWN;
    205     MetadataDatabase* metadata_database = context_->GetMetadataDatabase();
    206     int count = 0;
    207     do {
    208       if (count++ > kRetryLimit)
    209         return status;
    210       status = RunSyncer();
    211     } while (status == SYNC_STATUS_OK ||
    212              status == SYNC_STATUS_RETRY ||
    213              metadata_database->PromoteDemotedTrackers());
    214     return status;
    215   }
    216 
    217   SyncStatusCode ListChanges() {
    218     SyncStatusCode status = SYNC_STATUS_UNKNOWN;
    219     sync_task_manager_->ScheduleSyncTask(
    220         FROM_HERE,
    221         scoped_ptr<SyncTask>(new ListChangesTask(context_.get())),
    222         SyncTaskManager::PRIORITY_MED,
    223         CreateResultReceiver(&status));
    224     base::RunLoop().RunUntilIdle();
    225     return status;
    226   }
    227 
    228   void AppendExpectedChange(const storage::FileSystemURL& url,
    229                             FileChange::ChangeType change_type,
    230                             SyncFileType file_type) {
    231     expected_changes_[url].push_back(FileChange(change_type, file_type));
    232   }
    233 
    234   void VerifyConsistency() {
    235     remote_change_processor_->VerifyConsistency(expected_changes_);
    236   }
    237 
    238  private:
    239   content::TestBrowserThreadBundle thread_bundle_;
    240   base::ScopedTempDir database_dir_;
    241   scoped_ptr<leveldb::Env> in_memory_env_;
    242 
    243   scoped_ptr<SyncEngineContext> context_;
    244   scoped_ptr<FakeDriveServiceHelper> fake_drive_helper_;
    245   scoped_ptr<FakeRemoteChangeProcessor> remote_change_processor_;
    246 
    247   scoped_ptr<SyncTaskManager> sync_task_manager_;
    248 
    249   URLToFileChangesMap expected_changes_;
    250 
    251   DISALLOW_COPY_AND_ASSIGN(RemoteToLocalSyncerTest);
    252 };
    253 
    254 TEST_F(RemoteToLocalSyncerTest, AddNewFile) {
    255   const GURL kOrigin("chrome-extension://example");
    256   const std::string sync_root = CreateSyncRoot();
    257   const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
    258   InitializeMetadataDatabase();
    259   RegisterApp(kOrigin.host(), app_root);
    260 
    261   const std::string folder1 = CreateRemoteFolder(app_root, "folder1");
    262   const std::string file1 = CreateRemoteFile(app_root, "file1", "data1");
    263   const std::string folder2 = CreateRemoteFolder(folder1, "folder2");
    264   const std::string file2 = CreateRemoteFile(folder1, "file2", "data2");
    265 
    266   EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC, RunSyncerAndPromoteUntilIdle());
    267 
    268   // Create expected changes.
    269   // TODO(nhiroki): Clean up creating URL part.
    270   AppendExpectedChange(URL(kOrigin, "folder1"),
    271                        FileChange::FILE_CHANGE_ADD_OR_UPDATE,
    272                        SYNC_FILE_TYPE_DIRECTORY);
    273   AppendExpectedChange(URL(kOrigin, "file1"),
    274                        FileChange::FILE_CHANGE_ADD_OR_UPDATE,
    275                        SYNC_FILE_TYPE_FILE);
    276   AppendExpectedChange(URL(kOrigin, "folder1/folder2"),
    277                        FileChange::FILE_CHANGE_ADD_OR_UPDATE,
    278                        SYNC_FILE_TYPE_DIRECTORY);
    279   AppendExpectedChange(URL(kOrigin, "folder1/file2"),
    280                        FileChange::FILE_CHANGE_ADD_OR_UPDATE,
    281                        SYNC_FILE_TYPE_FILE);
    282 
    283   VerifyConsistency();
    284 
    285   EXPECT_FALSE(GetMetadataDatabase()->HasDirtyTracker());
    286 }
    287 
    288 TEST_F(RemoteToLocalSyncerTest, DeleteFile) {
    289   const GURL kOrigin("chrome-extension://example");
    290   const std::string sync_root = CreateSyncRoot();
    291   const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
    292   InitializeMetadataDatabase();
    293   RegisterApp(kOrigin.host(), app_root);
    294 
    295   const std::string folder = CreateRemoteFolder(app_root, "folder");
    296   const std::string file = CreateRemoteFile(app_root, "file", "data");
    297 
    298   AppendExpectedChange(URL(kOrigin, "folder"),
    299                        FileChange::FILE_CHANGE_ADD_OR_UPDATE,
    300                        SYNC_FILE_TYPE_DIRECTORY);
    301   AppendExpectedChange(URL(kOrigin, "file"),
    302                        FileChange::FILE_CHANGE_ADD_OR_UPDATE,
    303                        SYNC_FILE_TYPE_FILE);
    304 
    305   EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC, RunSyncerAndPromoteUntilIdle());
    306   VerifyConsistency();
    307 
    308   DeleteRemoteFile(folder);
    309   DeleteRemoteFile(file);
    310 
    311   AppendExpectedChange(URL(kOrigin, "folder"),
    312                        FileChange::FILE_CHANGE_DELETE,
    313                        SYNC_FILE_TYPE_UNKNOWN);
    314   AppendExpectedChange(URL(kOrigin, "file"),
    315                        FileChange::FILE_CHANGE_DELETE,
    316                        SYNC_FILE_TYPE_UNKNOWN);
    317 
    318   EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
    319   EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC, RunSyncerUntilIdle());
    320   VerifyConsistency();
    321 
    322   EXPECT_FALSE(GetMetadataDatabase()->HasDirtyTracker());
    323 }
    324 
    325 TEST_F(RemoteToLocalSyncerTest, DeleteNestedFiles) {
    326   const GURL kOrigin("chrome-extension://example");
    327   const std::string sync_root = CreateSyncRoot();
    328   const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
    329   InitializeMetadataDatabase();
    330   RegisterApp(kOrigin.host(), app_root);
    331 
    332   const std::string folder1 = CreateRemoteFolder(app_root, "folder1");
    333   const std::string file1 = CreateRemoteFile(app_root, "file1", "data1");
    334   const std::string folder2 = CreateRemoteFolder(folder1, "folder2");
    335   const std::string file2 = CreateRemoteFile(folder1, "file2", "data2");
    336 
    337   AppendExpectedChange(URL(kOrigin, "folder1"),
    338                        FileChange::FILE_CHANGE_ADD_OR_UPDATE,
    339                        SYNC_FILE_TYPE_DIRECTORY);
    340   AppendExpectedChange(URL(kOrigin, "file1"),
    341                        FileChange::FILE_CHANGE_ADD_OR_UPDATE,
    342                        SYNC_FILE_TYPE_FILE);
    343   AppendExpectedChange(URL(kOrigin, "folder1/folder2"),
    344                        FileChange::FILE_CHANGE_ADD_OR_UPDATE,
    345                        SYNC_FILE_TYPE_DIRECTORY);
    346   AppendExpectedChange(URL(kOrigin, "folder1/file2"),
    347                        FileChange::FILE_CHANGE_ADD_OR_UPDATE,
    348                        SYNC_FILE_TYPE_FILE);
    349 
    350   EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC, RunSyncerAndPromoteUntilIdle());
    351   VerifyConsistency();
    352 
    353   DeleteRemoteFile(folder1);
    354 
    355   AppendExpectedChange(URL(kOrigin, "folder1"),
    356                        FileChange::FILE_CHANGE_DELETE,
    357                        SYNC_FILE_TYPE_UNKNOWN);
    358   // Changes for descendant files ("folder2" and "file2") should be ignored.
    359 
    360   EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
    361   EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC, RunSyncerUntilIdle());
    362   VerifyConsistency();
    363 
    364   EXPECT_FALSE(GetMetadataDatabase()->HasDirtyTracker());
    365 }
    366 
    367 TEST_F(RemoteToLocalSyncerTest, Conflict_CreateFileOnFolder) {
    368   const GURL kOrigin("chrome-extension://example");
    369   const std::string sync_root = CreateSyncRoot();
    370   const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
    371   InitializeMetadataDatabase();
    372   RegisterApp(kOrigin.host(), app_root);
    373 
    374   CreateLocalFolder(URL(kOrigin, "folder"));
    375   CreateRemoteFile(app_root, "folder", "data");
    376 
    377   // Folder-File conflict happens. File creation should be ignored.
    378 
    379   EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
    380   EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC, RunSyncerUntilIdle());
    381   VerifyConsistency();
    382 
    383   // Tracker for the remote file should has low priority.
    384   EXPECT_FALSE(GetMetadataDatabase()->GetDirtyTracker(NULL));
    385   EXPECT_TRUE(GetMetadataDatabase()->HasDemotedDirtyTracker());
    386 }
    387 
    388 TEST_F(RemoteToLocalSyncerTest, Conflict_CreateFolderOnFile) {
    389   const GURL kOrigin("chrome-extension://example");
    390   const std::string sync_root = CreateSyncRoot();
    391   const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
    392   InitializeMetadataDatabase();
    393   RegisterApp(kOrigin.host(), app_root);
    394 
    395   EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC, RunSyncerUntilIdle());
    396   VerifyConsistency();
    397 
    398   CreateLocalFile(URL(kOrigin, "file"));
    399   CreateRemoteFolder(app_root, "file");
    400 
    401   // File-Folder conflict happens. Folder should override the existing file.
    402   AppendExpectedChange(URL(kOrigin, "file"),
    403                        FileChange::FILE_CHANGE_ADD_OR_UPDATE,
    404                        SYNC_FILE_TYPE_DIRECTORY);
    405 
    406   EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
    407   EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC, RunSyncerUntilIdle());
    408   VerifyConsistency();
    409 
    410   EXPECT_FALSE(GetMetadataDatabase()->HasDirtyTracker());
    411 }
    412 
    413 TEST_F(RemoteToLocalSyncerTest, Conflict_CreateFolderOnFolder) {
    414   const GURL kOrigin("chrome-extension://example");
    415   const std::string sync_root = CreateSyncRoot();
    416   const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
    417   InitializeMetadataDatabase();
    418   RegisterApp(kOrigin.host(), app_root);
    419 
    420   CreateLocalFolder(URL(kOrigin, "folder"));
    421   CreateRemoteFolder(app_root, "folder");
    422 
    423   // Folder-Folder conflict happens. Folder creation should be ignored.
    424 
    425   EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
    426   EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC, RunSyncerUntilIdle());
    427   VerifyConsistency();
    428 
    429   EXPECT_FALSE(GetMetadataDatabase()->HasDirtyTracker());
    430 }
    431 
    432 TEST_F(RemoteToLocalSyncerTest, Conflict_CreateFileOnFile) {
    433   const GURL kOrigin("chrome-extension://example");
    434   const std::string sync_root = CreateSyncRoot();
    435   const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
    436   InitializeMetadataDatabase();
    437   RegisterApp(kOrigin.host(), app_root);
    438 
    439   CreateLocalFile(URL(kOrigin, "file"));
    440   CreateRemoteFile(app_root, "file", "data");
    441 
    442   // File-File conflict happens. File creation should be ignored.
    443 
    444   EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
    445   EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC, RunSyncerUntilIdle());
    446   VerifyConsistency();
    447 
    448   // Tracker for the remote file should be lowered.
    449   EXPECT_FALSE(GetMetadataDatabase()->GetDirtyTracker(NULL));
    450   EXPECT_TRUE(GetMetadataDatabase()->HasDemotedDirtyTracker());
    451 }
    452 
    453 TEST_F(RemoteToLocalSyncerTest, Conflict_CreateNestedFolderOnFile) {
    454   const GURL kOrigin("chrome-extension://example");
    455   const std::string sync_root = CreateSyncRoot();
    456   const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
    457   InitializeMetadataDatabase();
    458   RegisterApp(kOrigin.host(), app_root);
    459 
    460   EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC, RunSyncerUntilIdle());
    461   VerifyConsistency();
    462 
    463   const std::string folder = CreateRemoteFolder(app_root, "folder");
    464   CreateLocalFile(URL(kOrigin, "/folder"));
    465   CreateRemoteFile(folder, "file", "data");
    466 
    467   // File-Folder conflict happens. Folder should override the existing file.
    468   AppendExpectedChange(URL(kOrigin, "/folder"),
    469                        FileChange::FILE_CHANGE_ADD_OR_UPDATE,
    470                        SYNC_FILE_TYPE_DIRECTORY);
    471 
    472   EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
    473   EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC, RunSyncerUntilIdle());
    474   VerifyConsistency();
    475 }
    476 
    477 TEST_F(RemoteToLocalSyncerTest, AppRootDeletion) {
    478   const GURL kOrigin("chrome-extension://example");
    479   const std::string sync_root = CreateSyncRoot();
    480   const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
    481   InitializeMetadataDatabase();
    482   RegisterApp(kOrigin.host(), app_root);
    483 
    484   EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC, RunSyncerUntilIdle());
    485   VerifyConsistency();
    486 
    487   DeleteRemoteFile(app_root);
    488 
    489   AppendExpectedChange(URL(kOrigin, "/"),
    490                        FileChange::FILE_CHANGE_DELETE,
    491                        SYNC_FILE_TYPE_UNKNOWN);
    492 
    493   EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
    494   EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC, RunSyncerUntilIdle());
    495   VerifyConsistency();
    496 
    497   // SyncEngine will re-register the app and resurrect the app root later.
    498 }
    499 
    500 }  // namespace drive_backend
    501 }  // namespace sync_file_system
    502