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"
33 namespace sync_file_system {
34 namespace drive_backend {
38 fileapi::FileSystemURL URL(const GURL& origin,
39 const std::string& path) {
40 return CreateSyncableFileSystemURL(
41 origin, base::FilePath::FromUTF8Unsafe(path));
46 class LocalToRemoteSyncerTest : public testing::Test,
47 public SyncEngineContext {
49 LocalToRemoteSyncerTest()
50 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
51 virtual ~LocalToRemoteSyncerTest() {}
53 virtual void SetUp() OVERRIDE {
54 ASSERT_TRUE(database_dir_.CreateUniqueTempDir());
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"));
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);
68 RegisterSyncableFileSystem();
71 virtual void TearDown() OVERRIDE {
72 RevokeSyncableFileSystem();
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();
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();
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);
103 virtual drive::DriveServiceInterface* GetDriveService() OVERRIDE {
104 return fake_drive_service_.get();
107 virtual drive::DriveUploaderInterface* GetDriveUploader() OVERRIDE {
108 return drive_uploader_.get();
111 virtual MetadataDatabase* GetMetadataDatabase() OVERRIDE {
112 return metadata_database_.get();
115 virtual RemoteChangeProcessor* GetRemoteChangeProcessor() OVERRIDE {
116 return fake_remote_change_processor_.get();
119 virtual base::SequencedTaskRunner* GetBlockingTaskRunner() OVERRIDE {
120 return base::MessageLoopProxy::current().get();
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;
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));
141 std::string CreateRemoteFile(const std::string& parent_folder_id,
142 const std::string& title,
143 const std::string& content) {
145 EXPECT_EQ(google_apis::HTTP_SUCCESS,
146 fake_drive_helper_->AddFile(
147 parent_folder_id, title, content, &file_id));
151 void DeleteResource(const std::string& file_id) {
152 EXPECT_EQ(google_apis::HTTP_NO_CONTENT,
153 fake_drive_helper_->DeleteResource(file_id));
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();
168 SyncStatusCode ListChanges() {
169 ListChangesTask list_changes(this);
170 SyncStatusCode status = SYNC_STATUS_UNKNOWN;
171 list_changes.Run(CreateResultReceiver(&status));
172 base::RunLoop().RunUntilIdle();
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();
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();
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();
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());
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());
224 content::TestBrowserThreadBundle thread_bundle_;
225 base::ScopedTempDir database_dir_;
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_;
233 DISALLOW_COPY_AND_ASSIGN(LocalToRemoteSyncerTest);
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);
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")));
256 std::string folder_id = GetFileIDForParentAndTitle(app_root, "folder");
257 ASSERT_FALSE(folder_id.empty());
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);
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);
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")));
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());
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);
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);
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")));
311 VerifyTitleUniqueness(app_root, "file", google_apis::ENTRY_KIND_FILE);
312 VerifyTitleUniqueness(app_root, "folder", google_apis::ENTRY_KIND_FOLDER);
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")));
323 VerifyFileDeletion(app_root, "file");
324 VerifyFileDeletion(app_root, "folder");
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);
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")));
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());
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);
356 CreateRemoteFile(app_root, "foo", "data");
357 EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
359 EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
360 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
361 SYNC_FILE_TYPE_DIRECTORY),
362 URL(kOrigin, "foo")));
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());
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);
379 CreateRemoteFile(app_root, "foo", "data");
380 EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
382 EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
383 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
384 SYNC_FILE_TYPE_FILE),
385 URL(kOrigin, "foo")));
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());
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);
402 const std::string file_id = CreateRemoteFile(app_root, "foo", "data");
403 EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
405 SyncStatusCode status;
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);
413 DeleteResource(file_id);
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")));
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());
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);
439 const std::string file_id = CreateRemoteFile(app_root, "foo", "data");
440 EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
441 SyncStatusCode status;
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);
449 DeleteResource(file_id);
451 EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
453 EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
454 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
455 SYNC_FILE_TYPE_FILE),
456 URL(kOrigin, "foo")));
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());
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);
473 const std::string folder_id = CreateRemoteFolder(app_root, "foo");
475 EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
476 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
477 SYNC_FILE_TYPE_DIRECTORY),
478 URL(kOrigin, "foo")));
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());
491 EXPECT_TRUE(GetMetadataDatabase()->FindTrackersByFileID(
492 folder_id, &trackers));
493 EXPECT_EQ(1u, trackers.size());
494 ASSERT_TRUE(trackers.has_active());
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);
504 DeleteResource(app_root);
505 EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
506 SyncStatusCode status;
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);
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")));
519 // SyncEngine will re-register the app and resurrect the app root later.
522 } // namespace drive_backend
523 } // namespace sync_file_system