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