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/chromeos/drive/change_list_processor.h" 6 7 #include "base/files/scoped_temp_dir.h" 8 #include "base/message_loop/message_loop_proxy.h" 9 #include "base/values.h" 10 #include "chrome/browser/chromeos/drive/drive.pb.h" 11 #include "chrome/browser/chromeos/drive/fake_free_disk_space_getter.h" 12 #include "chrome/browser/chromeos/drive/file_cache.h" 13 #include "chrome/browser/chromeos/drive/file_system_util.h" 14 #include "chrome/browser/chromeos/drive/resource_metadata.h" 15 #include "chrome/browser/chromeos/drive/test_util.h" 16 #include "content/public/test/test_browser_thread_bundle.h" 17 #include "google_apis/drive/drive_api_parser.h" 18 #include "google_apis/drive/gdata_wapi_parser.h" 19 #include "google_apis/drive/test_util.h" 20 #include "testing/gtest/include/gtest/gtest.h" 21 22 namespace drive { 23 namespace internal { 24 25 namespace { 26 27 const int64 kBaseResourceListChangestamp = 123; 28 const char kRootId[] = "fake_root"; 29 30 enum FileOrDirectory { 31 FILE, 32 DIRECTORY, 33 }; 34 35 struct EntryExpectation { 36 std::string path; 37 std::string id; 38 std::string parent_id; 39 FileOrDirectory type; 40 }; 41 42 // Returns a basic change list which contains some files and directories. 43 ScopedVector<ChangeList> CreateBaseChangeList() { 44 ScopedVector<ChangeList> change_lists; 45 change_lists.push_back(new ChangeList); 46 47 // Add directories to the change list. 48 ResourceEntry directory; 49 directory.mutable_file_info()->set_is_directory(true); 50 51 directory.set_title("Directory 1"); 52 directory.set_resource_id("folder:1_folder_resource_id"); 53 change_lists[0]->mutable_entries()->push_back(directory); 54 change_lists[0]->mutable_parent_resource_ids()->push_back(kRootId); 55 56 directory.set_title("Sub Directory Folder"); 57 directory.set_resource_id("folder:sub_dir_folder_resource_id"); 58 change_lists[0]->mutable_entries()->push_back(directory); 59 change_lists[0]->mutable_parent_resource_ids()->push_back( 60 "folder:1_folder_resource_id"); 61 62 directory.set_title("Sub Sub Directory Folder"); 63 directory.set_resource_id("folder:sub_sub_directory_folder_id"); 64 change_lists[0]->mutable_entries()->push_back(directory); 65 change_lists[0]->mutable_parent_resource_ids()->push_back( 66 "folder:sub_dir_folder_resource_id"); 67 68 directory.set_title("Directory 2 excludeDir-test"); 69 directory.set_resource_id("folder:sub_dir_folder_2_self_link"); 70 change_lists[0]->mutable_entries()->push_back(directory); 71 change_lists[0]->mutable_parent_resource_ids()->push_back(kRootId); 72 73 // Add files to the change list. 74 ResourceEntry file; 75 76 file.set_title("File 1.txt"); 77 file.set_resource_id("file:2_file_resource_id"); 78 change_lists[0]->mutable_entries()->push_back(file); 79 change_lists[0]->mutable_parent_resource_ids()->push_back(kRootId); 80 81 file.set_title("SubDirectory File 1.txt"); 82 file.set_resource_id("file:subdirectory_file_1_id"); 83 change_lists[0]->mutable_entries()->push_back(file); 84 change_lists[0]->mutable_parent_resource_ids()->push_back( 85 "folder:1_folder_resource_id"); 86 87 file.set_title("Orphan File 1.txt"); 88 file.set_resource_id("file:1_orphanfile_resource_id"); 89 change_lists[0]->mutable_entries()->push_back(file); 90 change_lists[0]->mutable_parent_resource_ids()->push_back(""); 91 92 change_lists[0]->set_largest_changestamp(kBaseResourceListChangestamp); 93 return change_lists.Pass(); 94 } 95 96 class ChangeListProcessorTest : public testing::Test { 97 protected: 98 virtual void SetUp() OVERRIDE { 99 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 100 101 metadata_storage_.reset(new ResourceMetadataStorage( 102 temp_dir_.path(), base::MessageLoopProxy::current().get())); 103 ASSERT_TRUE(metadata_storage_->Initialize()); 104 105 fake_free_disk_space_getter_.reset(new FakeFreeDiskSpaceGetter); 106 cache_.reset(new FileCache(metadata_storage_.get(), 107 temp_dir_.path(), 108 base::MessageLoopProxy::current().get(), 109 fake_free_disk_space_getter_.get())); 110 ASSERT_TRUE(cache_->Initialize()); 111 112 metadata_.reset(new internal::ResourceMetadata( 113 metadata_storage_.get(), cache_.get(), 114 base::MessageLoopProxy::current())); 115 ASSERT_EQ(FILE_ERROR_OK, metadata_->Initialize()); 116 } 117 118 // Applies the |changes| to |metadata_| as a full resource list of changestamp 119 // |kBaseResourceListChangestamp|. 120 FileError ApplyFullResourceList(ScopedVector<ChangeList> changes) { 121 scoped_ptr<google_apis::AboutResource> about_resource( 122 new google_apis::AboutResource); 123 about_resource->set_largest_change_id(kBaseResourceListChangestamp); 124 about_resource->set_root_folder_id(kRootId); 125 126 ChangeListProcessor processor(metadata_.get()); 127 return processor.Apply(about_resource.Pass(), 128 changes.Pass(), 129 false /* is_delta_update */); 130 } 131 132 // Applies the |changes| to |metadata_| as a delta update. Delta changelists 133 // should contain their changestamp in themselves. 134 FileError ApplyChangeList(ScopedVector<ChangeList> changes, 135 std::set<base::FilePath>* changed_dirs) { 136 scoped_ptr<google_apis::AboutResource> about_resource( 137 new google_apis::AboutResource); 138 about_resource->set_largest_change_id(kBaseResourceListChangestamp); 139 about_resource->set_root_folder_id(kRootId); 140 141 ChangeListProcessor processor(metadata_.get()); 142 FileError error = processor.Apply(about_resource.Pass(), 143 changes.Pass(), 144 true /* is_delta_update */); 145 *changed_dirs = processor.changed_dirs(); 146 return error; 147 } 148 149 // Gets the resource entry for the path from |metadata_| synchronously. 150 // Returns null if the entry does not exist. 151 scoped_ptr<ResourceEntry> GetResourceEntry(const std::string& path) { 152 scoped_ptr<ResourceEntry> entry(new ResourceEntry); 153 FileError error = metadata_->GetResourceEntryByPath( 154 base::FilePath::FromUTF8Unsafe(path), entry.get()); 155 if (error != FILE_ERROR_OK) 156 entry.reset(); 157 return entry.Pass(); 158 } 159 160 content::TestBrowserThreadBundle thread_bundle_; 161 base::ScopedTempDir temp_dir_; 162 scoped_ptr<ResourceMetadataStorage, 163 test_util::DestroyHelperForTests> metadata_storage_; 164 scoped_ptr<FakeFreeDiskSpaceGetter> fake_free_disk_space_getter_; 165 scoped_ptr<FileCache, test_util::DestroyHelperForTests> cache_; 166 scoped_ptr<ResourceMetadata, test_util::DestroyHelperForTests> metadata_; 167 }; 168 169 } // namespace 170 171 TEST_F(ChangeListProcessorTest, ApplyFullResourceList) { 172 EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList())); 173 174 const EntryExpectation kExpected[] = { 175 // Root files 176 {"drive/root", kRootId, "", DIRECTORY}, 177 {"drive/root/File 1.txt", 178 "file:2_file_resource_id", kRootId, FILE}, 179 // Subdirectory files 180 {"drive/root/Directory 1", 181 "folder:1_folder_resource_id", kRootId, DIRECTORY}, 182 {"drive/root/Directory 1/SubDirectory File 1.txt", 183 "file:subdirectory_file_1_id", "folder:1_folder_resource_id", FILE}, 184 {"drive/root/Directory 2 excludeDir-test", 185 "folder:sub_dir_folder_2_self_link", kRootId, DIRECTORY}, 186 // Deeper 187 {"drive/root/Directory 1/Sub Directory Folder", 188 "folder:sub_dir_folder_resource_id", 189 "folder:1_folder_resource_id", DIRECTORY}, 190 {"drive/root/Directory 1/Sub Directory Folder/Sub Sub Directory Folder", 191 "folder:sub_sub_directory_folder_id", 192 "folder:sub_dir_folder_resource_id", DIRECTORY}, 193 // Orphan 194 {"drive/other/Orphan File 1.txt", "file:1_orphanfile_resource_id", 195 "", FILE}, 196 }; 197 198 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kExpected); ++i) { 199 scoped_ptr<ResourceEntry> entry = GetResourceEntry(kExpected[i].path); 200 ASSERT_TRUE(entry) << "for path: " << kExpected[i].path; 201 EXPECT_EQ(kExpected[i].id, entry->resource_id()); 202 203 ResourceEntry parent_entry; 204 EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryById( 205 entry->parent_local_id(), &parent_entry)); 206 EXPECT_EQ(kExpected[i].parent_id, parent_entry.resource_id()); 207 EXPECT_EQ(kExpected[i].type, 208 entry->file_info().is_directory() ? DIRECTORY : FILE); 209 } 210 211 int64 changestamp = 0; 212 EXPECT_EQ(FILE_ERROR_OK, metadata_->GetLargestChangestamp(&changestamp)); 213 EXPECT_EQ(kBaseResourceListChangestamp, changestamp); 214 } 215 216 TEST_F(ChangeListProcessorTest, DeltaFileAddedInNewDirectory) { 217 ScopedVector<ChangeList> change_lists; 218 change_lists.push_back(new ChangeList); 219 220 ResourceEntry new_folder; 221 new_folder.set_resource_id("folder:new_folder_resource_id"); 222 new_folder.set_title("New Directory"); 223 new_folder.mutable_file_info()->set_is_directory(true); 224 change_lists[0]->mutable_entries()->push_back(new_folder); 225 change_lists[0]->mutable_parent_resource_ids()->push_back(kRootId); 226 227 ResourceEntry new_file; 228 new_file.set_resource_id("document:file_added_in_new_dir_id"); 229 new_file.set_title("File in new dir.txt"); 230 change_lists[0]->mutable_entries()->push_back(new_file); 231 change_lists[0]->mutable_parent_resource_ids()->push_back( 232 new_folder.resource_id()); 233 234 change_lists[0]->set_largest_changestamp(16730); 235 236 // Apply the changelist and check the effect. 237 EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList())); 238 std::set<base::FilePath> changed_dirs; 239 EXPECT_EQ(FILE_ERROR_OK, ApplyChangeList(change_lists.Pass(), &changed_dirs)); 240 241 int64 changestamp = 0; 242 EXPECT_EQ(FILE_ERROR_OK, metadata_->GetLargestChangestamp(&changestamp)); 243 EXPECT_EQ(16730, changestamp); 244 EXPECT_TRUE(GetResourceEntry("drive/root/New Directory")); 245 EXPECT_TRUE(GetResourceEntry( 246 "drive/root/New Directory/File in new dir.txt")); 247 248 EXPECT_EQ(2U, changed_dirs.size()); 249 EXPECT_TRUE(changed_dirs.count( 250 base::FilePath::FromUTF8Unsafe("drive/root"))); 251 EXPECT_TRUE(changed_dirs.count( 252 base::FilePath::FromUTF8Unsafe("drive/root/New Directory"))); 253 } 254 255 TEST_F(ChangeListProcessorTest, DeltaDirMovedFromRootToDirectory) { 256 ScopedVector<ChangeList> change_lists; 257 change_lists.push_back(new ChangeList); 258 259 ResourceEntry entry; 260 entry.set_resource_id("folder:1_folder_resource_id"); 261 entry.set_title("Directory 1"); 262 entry.mutable_file_info()->set_is_directory(true); 263 change_lists[0]->mutable_entries()->push_back(entry); 264 change_lists[0]->mutable_parent_resource_ids()->push_back( 265 "folder:sub_dir_folder_2_self_link"); 266 267 change_lists[0]->set_largest_changestamp(16809); 268 269 // Apply the changelist and check the effect. 270 EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList())); 271 std::set<base::FilePath> changed_dirs; 272 EXPECT_EQ(FILE_ERROR_OK, ApplyChangeList(change_lists.Pass(), &changed_dirs)); 273 274 int64 changestamp = 0; 275 EXPECT_EQ(FILE_ERROR_OK, metadata_->GetLargestChangestamp(&changestamp)); 276 EXPECT_EQ(16809, changestamp); 277 EXPECT_FALSE(GetResourceEntry("drive/root/Directory 1")); 278 EXPECT_TRUE(GetResourceEntry( 279 "drive/root/Directory 2 excludeDir-test/Directory 1")); 280 281 EXPECT_EQ(4U, changed_dirs.size()); 282 EXPECT_TRUE(changed_dirs.count( 283 base::FilePath::FromUTF8Unsafe("drive/root"))); 284 EXPECT_TRUE(changed_dirs.count( 285 base::FilePath::FromUTF8Unsafe("drive/root/Directory 1"))); 286 EXPECT_TRUE(changed_dirs.count( 287 base::FilePath::FromUTF8Unsafe( 288 "drive/root/Directory 2 excludeDir-test"))); 289 EXPECT_TRUE(changed_dirs.count( 290 base::FilePath::FromUTF8Unsafe( 291 "drive/root/Directory 2 excludeDir-test/Directory 1"))); 292 } 293 294 TEST_F(ChangeListProcessorTest, DeltaFileMovedFromDirectoryToRoot) { 295 ScopedVector<ChangeList> change_lists; 296 change_lists.push_back(new ChangeList); 297 298 ResourceEntry entry; 299 entry.set_resource_id("file:subdirectory_file_1_id"); 300 entry.set_title("SubDirectory File 1.txt"); 301 change_lists[0]->mutable_entries()->push_back(entry); 302 change_lists[0]->mutable_parent_resource_ids()->push_back(kRootId); 303 304 change_lists[0]->set_largest_changestamp(16815); 305 306 // Apply the changelist and check the effect. 307 EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList())); 308 std::set<base::FilePath> changed_dirs; 309 EXPECT_EQ(FILE_ERROR_OK, ApplyChangeList(change_lists.Pass(), &changed_dirs)); 310 311 int64 changestamp = 0; 312 EXPECT_EQ(FILE_ERROR_OK, metadata_->GetLargestChangestamp(&changestamp)); 313 EXPECT_EQ(16815, changestamp); 314 EXPECT_FALSE(GetResourceEntry( 315 "drive/root/Directory 1/SubDirectory File 1.txt")); 316 EXPECT_TRUE(GetResourceEntry("drive/root/SubDirectory File 1.txt")); 317 318 EXPECT_EQ(2U, changed_dirs.size()); 319 EXPECT_TRUE(changed_dirs.count( 320 base::FilePath::FromUTF8Unsafe("drive/root"))); 321 EXPECT_TRUE(changed_dirs.count( 322 base::FilePath::FromUTF8Unsafe("drive/root/Directory 1"))); 323 } 324 325 TEST_F(ChangeListProcessorTest, DeltaFileRenamedInDirectory) { 326 ScopedVector<ChangeList> change_lists; 327 change_lists.push_back(new ChangeList); 328 329 ResourceEntry entry; 330 entry.set_resource_id("file:subdirectory_file_1_id"); 331 entry.set_title("New SubDirectory File 1.txt"); 332 change_lists[0]->mutable_entries()->push_back(entry); 333 change_lists[0]->mutable_parent_resource_ids()->push_back( 334 "folder:1_folder_resource_id"); 335 336 change_lists[0]->set_largest_changestamp(16767); 337 338 // Apply the changelist and check the effect. 339 EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList())); 340 std::set<base::FilePath> changed_dirs; 341 EXPECT_EQ(FILE_ERROR_OK, ApplyChangeList(change_lists.Pass(), &changed_dirs)); 342 343 int64 changestamp = 0; 344 EXPECT_EQ(FILE_ERROR_OK, metadata_->GetLargestChangestamp(&changestamp)); 345 EXPECT_EQ(16767, changestamp); 346 EXPECT_FALSE(GetResourceEntry( 347 "drive/root/Directory 1/SubDirectory File 1.txt")); 348 EXPECT_TRUE(GetResourceEntry( 349 "drive/root/Directory 1/New SubDirectory File 1.txt")); 350 351 EXPECT_EQ(1U, changed_dirs.size()); 352 EXPECT_TRUE(changed_dirs.count( 353 base::FilePath::FromUTF8Unsafe("drive/root/Directory 1"))); 354 } 355 356 TEST_F(ChangeListProcessorTest, DeltaAddAndDeleteFileInRoot) { 357 // Create ChangeList to add a file. 358 ScopedVector<ChangeList> change_lists; 359 change_lists.push_back(new ChangeList); 360 361 ResourceEntry entry; 362 entry.set_resource_id("document:added_in_root_id"); 363 entry.set_title("Added file.txt"); 364 change_lists[0]->mutable_entries()->push_back(entry); 365 change_lists[0]->mutable_parent_resource_ids()->push_back(kRootId); 366 367 change_lists[0]->set_largest_changestamp(16683); 368 369 // Apply. 370 EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList())); 371 std::set<base::FilePath> changed_dirs; 372 EXPECT_EQ(FILE_ERROR_OK, ApplyChangeList(change_lists.Pass(), &changed_dirs)); 373 int64 changestamp = 0; 374 EXPECT_EQ(FILE_ERROR_OK, metadata_->GetLargestChangestamp(&changestamp)); 375 EXPECT_EQ(16683, changestamp); 376 EXPECT_TRUE(GetResourceEntry("drive/root/Added file.txt")); 377 EXPECT_EQ(1U, changed_dirs.size()); 378 EXPECT_TRUE(changed_dirs.count( 379 base::FilePath::FromUTF8Unsafe("drive/root"))); 380 381 // Create ChangeList to delete the file. 382 change_lists.push_back(new ChangeList); 383 384 entry.set_deleted(true); 385 change_lists[0]->mutable_entries()->push_back(entry); 386 change_lists[0]->mutable_parent_resource_ids()->push_back(kRootId); 387 388 change_lists[0]->set_largest_changestamp(16687); 389 390 // Apply. 391 EXPECT_EQ(FILE_ERROR_OK, ApplyChangeList(change_lists.Pass(), &changed_dirs)); 392 EXPECT_EQ(FILE_ERROR_OK, metadata_->GetLargestChangestamp(&changestamp)); 393 EXPECT_EQ(16687, changestamp); 394 EXPECT_FALSE(GetResourceEntry("drive/root/Added file.txt")); 395 EXPECT_EQ(1U, changed_dirs.size()); 396 EXPECT_TRUE(changed_dirs.count( 397 base::FilePath::FromUTF8Unsafe("drive/root"))); 398 } 399 400 401 TEST_F(ChangeListProcessorTest, DeltaAddAndDeleteFileFromExistingDirectory) { 402 // Create ChangeList to add a file. 403 ScopedVector<ChangeList> change_lists; 404 change_lists.push_back(new ChangeList); 405 406 ResourceEntry entry; 407 entry.set_resource_id("document:added_in_root_id"); 408 entry.set_title("Added file.txt"); 409 change_lists[0]->mutable_entries()->push_back(entry); 410 change_lists[0]->mutable_parent_resource_ids()->push_back( 411 "folder:1_folder_resource_id"); 412 413 change_lists[0]->set_largest_changestamp(16730); 414 415 // Apply. 416 EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList())); 417 std::set<base::FilePath> changed_dirs; 418 EXPECT_EQ(FILE_ERROR_OK, ApplyChangeList(change_lists.Pass(), &changed_dirs)); 419 int64 changestamp = 0; 420 EXPECT_EQ(FILE_ERROR_OK, metadata_->GetLargestChangestamp(&changestamp)); 421 EXPECT_EQ(16730, changestamp); 422 EXPECT_TRUE(GetResourceEntry("drive/root/Directory 1/Added file.txt")); 423 424 EXPECT_EQ(1U, changed_dirs.size()); 425 EXPECT_TRUE(changed_dirs.count( 426 base::FilePath::FromUTF8Unsafe("drive/root/Directory 1"))); 427 428 // Create ChangeList to delete the file. 429 change_lists.push_back(new ChangeList); 430 431 entry.set_deleted(true); 432 change_lists[0]->mutable_entries()->push_back(entry); 433 change_lists[0]->mutable_parent_resource_ids()->push_back( 434 "folder:1_folder_resource_id"); 435 436 change_lists[0]->set_largest_changestamp(16770); 437 438 // Apply. 439 EXPECT_EQ(FILE_ERROR_OK, ApplyChangeList(change_lists.Pass(), &changed_dirs)); 440 EXPECT_EQ(FILE_ERROR_OK, metadata_->GetLargestChangestamp(&changestamp)); 441 EXPECT_EQ(16770, changestamp); 442 EXPECT_FALSE(GetResourceEntry("drive/root/Directory 1/Added file.txt")); 443 444 EXPECT_EQ(1U, changed_dirs.size()); 445 EXPECT_TRUE(changed_dirs.count( 446 base::FilePath::FromUTF8Unsafe("drive/root/Directory 1"))); 447 } 448 449 TEST_F(ChangeListProcessorTest, DeltaAddFileToNewButDeletedDirectory) { 450 // Create a change which contains the following updates: 451 // 1) A new PDF file is added to a new directory 452 // 2) but the new directory is marked "deleted" (i.e. moved to Trash) 453 // Hence, the PDF file should be just ignored. 454 ScopedVector<ChangeList> change_lists; 455 change_lists.push_back(new ChangeList); 456 457 ResourceEntry file; 458 file.set_resource_id("pdf:file_added_in_deleted_id"); 459 file.set_title("new_pdf_file.pdf"); 460 file.set_deleted(true); 461 change_lists[0]->mutable_entries()->push_back(file); 462 change_lists[0]->mutable_parent_resource_ids()->push_back( 463 "folder:new_folder_resource_id"); 464 465 ResourceEntry directory; 466 directory.set_resource_id("folder:new_folder_resource_id"); 467 directory.set_title("New Directory"); 468 directory.mutable_file_info()->set_is_directory(true); 469 directory.set_deleted(true); 470 change_lists[0]->mutable_entries()->push_back(directory); 471 change_lists[0]->mutable_parent_resource_ids()->push_back(kRootId); 472 473 change_lists[0]->set_largest_changestamp(16730); 474 475 // Apply the changelist and check the effect. 476 EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList())); 477 std::set<base::FilePath> changed_dirs; 478 EXPECT_EQ(FILE_ERROR_OK, ApplyChangeList(change_lists.Pass(), &changed_dirs)); 479 480 int64 changestamp = 0; 481 EXPECT_EQ(FILE_ERROR_OK, metadata_->GetLargestChangestamp(&changestamp)); 482 EXPECT_EQ(16730, changestamp); 483 EXPECT_FALSE(GetResourceEntry("drive/root/New Directory/new_pdf_file.pdf")); 484 485 EXPECT_TRUE(changed_dirs.empty()); 486 } 487 488 TEST_F(ChangeListProcessorTest, RefreshDirectory) { 489 // Prepare metadata. 490 EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList())); 491 492 // Create change list. 493 scoped_ptr<ChangeList> change_list(new ChangeList); 494 495 // Add a new file to the change list. 496 ResourceEntry new_file; 497 new_file.set_title("new_file"); 498 new_file.set_resource_id("new_file_id"); 499 change_list->mutable_entries()->push_back(new_file); 500 change_list->mutable_parent_resource_ids()->push_back(kRootId); 501 502 // Add "Directory 1" to the map with a new name. 503 ResourceEntry dir1; 504 EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath( 505 util::GetDriveMyDriveRootPath().AppendASCII("Directory 1"), &dir1)); 506 dir1.set_title(dir1.title() + " (renamed)"); 507 change_list->mutable_entries()->push_back(dir1); 508 change_list->mutable_parent_resource_ids()->push_back(kRootId); 509 510 // Update the directory with the map. 511 ResourceEntry root; 512 EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath( 513 util::GetDriveMyDriveRootPath(), &root)); 514 const int64 kNewChangestamp = 12345; 515 ResourceEntryVector refreshed_entries; 516 EXPECT_EQ(FILE_ERROR_OK, ChangeListProcessor::RefreshDirectory( 517 metadata_.get(), 518 DirectoryFetchInfo(root.local_id(), kRootId, kNewChangestamp), 519 change_list.Pass(), 520 &refreshed_entries)); 521 522 // "new_file" should be added. 523 ResourceEntry entry; 524 EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath( 525 util::GetDriveMyDriveRootPath().AppendASCII(new_file.title()), &entry)); 526 527 // "Directory 1" should be renamed. 528 EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath( 529 util::GetDriveMyDriveRootPath().AppendASCII(dir1.title()), &entry)); 530 } 531 532 TEST_F(ChangeListProcessorTest, RefreshDirectory_WrongParentId) { 533 // Prepare metadata. 534 EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList())); 535 536 // Create change list and add a new file to it. 537 scoped_ptr<ChangeList> change_list(new ChangeList); 538 ResourceEntry new_file; 539 new_file.set_title("new_file"); 540 new_file.set_resource_id("new_file_id"); 541 // This entry should not be added because the parent ID does not match. 542 change_list->mutable_parent_resource_ids()->push_back( 543 "some-random-resource-id"); 544 change_list->mutable_entries()->push_back(new_file); 545 546 547 // Update the directory. 548 ResourceEntry root; 549 EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath( 550 util::GetDriveMyDriveRootPath(), &root)); 551 const int64 kNewChangestamp = 12345; 552 ResourceEntryVector refreshed_entries; 553 EXPECT_EQ(FILE_ERROR_OK, ChangeListProcessor::RefreshDirectory( 554 metadata_.get(), 555 DirectoryFetchInfo(root.local_id(), kRootId, kNewChangestamp), 556 change_list.Pass(), 557 &refreshed_entries)); 558 559 // "new_file" should not be added. 560 ResourceEntry entry; 561 EXPECT_EQ(FILE_ERROR_NOT_FOUND, metadata_->GetResourceEntryByPath( 562 util::GetDriveMyDriveRootPath().AppendASCII(new_file.title()), &entry)); 563 } 564 565 TEST_F(ChangeListProcessorTest, SharedFilesWithNoParentInFeed) { 566 // Prepare metadata. 567 EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList())); 568 569 // Create change lists. 570 ScopedVector<ChangeList> change_lists; 571 change_lists.push_back(new ChangeList); 572 573 // Add a new file with non-existing parent resource id to the change lists. 574 ResourceEntry new_file; 575 new_file.set_title("new_file"); 576 new_file.set_resource_id("new_file_id"); 577 change_lists[0]->mutable_entries()->push_back(new_file); 578 change_lists[0]->mutable_parent_resource_ids()->push_back("nonexisting"); 579 change_lists[0]->set_largest_changestamp(kBaseResourceListChangestamp + 1); 580 581 std::set<base::FilePath> changed_dirs; 582 EXPECT_EQ(FILE_ERROR_OK, ApplyChangeList(change_lists.Pass(), &changed_dirs)); 583 584 // "new_file" should be added under drive/other. 585 ResourceEntry entry; 586 EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath( 587 util::GetDriveGrandRootPath().AppendASCII("other/new_file"), &entry)); 588 } 589 590 TEST_F(ChangeListProcessorTest, ModificationDate) { 591 // Prepare metadata. 592 EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList())); 593 594 // Create change lists with a new file. 595 ScopedVector<ChangeList> change_lists; 596 change_lists.push_back(new ChangeList); 597 598 const base::Time now = base::Time::Now(); 599 ResourceEntry new_file_remote; 600 new_file_remote.set_title("new_file_remote"); 601 new_file_remote.set_resource_id("new_file_id"); 602 new_file_remote.set_modification_date(now.ToInternalValue()); 603 604 change_lists[0]->mutable_entries()->push_back(new_file_remote); 605 change_lists[0]->mutable_parent_resource_ids()->push_back(kRootId); 606 change_lists[0]->set_largest_changestamp(kBaseResourceListChangestamp + 1); 607 608 // Add the same file locally, but with a different name, a dirty metadata 609 // state, and a newer modification date. 610 ResourceEntry root; 611 EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath( 612 util::GetDriveMyDriveRootPath(), &root)); 613 614 ResourceEntry new_file_local; 615 new_file_local.set_resource_id(new_file_remote.resource_id()); 616 new_file_local.set_parent_local_id(root.local_id()); 617 new_file_local.set_title("new_file_local"); 618 new_file_local.set_metadata_edit_state(ResourceEntry::DIRTY); 619 new_file_local.set_modification_date( 620 (now + base::TimeDelta::FromSeconds(1)).ToInternalValue()); 621 std::string local_id; 622 EXPECT_EQ(FILE_ERROR_OK, metadata_->AddEntry(new_file_local, &local_id)); 623 624 // Apply the change. 625 std::set<base::FilePath> changed_dirs; 626 EXPECT_EQ(FILE_ERROR_OK, ApplyChangeList(change_lists.Pass(), &changed_dirs)); 627 628 // The change is rejected due to the old modification date. 629 ResourceEntry entry; 630 EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryById(local_id, &entry)); 631 EXPECT_EQ(new_file_local.title(), entry.title()); 632 } 633 634 } // namespace internal 635 } // namespace drive 636