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