Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / sync_file_system / drive_backend / local_to_remote_syncer_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/drive_backend/local_to_remote_syncer.h"
6
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/files/scoped_temp_dir.h"
10 #include "base/logging.h"
11 #include "base/run_loop.h"
12 #include "chrome/browser/drive/drive_api_util.h"
13 #include "chrome/browser/drive/drive_uploader.h"
14 #include "chrome/browser/drive/fake_drive_service.h"
15 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h"
16 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_test_util.h"
17 #include "chrome/browser/sync_file_system/drive_backend/fake_drive_service_helper.h"
18 #include "chrome/browser/sync_file_system/drive_backend/fake_drive_uploader.h"
19 #include "chrome/browser/sync_file_system/drive_backend/list_changes_task.h"
20 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
21 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h"
22 #include "chrome/browser/sync_file_system/drive_backend/remote_to_local_syncer.h"
23 #include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h"
24 #include "chrome/browser/sync_file_system/drive_backend/sync_engine_initializer.h"
25 #include "chrome/browser/sync_file_system/fake_remote_change_processor.h"
26 #include "chrome/browser/sync_file_system/sync_file_system_test_util.h"
27 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
28 #include "content/public/test/test_browser_thread_bundle.h"
29 #include "google_apis/drive/drive_api_parser.h"
30 #include "google_apis/drive/gdata_errorcode.h"
31 #include "testing/gtest/include/gtest/gtest.h"
32
33 namespace sync_file_system {
34 namespace drive_backend {
35
36 namespace {
37
38 fileapi::FileSystemURL URL(const GURL& origin,
39                            const std::string& path) {
40   return CreateSyncableFileSystemURL(
41       origin, base::FilePath::FromUTF8Unsafe(path));
42 }
43
44 }  // namespace
45
46 class LocalToRemoteSyncerTest : public testing::Test,
47                                 public SyncEngineContext {
48  public:
49   LocalToRemoteSyncerTest()
50       : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
51   virtual ~LocalToRemoteSyncerTest() {}
52
53   virtual void SetUp() OVERRIDE {
54     ASSERT_TRUE(database_dir_.CreateUniqueTempDir());
55
56     fake_drive_service_.reset(new FakeDriveServiceWrapper);
57     ASSERT_TRUE(fake_drive_service_->LoadAccountMetadataForWapi(
58         "sync_file_system/account_metadata.json"));
59     ASSERT_TRUE(fake_drive_service_->LoadResourceListForWapi(
60         "gdata/empty_feed.json"));
61
62     drive_uploader_.reset(new FakeDriveUploader(fake_drive_service_.get()));
63     fake_drive_helper_.reset(new FakeDriveServiceHelper(
64         fake_drive_service_.get(), drive_uploader_.get(),
65         kSyncRootFolderTitle));
66     fake_remote_change_processor_.reset(new FakeRemoteChangeProcessor);
67
68     RegisterSyncableFileSystem();
69   }
70
71   virtual void TearDown() OVERRIDE {
72     RevokeSyncableFileSystem();
73
74     fake_remote_change_processor_.reset();
75     metadata_database_.reset();
76     fake_drive_helper_.reset();
77     drive_uploader_.reset();
78     fake_drive_service_.reset();
79     base::RunLoop().RunUntilIdle();
80   }
81
82   void InitializeMetadataDatabase() {
83     SyncEngineInitializer initializer(this,
84                                       base::MessageLoopProxy::current(),
85                                       fake_drive_service_.get(),
86                                       database_dir_.path());
87     SyncStatusCode status = SYNC_STATUS_UNKNOWN;
88     initializer.Run(CreateResultReceiver(&status));
89     base::RunLoop().RunUntilIdle();
90     EXPECT_EQ(SYNC_STATUS_OK, status);
91     metadata_database_ = initializer.PassMetadataDatabase();
92   }
93
94   void RegisterApp(const std::string& app_id,
95                    const std::string& app_root_folder_id) {
96     SyncStatusCode status = SYNC_STATUS_FAILED;
97     metadata_database_->RegisterApp(app_id, app_root_folder_id,
98                                     CreateResultReceiver(&status));
99     base::RunLoop().RunUntilIdle();
100     EXPECT_EQ(SYNC_STATUS_OK, status);
101   }
102
103   virtual drive::DriveServiceInterface* GetDriveService() OVERRIDE {
104     return fake_drive_service_.get();
105   }
106
107   virtual drive::DriveUploaderInterface* GetDriveUploader() OVERRIDE {
108     return drive_uploader_.get();
109   }
110
111   virtual MetadataDatabase* GetMetadataDatabase() OVERRIDE {
112     return metadata_database_.get();
113   }
114
115   virtual RemoteChangeProcessor* GetRemoteChangeProcessor() OVERRIDE {
116     return fake_remote_change_processor_.get();
117   }
118
119   virtual base::SequencedTaskRunner* GetBlockingTaskRunner() OVERRIDE {
120     return base::MessageLoopProxy::current().get();
121   }
122
123  protected:
124   std::string CreateSyncRoot() {
125     std::string sync_root_folder_id;
126     EXPECT_EQ(google_apis::HTTP_CREATED,
127               fake_drive_helper_->AddOrphanedFolder(
128                   kSyncRootFolderTitle, &sync_root_folder_id));
129     return sync_root_folder_id;
130   }
131
132   std::string CreateRemoteFolder(const std::string& parent_folder_id,
133                                  const std::string& title) {
134     std::string folder_id;
135     EXPECT_EQ(google_apis::HTTP_CREATED,
136               fake_drive_helper_->AddFolder(
137                   parent_folder_id, title, &folder_id));
138     return folder_id;
139   }
140
141   std::string CreateRemoteFile(const std::string& parent_folder_id,
142                                const std::string& title,
143                                const std::string& content) {
144     std::string file_id;
145     EXPECT_EQ(google_apis::HTTP_SUCCESS,
146               fake_drive_helper_->AddFile(
147                   parent_folder_id, title, content, &file_id));
148     return file_id;
149   }
150
151   void DeleteResource(const std::string& file_id) {
152     EXPECT_EQ(google_apis::HTTP_NO_CONTENT,
153               fake_drive_helper_->DeleteResource(file_id));
154   }
155
156   SyncStatusCode RunLocalToRemoteSyncer(FileChange file_change,
157                            const fileapi::FileSystemURL& url) {
158     SyncStatusCode status = SYNC_STATUS_UNKNOWN;
159     base::FilePath local_path = base::FilePath::FromUTF8Unsafe("dummy");
160     scoped_ptr<LocalToRemoteSyncer> syncer(new LocalToRemoteSyncer(
161         this, SyncFileMetadata(file_change.file_type(), 0, base::Time()),
162         file_change, local_path, url));
163     syncer->Run(CreateResultReceiver(&status));
164     base::RunLoop().RunUntilIdle();
165     return status;
166   }
167
168   SyncStatusCode ListChanges() {
169     ListChangesTask list_changes(this);
170     SyncStatusCode status = SYNC_STATUS_UNKNOWN;
171     list_changes.Run(CreateResultReceiver(&status));
172     base::RunLoop().RunUntilIdle();
173     return status;
174   }
175
176   SyncStatusCode RunRemoteToLocalSyncer() {
177     SyncStatusCode status = SYNC_STATUS_UNKNOWN;
178     scoped_ptr<RemoteToLocalSyncer> syncer(new RemoteToLocalSyncer(this));
179     syncer->Run(CreateResultReceiver(&status));
180     base::RunLoop().RunUntilIdle();
181     return status;
182   }
183
184   ScopedVector<google_apis::ResourceEntry>
185   GetResourceEntriesForParentAndTitle(const std::string& parent_folder_id,
186                                       const std::string& title) {
187     ScopedVector<google_apis::ResourceEntry> entries;
188     EXPECT_EQ(google_apis::HTTP_SUCCESS,
189               fake_drive_helper_->SearchByTitle(
190                   parent_folder_id, title, &entries));
191     return entries.Pass();
192   }
193
194   std::string GetFileIDForParentAndTitle(const std::string& parent_folder_id,
195                                          const std::string& title) {
196     ScopedVector<google_apis::ResourceEntry> entries =
197         GetResourceEntriesForParentAndTitle(parent_folder_id, title);
198     if (entries.size() != 1)
199       return std::string();
200     return entries[0]->resource_id();
201   }
202
203   void VerifyTitleUniqueness(const std::string& parent_folder_id,
204                              const std::string& title,
205                              google_apis::DriveEntryKind kind) {
206     ScopedVector<google_apis::ResourceEntry> entries;
207     EXPECT_EQ(google_apis::HTTP_SUCCESS,
208               fake_drive_helper_->SearchByTitle(
209                   parent_folder_id, title, &entries));
210     ASSERT_EQ(1u, entries.size());
211     EXPECT_EQ(kind, entries[0]->kind());
212   }
213
214   void VerifyFileDeletion(const std::string& parent_folder_id,
215                           const std::string& title) {
216     ScopedVector<google_apis::ResourceEntry> entries;
217     EXPECT_EQ(google_apis::HTTP_SUCCESS,
218               fake_drive_helper_->SearchByTitle(
219                   parent_folder_id, title, &entries));
220     EXPECT_TRUE(entries.empty());
221   }
222
223  private:
224   content::TestBrowserThreadBundle thread_bundle_;
225   base::ScopedTempDir database_dir_;
226
227   scoped_ptr<FakeDriveServiceWrapper> fake_drive_service_;
228   scoped_ptr<FakeDriveUploader> drive_uploader_;
229   scoped_ptr<FakeDriveServiceHelper> fake_drive_helper_;
230   scoped_ptr<MetadataDatabase> metadata_database_;
231   scoped_ptr<FakeRemoteChangeProcessor> fake_remote_change_processor_;
232
233   DISALLOW_COPY_AND_ASSIGN(LocalToRemoteSyncerTest);
234 };
235
236 TEST_F(LocalToRemoteSyncerTest, CreateFile) {
237   const GURL kOrigin("chrome-extension://example");
238   const std::string sync_root = CreateSyncRoot();
239   const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
240   InitializeMetadataDatabase();
241   RegisterApp(kOrigin.host(), app_root);
242
243   EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
244       FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
245                  SYNC_FILE_TYPE_FILE),
246       URL(kOrigin, "file1")));
247   EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
248       FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
249                  SYNC_FILE_TYPE_DIRECTORY),
250       URL(kOrigin, "folder")));
251   EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
252       FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
253                  SYNC_FILE_TYPE_FILE),
254       URL(kOrigin, "folder/file2")));
255
256   std::string folder_id = GetFileIDForParentAndTitle(app_root, "folder");
257   ASSERT_FALSE(folder_id.empty());
258
259   VerifyTitleUniqueness(app_root, "file1", google_apis::ENTRY_KIND_FILE);
260   VerifyTitleUniqueness(app_root, "folder", google_apis::ENTRY_KIND_FOLDER);
261   VerifyTitleUniqueness(folder_id, "file2", google_apis::ENTRY_KIND_FILE);
262 }
263
264 TEST_F(LocalToRemoteSyncerTest, CreateFileOnMissingPath) {
265   const GURL kOrigin("chrome-extension://example");
266   const std::string sync_root = CreateSyncRoot();
267   const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
268   InitializeMetadataDatabase();
269   RegisterApp(kOrigin.host(), app_root);
270
271   // Run the syncer 3 times to create missing folder1 and folder2.
272   EXPECT_EQ(SYNC_STATUS_RETRY, RunLocalToRemoteSyncer(
273       FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
274                  SYNC_FILE_TYPE_FILE),
275       URL(kOrigin, "folder1/folder2/file")));
276   EXPECT_EQ(SYNC_STATUS_RETRY, RunLocalToRemoteSyncer(
277       FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
278                  SYNC_FILE_TYPE_FILE),
279       URL(kOrigin, "folder1/folder2/file")));
280   EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
281       FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
282                  SYNC_FILE_TYPE_FILE),
283       URL(kOrigin, "folder1/folder2/file")));
284
285   std::string folder_id1 = GetFileIDForParentAndTitle(app_root, "folder1");
286   ASSERT_FALSE(folder_id1.empty());
287   std::string folder_id2 = GetFileIDForParentAndTitle(folder_id1, "folder2");
288   ASSERT_FALSE(folder_id2.empty());
289
290   VerifyTitleUniqueness(app_root, "folder1", google_apis::ENTRY_KIND_FOLDER);
291   VerifyTitleUniqueness(folder_id1, "folder2", google_apis::ENTRY_KIND_FOLDER);
292   VerifyTitleUniqueness(folder_id2, "file", google_apis::ENTRY_KIND_FILE);
293 }
294
295 TEST_F(LocalToRemoteSyncerTest, DeleteFile) {
296   const GURL kOrigin("chrome-extension://example");
297   const std::string sync_root = CreateSyncRoot();
298   const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
299   InitializeMetadataDatabase();
300   RegisterApp(kOrigin.host(), app_root);
301
302   EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
303       FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
304                  SYNC_FILE_TYPE_FILE),
305       URL(kOrigin, "file")));
306   EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
307       FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
308                  SYNC_FILE_TYPE_DIRECTORY),
309       URL(kOrigin, "folder")));
310
311   VerifyTitleUniqueness(app_root, "file", google_apis::ENTRY_KIND_FILE);
312   VerifyTitleUniqueness(app_root, "folder", google_apis::ENTRY_KIND_FOLDER);
313
314   EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
315       FileChange(FileChange::FILE_CHANGE_DELETE,
316                  SYNC_FILE_TYPE_FILE),
317       URL(kOrigin, "file")));
318   EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
319       FileChange(FileChange::FILE_CHANGE_DELETE,
320                  SYNC_FILE_TYPE_DIRECTORY),
321       URL(kOrigin, "folder")));
322
323   VerifyFileDeletion(app_root, "file");
324   VerifyFileDeletion(app_root, "folder");
325 }
326
327 TEST_F(LocalToRemoteSyncerTest, Conflict_CreateFileOnFolder) {
328   const GURL kOrigin("chrome-extension://example");
329   const std::string sync_root = CreateSyncRoot();
330   const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
331   InitializeMetadataDatabase();
332   RegisterApp(kOrigin.host(), app_root);
333
334   CreateRemoteFolder(app_root, "foo");
335   EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
336   EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
337       FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
338                  SYNC_FILE_TYPE_FILE),
339       URL(kOrigin, "foo")));
340
341   // There should exist both file and folder on remote.
342   ScopedVector<google_apis::ResourceEntry> entries =
343       GetResourceEntriesForParentAndTitle(app_root, "foo");
344   ASSERT_EQ(2u, entries.size());
345   EXPECT_EQ(google_apis::ENTRY_KIND_FOLDER, entries[0]->kind());
346   EXPECT_EQ(google_apis::ENTRY_KIND_FILE, entries[1]->kind());
347 }
348
349 TEST_F(LocalToRemoteSyncerTest, Conflict_CreateFolderOnFile) {
350   const GURL kOrigin("chrome-extension://example");
351   const std::string sync_root = CreateSyncRoot();
352   const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
353   InitializeMetadataDatabase();
354   RegisterApp(kOrigin.host(), app_root);
355
356   CreateRemoteFile(app_root, "foo", "data");
357   EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
358
359   EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
360       FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
361                  SYNC_FILE_TYPE_DIRECTORY),
362       URL(kOrigin, "foo")));
363
364   // There should exist both file and folder on remote.
365   ScopedVector<google_apis::ResourceEntry> entries =
366       GetResourceEntriesForParentAndTitle(app_root, "foo");
367   ASSERT_EQ(2u, entries.size());
368   EXPECT_EQ(google_apis::ENTRY_KIND_FILE, entries[0]->kind());
369   EXPECT_EQ(google_apis::ENTRY_KIND_FOLDER, entries[1]->kind());
370 }
371
372 TEST_F(LocalToRemoteSyncerTest, Conflict_CreateFileOnFile) {
373   const GURL kOrigin("chrome-extension://example");
374   const std::string sync_root = CreateSyncRoot();
375   const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
376   InitializeMetadataDatabase();
377   RegisterApp(kOrigin.host(), app_root);
378
379   CreateRemoteFile(app_root, "foo", "data");
380   EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
381
382   EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
383       FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
384                  SYNC_FILE_TYPE_FILE),
385       URL(kOrigin, "foo")));
386
387   // There should exist both files on remote.
388   ScopedVector<google_apis::ResourceEntry> entries =
389       GetResourceEntriesForParentAndTitle(app_root, "foo");
390   ASSERT_EQ(2u, entries.size());
391   EXPECT_EQ(google_apis::ENTRY_KIND_FILE, entries[0]->kind());
392   EXPECT_EQ(google_apis::ENTRY_KIND_FILE, entries[1]->kind());
393 }
394
395 TEST_F(LocalToRemoteSyncerTest, Conflict_UpdateDeleteOnFile) {
396   const GURL kOrigin("chrome-extension://example");
397   const std::string sync_root = CreateSyncRoot();
398   const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
399   InitializeMetadataDatabase();
400   RegisterApp(kOrigin.host(), app_root);
401
402   const std::string file_id = CreateRemoteFile(app_root, "foo", "data");
403   EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
404
405   SyncStatusCode status;
406   do {
407     status = RunRemoteToLocalSyncer();
408     EXPECT_TRUE(status == SYNC_STATUS_OK ||
409                 status == SYNC_STATUS_RETRY ||
410                 status == SYNC_STATUS_NO_CHANGE_TO_SYNC);
411   } while (status != SYNC_STATUS_NO_CHANGE_TO_SYNC);
412
413   DeleteResource(file_id);
414
415   EXPECT_EQ(SYNC_STATUS_FILE_BUSY, RunLocalToRemoteSyncer(
416       FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
417                  SYNC_FILE_TYPE_FILE),
418       URL(kOrigin, "foo")));
419   EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
420       FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
421                  SYNC_FILE_TYPE_FILE),
422       URL(kOrigin, "foo")));
423
424   ScopedVector<google_apis::ResourceEntry> entries =
425       GetResourceEntriesForParentAndTitle(app_root, "foo");
426   ASSERT_EQ(1u, entries.size());
427   EXPECT_EQ(google_apis::ENTRY_KIND_FILE, entries[0]->kind());
428   EXPECT_TRUE(!entries[0]->deleted());
429   EXPECT_NE(file_id, entries[0]->resource_id());
430 }
431
432 TEST_F(LocalToRemoteSyncerTest, Conflict_CreateDeleteOnFile) {
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   const std::string file_id = CreateRemoteFile(app_root, "foo", "data");
440   EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
441   SyncStatusCode status;
442   do {
443     status = RunRemoteToLocalSyncer();
444     EXPECT_TRUE(status == SYNC_STATUS_OK ||
445                 status == SYNC_STATUS_RETRY ||
446                 status == SYNC_STATUS_NO_CHANGE_TO_SYNC);
447   } while (status != SYNC_STATUS_NO_CHANGE_TO_SYNC);
448
449   DeleteResource(file_id);
450
451   EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
452
453   EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
454       FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
455                  SYNC_FILE_TYPE_FILE),
456       URL(kOrigin, "foo")));
457
458   ScopedVector<google_apis::ResourceEntry> entries =
459       GetResourceEntriesForParentAndTitle(app_root, "foo");
460   ASSERT_EQ(1u, entries.size());
461   EXPECT_EQ(google_apis::ENTRY_KIND_FILE, entries[0]->kind());
462   EXPECT_TRUE(!entries[0]->deleted());
463   EXPECT_NE(file_id, entries[0]->resource_id());
464 }
465
466 TEST_F(LocalToRemoteSyncerTest, Conflict_CreateFolderOnFolder) {
467   const GURL kOrigin("chrome-extension://example");
468   const std::string sync_root = CreateSyncRoot();
469   const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
470   InitializeMetadataDatabase();
471   RegisterApp(kOrigin.host(), app_root);
472
473   const std::string folder_id = CreateRemoteFolder(app_root, "foo");
474
475   EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
476       FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
477                  SYNC_FILE_TYPE_DIRECTORY),
478       URL(kOrigin, "foo")));
479
480   ScopedVector<google_apis::ResourceEntry> entries =
481       GetResourceEntriesForParentAndTitle(app_root, "foo");
482   ASSERT_EQ(2u, entries.size());
483   EXPECT_EQ(google_apis::ENTRY_KIND_FOLDER, entries[0]->kind());
484   EXPECT_EQ(google_apis::ENTRY_KIND_FOLDER, entries[1]->kind());
485   EXPECT_TRUE(!entries[0]->deleted());
486   EXPECT_TRUE(!entries[1]->deleted());
487   EXPECT_TRUE(folder_id == entries[0]->resource_id() ||
488               folder_id == entries[1]->resource_id());
489
490   TrackerSet trackers;
491   EXPECT_TRUE(GetMetadataDatabase()->FindTrackersByFileID(
492       folder_id, &trackers));
493   EXPECT_EQ(1u, trackers.size());
494   ASSERT_TRUE(trackers.has_active());
495 }
496
497 TEST_F(LocalToRemoteSyncerTest, AppRootDeletion) {
498   const GURL kOrigin("chrome-extension://example");
499   const std::string sync_root = CreateSyncRoot();
500   const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
501   InitializeMetadataDatabase();
502   RegisterApp(kOrigin.host(), app_root);
503
504   DeleteResource(app_root);
505   EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
506   SyncStatusCode status;
507   do {
508     status = RunRemoteToLocalSyncer();
509     EXPECT_TRUE(status == SYNC_STATUS_OK ||
510                 status == SYNC_STATUS_RETRY ||
511                 status == SYNC_STATUS_NO_CHANGE_TO_SYNC);
512   } while (status != SYNC_STATUS_NO_CHANGE_TO_SYNC);
513
514   EXPECT_EQ(SYNC_STATUS_UNKNOWN_ORIGIN, RunLocalToRemoteSyncer(
515       FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
516                  SYNC_FILE_TYPE_DIRECTORY),
517       URL(kOrigin, "foo")));
518
519   // SyncEngine will re-register the app and resurrect the app root later.
520 }
521
522 }  // namespace drive_backend
523 }  // namespace sync_file_system