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