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