local_to_remote_syncer_unittest.cc revision 6d86b77056ed63eb6871182f42a9fd5f07550f90
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/drive_backend/sync_task_token.h" 27#include "chrome/browser/sync_file_system/fake_remote_change_processor.h" 28#include "chrome/browser/sync_file_system/sync_file_system_test_util.h" 29#include "chrome/browser/sync_file_system/syncable_file_system_util.h" 30#include "content/public/test/test_browser_thread_bundle.h" 31#include "google_apis/drive/drive_api_parser.h" 32#include "google_apis/drive/gdata_errorcode.h" 33#include "testing/gtest/include/gtest/gtest.h" 34#include "third_party/leveldatabase/src/helpers/memenv/memenv.h" 35#include "third_party/leveldatabase/src/include/leveldb/env.h" 36 37namespace sync_file_system { 38namespace drive_backend { 39 40namespace { 41 42fileapi::FileSystemURL URL(const GURL& origin, 43 const std::string& path) { 44 return CreateSyncableFileSystemURL( 45 origin, base::FilePath::FromUTF8Unsafe(path)); 46} 47 48const int kRetryLimit = 100; 49 50} // namespace 51 52class 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::MessageLoopProxy::current(), 77 base::MessageLoopProxy::current(), 78 base::MessageLoopProxy::current())); 79 context_->SetRemoteChangeProcessor(remote_change_processor_.get()); 80 81 RegisterSyncableFileSystem(); 82 83 sync_task_manager_.reset(new SyncTaskManager( 84 base::WeakPtr<SyncTaskManager::Client>(), 85 10 /* maximum_background_task */, 86 base::MessageLoopProxy::current())); 87 sync_task_manager_->Initialize(SYNC_STATUS_OK); 88 } 89 90 virtual void TearDown() OVERRIDE { 91 sync_task_manager_.reset(); 92 RevokeSyncableFileSystem(); 93 fake_drive_helper_.reset(); 94 context_.reset(); 95 base::RunLoop().RunUntilIdle(); 96 } 97 98 void InitializeMetadataDatabase() { 99 SyncEngineInitializer* initializer = 100 new SyncEngineInitializer(context_.get(), 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->RunPreflight(SyncTaskToken::CreateForTesting( 178 CreateResultReceiver(&status))); 179 base::RunLoop().RunUntilIdle(); 180 return status; 181 } 182 183 SyncStatusCode ListChanges() { 184 SyncStatusCode status = SYNC_STATUS_UNKNOWN; 185 sync_task_manager_->ScheduleSyncTask( 186 FROM_HERE, 187 scoped_ptr<SyncTask>(new ListChangesTask(context_.get())), 188 SyncTaskManager::PRIORITY_MED, 189 CreateResultReceiver(&status)); 190 base::RunLoop().RunUntilIdle(); 191 return status; 192 } 193 194 SyncStatusCode RunRemoteToLocalSyncer() { 195 SyncStatusCode status = SYNC_STATUS_UNKNOWN; 196 scoped_ptr<RemoteToLocalSyncer> 197 syncer(new RemoteToLocalSyncer(context_.get())); 198 syncer->RunExclusive(CreateResultReceiver(&status)); 199 base::RunLoop().RunUntilIdle(); 200 return status; 201 } 202 203 ScopedVector<google_apis::ResourceEntry> 204 GetResourceEntriesForParentAndTitle(const std::string& parent_folder_id, 205 const std::string& title) { 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 return entries.Pass(); 211 } 212 213 std::string GetFileIDForParentAndTitle(const std::string& parent_folder_id, 214 const std::string& title) { 215 ScopedVector<google_apis::ResourceEntry> entries = 216 GetResourceEntriesForParentAndTitle(parent_folder_id, title); 217 if (entries.size() != 1) 218 return std::string(); 219 return entries[0]->resource_id(); 220 } 221 222 void VerifyTitleUniqueness(const std::string& parent_folder_id, 223 const std::string& title, 224 google_apis::DriveEntryKind kind) { 225 ScopedVector<google_apis::ResourceEntry> entries; 226 EXPECT_EQ(google_apis::HTTP_SUCCESS, 227 fake_drive_helper_->SearchByTitle( 228 parent_folder_id, title, &entries)); 229 ASSERT_EQ(1u, entries.size()); 230 EXPECT_EQ(kind, entries[0]->kind()); 231 } 232 233 void VerifyFileDeletion(const std::string& parent_folder_id, 234 const std::string& title) { 235 ScopedVector<google_apis::ResourceEntry> entries; 236 EXPECT_EQ(google_apis::HTTP_SUCCESS, 237 fake_drive_helper_->SearchByTitle( 238 parent_folder_id, title, &entries)); 239 EXPECT_TRUE(entries.empty()); 240 } 241 242 private: 243 content::TestBrowserThreadBundle thread_bundle_; 244 base::ScopedTempDir database_dir_; 245 scoped_ptr<leveldb::Env> in_memory_env_; 246 247 scoped_ptr<SyncEngineContext> context_; 248 scoped_ptr<FakeDriveServiceHelper> fake_drive_helper_; 249 scoped_ptr<FakeRemoteChangeProcessor> remote_change_processor_; 250 scoped_ptr<MetadataDatabase> metadata_database_; 251 scoped_ptr<SyncTaskManager> sync_task_manager_; 252 253 DISALLOW_COPY_AND_ASSIGN(LocalToRemoteSyncerTest); 254}; 255 256TEST_F(LocalToRemoteSyncerTest, CreateFile) { 257 const GURL kOrigin("chrome-extension://example"); 258 const std::string sync_root = CreateSyncRoot(); 259 const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host()); 260 InitializeMetadataDatabase(); 261 RegisterApp(kOrigin.host(), app_root); 262 263 EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer( 264 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 265 SYNC_FILE_TYPE_FILE), 266 URL(kOrigin, "file1"))); 267 EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer( 268 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 269 SYNC_FILE_TYPE_DIRECTORY), 270 URL(kOrigin, "folder"))); 271 EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer( 272 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 273 SYNC_FILE_TYPE_FILE), 274 URL(kOrigin, "folder/file2"))); 275 276 std::string folder_id = GetFileIDForParentAndTitle(app_root, "folder"); 277 ASSERT_FALSE(folder_id.empty()); 278 279 VerifyTitleUniqueness(app_root, "file1", google_apis::ENTRY_KIND_FILE); 280 VerifyTitleUniqueness(app_root, "folder", google_apis::ENTRY_KIND_FOLDER); 281 VerifyTitleUniqueness(folder_id, "file2", google_apis::ENTRY_KIND_FILE); 282} 283 284TEST_F(LocalToRemoteSyncerTest, CreateFileOnMissingPath) { 285 const GURL kOrigin("chrome-extension://example"); 286 const std::string sync_root = CreateSyncRoot(); 287 const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host()); 288 InitializeMetadataDatabase(); 289 RegisterApp(kOrigin.host(), app_root); 290 291 // Run the syncer 3 times to create missing folder1 and folder2. 292 EXPECT_EQ(SYNC_STATUS_RETRY, RunLocalToRemoteSyncer( 293 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 294 SYNC_FILE_TYPE_FILE), 295 URL(kOrigin, "folder1/folder2/file"))); 296 EXPECT_EQ(SYNC_STATUS_RETRY, RunLocalToRemoteSyncer( 297 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 298 SYNC_FILE_TYPE_FILE), 299 URL(kOrigin, "folder1/folder2/file"))); 300 EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer( 301 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 302 SYNC_FILE_TYPE_FILE), 303 URL(kOrigin, "folder1/folder2/file"))); 304 305 std::string folder_id1 = GetFileIDForParentAndTitle(app_root, "folder1"); 306 ASSERT_FALSE(folder_id1.empty()); 307 std::string folder_id2 = GetFileIDForParentAndTitle(folder_id1, "folder2"); 308 ASSERT_FALSE(folder_id2.empty()); 309 310 VerifyTitleUniqueness(app_root, "folder1", google_apis::ENTRY_KIND_FOLDER); 311 VerifyTitleUniqueness(folder_id1, "folder2", google_apis::ENTRY_KIND_FOLDER); 312 VerifyTitleUniqueness(folder_id2, "file", google_apis::ENTRY_KIND_FILE); 313} 314 315TEST_F(LocalToRemoteSyncerTest, DeleteFile) { 316 const GURL kOrigin("chrome-extension://example"); 317 const std::string sync_root = CreateSyncRoot(); 318 const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host()); 319 InitializeMetadataDatabase(); 320 RegisterApp(kOrigin.host(), app_root); 321 322 EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer( 323 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 324 SYNC_FILE_TYPE_FILE), 325 URL(kOrigin, "file"))); 326 EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer( 327 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 328 SYNC_FILE_TYPE_DIRECTORY), 329 URL(kOrigin, "folder"))); 330 331 VerifyTitleUniqueness(app_root, "file", google_apis::ENTRY_KIND_FILE); 332 VerifyTitleUniqueness(app_root, "folder", google_apis::ENTRY_KIND_FOLDER); 333 334 EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer( 335 FileChange(FileChange::FILE_CHANGE_DELETE, 336 SYNC_FILE_TYPE_FILE), 337 URL(kOrigin, "file"))); 338 EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer( 339 FileChange(FileChange::FILE_CHANGE_DELETE, 340 SYNC_FILE_TYPE_DIRECTORY), 341 URL(kOrigin, "folder"))); 342 343 VerifyFileDeletion(app_root, "file"); 344 VerifyFileDeletion(app_root, "folder"); 345} 346 347TEST_F(LocalToRemoteSyncerTest, Conflict_CreateFileOnFolder) { 348 const GURL kOrigin("chrome-extension://example"); 349 const std::string sync_root = CreateSyncRoot(); 350 const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host()); 351 InitializeMetadataDatabase(); 352 RegisterApp(kOrigin.host(), app_root); 353 354 CreateRemoteFolder(app_root, "foo"); 355 EXPECT_EQ(SYNC_STATUS_OK, ListChanges()); 356 EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer( 357 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 358 SYNC_FILE_TYPE_FILE), 359 URL(kOrigin, "foo"))); 360 361 // There should exist both file and folder on remote. 362 ScopedVector<google_apis::ResourceEntry> entries = 363 GetResourceEntriesForParentAndTitle(app_root, "foo"); 364 ASSERT_EQ(2u, entries.size()); 365 EXPECT_EQ(google_apis::ENTRY_KIND_FOLDER, entries[0]->kind()); 366 EXPECT_EQ(google_apis::ENTRY_KIND_FILE, entries[1]->kind()); 367} 368 369TEST_F(LocalToRemoteSyncerTest, Conflict_CreateFolderOnFile) { 370 const GURL kOrigin("chrome-extension://example"); 371 const std::string sync_root = CreateSyncRoot(); 372 const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host()); 373 InitializeMetadataDatabase(); 374 RegisterApp(kOrigin.host(), app_root); 375 376 CreateRemoteFile(app_root, "foo", "data"); 377 EXPECT_EQ(SYNC_STATUS_OK, ListChanges()); 378 379 EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer( 380 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 381 SYNC_FILE_TYPE_DIRECTORY), 382 URL(kOrigin, "foo"))); 383 384 // There should exist both file and folder on remote. 385 ScopedVector<google_apis::ResourceEntry> entries = 386 GetResourceEntriesForParentAndTitle(app_root, "foo"); 387 ASSERT_EQ(2u, entries.size()); 388 EXPECT_EQ(google_apis::ENTRY_KIND_FILE, entries[0]->kind()); 389 EXPECT_EQ(google_apis::ENTRY_KIND_FOLDER, entries[1]->kind()); 390} 391 392TEST_F(LocalToRemoteSyncerTest, Conflict_CreateFileOnFile) { 393 const GURL kOrigin("chrome-extension://example"); 394 const std::string sync_root = CreateSyncRoot(); 395 const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host()); 396 InitializeMetadataDatabase(); 397 RegisterApp(kOrigin.host(), app_root); 398 399 CreateRemoteFile(app_root, "foo", "data"); 400 EXPECT_EQ(SYNC_STATUS_OK, ListChanges()); 401 402 EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer( 403 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 404 SYNC_FILE_TYPE_FILE), 405 URL(kOrigin, "foo"))); 406 407 // There should exist both files on remote. 408 ScopedVector<google_apis::ResourceEntry> entries = 409 GetResourceEntriesForParentAndTitle(app_root, "foo"); 410 ASSERT_EQ(2u, entries.size()); 411 EXPECT_EQ(google_apis::ENTRY_KIND_FILE, entries[0]->kind()); 412 EXPECT_EQ(google_apis::ENTRY_KIND_FILE, entries[1]->kind()); 413} 414 415TEST_F(LocalToRemoteSyncerTest, Conflict_UpdateDeleteOnFile) { 416 const GURL kOrigin("chrome-extension://example"); 417 const std::string sync_root = CreateSyncRoot(); 418 const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host()); 419 InitializeMetadataDatabase(); 420 RegisterApp(kOrigin.host(), app_root); 421 422 const std::string file_id = CreateRemoteFile(app_root, "foo", "data"); 423 EXPECT_EQ(SYNC_STATUS_OK, ListChanges()); 424 425 SyncStatusCode status; 426 int retry_count = 0; 427 do { 428 if (retry_count++ > kRetryLimit) 429 break; 430 status = RunRemoteToLocalSyncer(); 431 } while (status == SYNC_STATUS_OK || 432 status == SYNC_STATUS_RETRY); 433 EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC, status); 434 435 DeleteResource(file_id); 436 437 EXPECT_EQ(SYNC_STATUS_FILE_BUSY, RunLocalToRemoteSyncer( 438 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 439 SYNC_FILE_TYPE_FILE), 440 URL(kOrigin, "foo"))); 441 EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer( 442 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 443 SYNC_FILE_TYPE_FILE), 444 URL(kOrigin, "foo"))); 445 446 ScopedVector<google_apis::ResourceEntry> entries = 447 GetResourceEntriesForParentAndTitle(app_root, "foo"); 448 ASSERT_EQ(1u, entries.size()); 449 EXPECT_EQ(google_apis::ENTRY_KIND_FILE, entries[0]->kind()); 450 EXPECT_TRUE(!entries[0]->deleted()); 451 EXPECT_NE(file_id, entries[0]->resource_id()); 452} 453 454TEST_F(LocalToRemoteSyncerTest, Conflict_CreateDeleteOnFile) { 455 const GURL kOrigin("chrome-extension://example"); 456 const std::string sync_root = CreateSyncRoot(); 457 const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host()); 458 InitializeMetadataDatabase(); 459 RegisterApp(kOrigin.host(), app_root); 460 461 const std::string file_id = CreateRemoteFile(app_root, "foo", "data"); 462 EXPECT_EQ(SYNC_STATUS_OK, ListChanges()); 463 SyncStatusCode status; 464 int retry_count = 0; 465 do { 466 if (retry_count++ > kRetryLimit) 467 break; 468 status = RunRemoteToLocalSyncer(); 469 } while (status == SYNC_STATUS_OK || 470 status == SYNC_STATUS_RETRY); 471 EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC, status); 472 473 DeleteResource(file_id); 474 475 EXPECT_EQ(SYNC_STATUS_OK, ListChanges()); 476 477 EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer( 478 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 479 SYNC_FILE_TYPE_FILE), 480 URL(kOrigin, "foo"))); 481 482 ScopedVector<google_apis::ResourceEntry> entries = 483 GetResourceEntriesForParentAndTitle(app_root, "foo"); 484 ASSERT_EQ(1u, entries.size()); 485 EXPECT_EQ(google_apis::ENTRY_KIND_FILE, entries[0]->kind()); 486 EXPECT_TRUE(!entries[0]->deleted()); 487 EXPECT_NE(file_id, entries[0]->resource_id()); 488} 489 490TEST_F(LocalToRemoteSyncerTest, Conflict_CreateFolderOnFolder) { 491 const GURL kOrigin("chrome-extension://example"); 492 const std::string sync_root = CreateSyncRoot(); 493 const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host()); 494 InitializeMetadataDatabase(); 495 RegisterApp(kOrigin.host(), app_root); 496 497 const std::string folder_id = CreateRemoteFolder(app_root, "foo"); 498 499 EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer( 500 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 501 SYNC_FILE_TYPE_DIRECTORY), 502 URL(kOrigin, "foo"))); 503 504 ScopedVector<google_apis::ResourceEntry> entries = 505 GetResourceEntriesForParentAndTitle(app_root, "foo"); 506 ASSERT_EQ(2u, entries.size()); 507 EXPECT_EQ(google_apis::ENTRY_KIND_FOLDER, entries[0]->kind()); 508 EXPECT_EQ(google_apis::ENTRY_KIND_FOLDER, entries[1]->kind()); 509 EXPECT_TRUE(!entries[0]->deleted()); 510 EXPECT_TRUE(!entries[1]->deleted()); 511 EXPECT_TRUE(folder_id == entries[0]->resource_id() || 512 folder_id == entries[1]->resource_id()); 513 514 TrackerIDSet trackers; 515 EXPECT_TRUE(GetMetadataDatabase()->FindTrackersByFileID( 516 folder_id, &trackers)); 517 EXPECT_EQ(1u, trackers.size()); 518 ASSERT_TRUE(trackers.has_active()); 519} 520 521TEST_F(LocalToRemoteSyncerTest, AppRootDeletion) { 522 const GURL kOrigin("chrome-extension://example"); 523 const std::string sync_root = CreateSyncRoot(); 524 const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host()); 525 InitializeMetadataDatabase(); 526 RegisterApp(kOrigin.host(), app_root); 527 528 DeleteResource(app_root); 529 EXPECT_EQ(SYNC_STATUS_OK, ListChanges()); 530 SyncStatusCode status; 531 int retry_count = 0; 532 do { 533 if (retry_count++ > kRetryLimit) 534 break; 535 status = RunRemoteToLocalSyncer(); 536 } while (status == SYNC_STATUS_OK || 537 status == SYNC_STATUS_RETRY); 538 EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC, status); 539 540 EXPECT_EQ(SYNC_STATUS_UNKNOWN_ORIGIN, RunLocalToRemoteSyncer( 541 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 542 SYNC_FILE_TYPE_DIRECTORY), 543 URL(kOrigin, "foo"))); 544 545 // SyncEngine will re-register the app and resurrect the app root later. 546} 547 548} // namespace drive_backend 549} // namespace sync_file_system 550