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