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/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"
35 namespace sync_file_system {
36 namespace drive_backend {
40 fileapi::FileSystemURL URL(const GURL& origin,
41 const std::string& path) {
42 return CreateSyncableFileSystemURL(
43 origin, base::FilePath::FromUTF8Unsafe(path));
48 class LocalToRemoteSyncerTest : public testing::Test,
49 public SyncEngineContext {
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 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"));
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);
71 RegisterSyncableFileSystem();
74 virtual void TearDown() OVERRIDE {
75 RevokeSyncableFileSystem();
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();
85 void InitializeMetadataDatabase() {
86 SyncEngineInitializer initializer(this,
87 base::MessageLoopProxy::current(),
88 fake_drive_service_.get(),
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();
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);
107 virtual drive::DriveServiceInterface* GetDriveService() OVERRIDE {
108 return fake_drive_service_.get();
111 virtual drive::DriveUploaderInterface* GetDriveUploader() OVERRIDE {
112 return drive_uploader_.get();
115 virtual MetadataDatabase* GetMetadataDatabase() OVERRIDE {
116 return metadata_database_.get();
119 virtual RemoteChangeProcessor* GetRemoteChangeProcessor() OVERRIDE {
120 return fake_remote_change_processor_.get();
123 virtual base::SequencedTaskRunner* GetBlockingTaskRunner() OVERRIDE {
124 return base::MessageLoopProxy::current().get();
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;
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));
145 std::string CreateRemoteFile(const std::string& parent_folder_id,
146 const std::string& title,
147 const std::string& content) {
149 EXPECT_EQ(google_apis::HTTP_SUCCESS,
150 fake_drive_helper_->AddFile(
151 parent_folder_id, title, content, &file_id));
155 void DeleteResource(const std::string& file_id) {
156 EXPECT_EQ(google_apis::HTTP_NO_CONTENT,
157 fake_drive_helper_->DeleteResource(file_id));
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();
172 SyncStatusCode ListChanges() {
173 ListChangesTask list_changes(this);
174 SyncStatusCode status = SYNC_STATUS_UNKNOWN;
175 list_changes.Run(CreateResultReceiver(&status));
176 base::RunLoop().RunUntilIdle();
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();
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();
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();
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());
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());
228 content::TestBrowserThreadBundle thread_bundle_;
229 base::ScopedTempDir database_dir_;
230 scoped_ptr<leveldb::Env> in_memory_env_;
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_;
238 DISALLOW_COPY_AND_ASSIGN(LocalToRemoteSyncerTest);
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);
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")));
261 std::string folder_id = GetFileIDForParentAndTitle(app_root, "folder");
262 ASSERT_FALSE(folder_id.empty());
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);
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);
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")));
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());
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);
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);
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")));
316 VerifyTitleUniqueness(app_root, "file", google_apis::ENTRY_KIND_FILE);
317 VerifyTitleUniqueness(app_root, "folder", google_apis::ENTRY_KIND_FOLDER);
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")));
328 VerifyFileDeletion(app_root, "file");
329 VerifyFileDeletion(app_root, "folder");
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);
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")));
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());
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);
361 CreateRemoteFile(app_root, "foo", "data");
362 EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
364 EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
365 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
366 SYNC_FILE_TYPE_DIRECTORY),
367 URL(kOrigin, "foo")));
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());
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);
384 CreateRemoteFile(app_root, "foo", "data");
385 EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
387 EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
388 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
389 SYNC_FILE_TYPE_FILE),
390 URL(kOrigin, "foo")));
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());
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);
407 const std::string file_id = CreateRemoteFile(app_root, "foo", "data");
408 EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
410 SyncStatusCode status;
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);
418 DeleteResource(file_id);
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")));
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());
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);
444 const std::string file_id = CreateRemoteFile(app_root, "foo", "data");
445 EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
446 SyncStatusCode status;
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);
454 DeleteResource(file_id);
456 EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
458 EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
459 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
460 SYNC_FILE_TYPE_FILE),
461 URL(kOrigin, "foo")));
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());
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);
478 const std::string folder_id = CreateRemoteFolder(app_root, "foo");
480 EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
481 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
482 SYNC_FILE_TYPE_DIRECTORY),
483 URL(kOrigin, "foo")));
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());
496 EXPECT_TRUE(GetMetadataDatabase()->FindTrackersByFileID(
497 folder_id, &trackers));
498 EXPECT_EQ(1u, trackers.size());
499 ASSERT_TRUE(trackers.has_active());
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);
509 DeleteResource(app_root);
510 EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
511 SyncStatusCode status;
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);
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")));
524 // SyncEngine will re-register the app and resurrect the app root later.
527 } // namespace drive_backend
528 } // namespace sync_file_system