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