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.
5 #include "chrome/browser/sync_file_system/drive_backend/local_to_remote_syncer.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"
36 namespace sync_file_system {
37 namespace drive_backend {
41 fileapi::FileSystemURL URL(const GURL& origin,
42 const std::string& path) {
43 return CreateSyncableFileSystemURL(
44 origin, base::FilePath::FromUTF8Unsafe(path));
49 class LocalToRemoteSyncerTest : public testing::Test {
51 LocalToRemoteSyncerTest()
52 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
53 virtual ~LocalToRemoteSyncerTest() {}
55 virtual void SetUp() OVERRIDE {
56 ASSERT_TRUE(database_dir_.CreateUniqueTempDir());
57 in_memory_env_.reset(leveldb::NewMemEnv(leveldb::Env::Default()));
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(),
66 kSyncRootFolderTitle));
67 remote_change_processor_.reset(new FakeRemoteChangeProcessor);
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());
77 RegisterSyncableFileSystem();
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);
85 virtual void TearDown() OVERRIDE {
86 sync_task_manager_.reset();
87 RevokeSyncableFileSystem();
88 fake_drive_helper_.reset();
90 base::RunLoop().RunUntilIdle();
93 void InitializeMetadataDatabase() {
94 SyncEngineInitializer* initializer =
95 new SyncEngineInitializer(context_.get(),
96 base::MessageLoopProxy::current(),
98 in_memory_env_.get());
99 SyncStatusCode status = SYNC_STATUS_UNKNOWN;
101 sync_task_manager_->ScheduleSyncTask(
103 scoped_ptr<SyncTask>(initializer),
104 SyncTaskManager::PRIORITY_MED,
105 base::Bind(&LocalToRemoteSyncerTest::DidInitializeMetadataDatabase,
106 base::Unretained(this), initializer, &status));
108 base::RunLoop().RunUntilIdle();
109 EXPECT_EQ(SYNC_STATUS_OK, status);
112 void DidInitializeMetadataDatabase(SyncEngineInitializer* initializer,
113 SyncStatusCode* status_out,
114 SyncStatusCode status) {
115 *status_out = status;
116 context_->SetMetadataDatabase(initializer->PassMetadataDatabase());
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);
128 MetadataDatabase* GetMetadataDatabase() {
129 return context_->GetMetadataDatabase();
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;
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));
150 std::string CreateRemoteFile(const std::string& parent_folder_id,
151 const std::string& title,
152 const std::string& content) {
154 EXPECT_EQ(google_apis::HTTP_SUCCESS,
155 fake_drive_helper_->AddFile(
156 parent_folder_id, title, content, &file_id));
160 void DeleteResource(const std::string& file_id) {
161 EXPECT_EQ(google_apis::HTTP_NO_CONTENT,
162 fake_drive_helper_->DeleteResource(file_id));
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(
171 SyncFileMetadata(file_change.file_type(), 0, base::Time()),
172 file_change, local_path, url));
173 syncer->RunExclusive(CreateResultReceiver(&status));
174 base::RunLoop().RunUntilIdle();
178 SyncStatusCode ListChanges() {
179 SyncStatusCode status = SYNC_STATUS_UNKNOWN;
180 sync_task_manager_->ScheduleSyncTask(
182 scoped_ptr<SyncTask>(new ListChangesTask(context_.get())),
183 SyncTaskManager::PRIORITY_MED,
184 CreateResultReceiver(&status));
185 base::RunLoop().RunUntilIdle();
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();
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();
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();
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());
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());
238 content::TestBrowserThreadBundle thread_bundle_;
239 base::ScopedTempDir database_dir_;
240 scoped_ptr<leveldb::Env> in_memory_env_;
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_;
248 DISALLOW_COPY_AND_ASSIGN(LocalToRemoteSyncerTest);
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);
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")));
271 std::string folder_id = GetFileIDForParentAndTitle(app_root, "folder");
272 ASSERT_FALSE(folder_id.empty());
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);
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);
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")));
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());
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);
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);
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")));
326 VerifyTitleUniqueness(app_root, "file", google_apis::ENTRY_KIND_FILE);
327 VerifyTitleUniqueness(app_root, "folder", google_apis::ENTRY_KIND_FOLDER);
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")));
338 VerifyFileDeletion(app_root, "file");
339 VerifyFileDeletion(app_root, "folder");
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);
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")));
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());
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);
371 CreateRemoteFile(app_root, "foo", "data");
372 EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
374 EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
375 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
376 SYNC_FILE_TYPE_DIRECTORY),
377 URL(kOrigin, "foo")));
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());
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);
394 CreateRemoteFile(app_root, "foo", "data");
395 EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
397 EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
398 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
399 SYNC_FILE_TYPE_FILE),
400 URL(kOrigin, "foo")));
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());
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);
417 const std::string file_id = CreateRemoteFile(app_root, "foo", "data");
418 EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
420 SyncStatusCode status;
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);
428 DeleteResource(file_id);
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")));
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());
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);
454 const std::string file_id = CreateRemoteFile(app_root, "foo", "data");
455 EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
456 SyncStatusCode status;
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);
464 DeleteResource(file_id);
466 EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
468 EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
469 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
470 SYNC_FILE_TYPE_FILE),
471 URL(kOrigin, "foo")));
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());
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);
488 const std::string folder_id = CreateRemoteFolder(app_root, "foo");
490 EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
491 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
492 SYNC_FILE_TYPE_DIRECTORY),
493 URL(kOrigin, "foo")));
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());
505 TrackerIDSet trackers;
506 EXPECT_TRUE(GetMetadataDatabase()->FindTrackersByFileID(
507 folder_id, &trackers));
508 EXPECT_EQ(1u, trackers.size());
509 ASSERT_TRUE(trackers.has_active());
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);
519 DeleteResource(app_root);
520 EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
521 SyncStatusCode status;
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);
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")));
534 // SyncEngine will re-register the app and resurrect the app root later.
537 } // namespace drive_backend
538 } // namespace sync_file_system