| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/drive/chromeos/change_list_processor.h" |
| |
| #include <stddef.h> |
| #include <stdint.h> |
| #include <memory> |
| #include <utility> |
| |
| #include "base/command_line.h" |
| #include "base/files/scoped_temp_dir.h" |
| #include "base/single_thread_task_runner.h" |
| #include "base/stl_util.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "base/values.h" |
| #include "components/drive/chromeos/drive_test_util.h" |
| #include "components/drive/chromeos/fake_free_disk_space_getter.h" |
| #include "components/drive/chromeos/file_cache.h" |
| #include "components/drive/chromeos/resource_metadata.h" |
| #include "components/drive/drive.pb.h" |
| #include "components/drive/file_change.h" |
| #include "components/drive/file_system_core_util.h" |
| #include "content/public/test/test_browser_thread_bundle.h" |
| #include "google_apis/drive/drive_api_parser.h" |
| #include "google_apis/drive/test_util.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace drive { |
| namespace internal { |
| |
| namespace { |
| |
| constexpr char kBaseStartPageToken[] = "123"; |
| constexpr char kRootId[] = "fake_root"; |
| |
| enum FileOrDirectory { |
| FILE, |
| DIRECTORY, |
| }; |
| |
| struct EntryExpectation { |
| std::string path; |
| std::string id; |
| std::string parent_id; |
| FileOrDirectory type; |
| }; |
| |
| // Returns a basic change list which contains some files and directories. |
| std::vector<std::unique_ptr<ChangeList>> CreateBaseChangeList() { |
| std::vector<std::unique_ptr<ChangeList>> change_lists; |
| change_lists.push_back(std::make_unique<ChangeList>()); |
| |
| // Add directories to the change list. |
| ResourceEntry directory; |
| directory.mutable_file_info()->set_is_directory(true); |
| |
| directory.set_title("Directory 1"); |
| directory.set_resource_id("1_folder_resource_id"); |
| change_lists[0]->mutable_entries()->push_back(directory); |
| change_lists[0]->mutable_parent_resource_ids()->push_back(kRootId); |
| |
| directory.set_title("Sub Directory Folder"); |
| directory.set_resource_id("sub_dir_folder_resource_id"); |
| change_lists[0]->mutable_entries()->push_back(directory); |
| change_lists[0]->mutable_parent_resource_ids()->push_back( |
| "1_folder_resource_id"); |
| |
| directory.set_title("Sub Sub Directory Folder"); |
| directory.set_resource_id("sub_sub_directory_folder_id"); |
| change_lists[0]->mutable_entries()->push_back(directory); |
| change_lists[0]->mutable_parent_resource_ids()->push_back( |
| "sub_dir_folder_resource_id"); |
| |
| directory.set_title("Directory 2 excludeDir-test"); |
| directory.set_resource_id("sub_dir_folder_2_self_link"); |
| change_lists[0]->mutable_entries()->push_back(directory); |
| change_lists[0]->mutable_parent_resource_ids()->push_back(kRootId); |
| |
| // Add files to the change list. |
| ResourceEntry file; |
| |
| file.set_title("File 1.txt"); |
| file.set_resource_id("2_file_resource_id"); |
| change_lists[0]->mutable_entries()->push_back(file); |
| change_lists[0]->mutable_parent_resource_ids()->push_back(kRootId); |
| |
| file.set_title("SubDirectory File 1.txt"); |
| file.set_resource_id("subdirectory_file_1_id"); |
| Property* const property = file.mutable_new_properties()->Add(); |
| property->set_key("hello"); |
| property->set_value("world"); |
| change_lists[0]->mutable_entries()->push_back(file); |
| change_lists[0]->mutable_parent_resource_ids()->push_back( |
| "1_folder_resource_id"); |
| |
| file.set_title("Orphan File 1.txt"); |
| file.set_resource_id("1_orphanfile_resource_id"); |
| change_lists[0]->mutable_entries()->push_back(file); |
| change_lists[0]->mutable_parent_resource_ids()->push_back(""); |
| |
| change_lists[0]->set_new_start_page_token(kBaseStartPageToken); |
| return change_lists; |
| } |
| |
| class ChangeListProcessorTest : public testing::Test { |
| protected: |
| void SetUp() override { |
| ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| |
| metadata_storage_.reset(new ResourceMetadataStorage( |
| temp_dir_.GetPath(), base::ThreadTaskRunnerHandle::Get().get())); |
| ASSERT_TRUE(metadata_storage_->Initialize()); |
| |
| fake_free_disk_space_getter_ = std::make_unique<FakeFreeDiskSpaceGetter>(); |
| cache_.reset(new FileCache(metadata_storage_.get(), temp_dir_.GetPath(), |
| base::ThreadTaskRunnerHandle::Get().get(), |
| fake_free_disk_space_getter_.get())); |
| ASSERT_TRUE(cache_->Initialize()); |
| |
| metadata_.reset( |
| new internal::ResourceMetadata(metadata_storage_.get(), cache_.get(), |
| base::ThreadTaskRunnerHandle::Get())); |
| ASSERT_EQ(FILE_ERROR_OK, metadata_->Initialize()); |
| } |
| |
| // Applies the |changes| to |metadata_| as a full resource list of |
| // start page token |kBaseStartPageToken|. |
| FileError ApplyFullResourceList( |
| std::vector<std::unique_ptr<ChangeList>> changes) { |
| ChangeListProcessor processor(util::kTeamDriveIdDefaultCorpus, |
| util::GetDriveMyDriveRootPath(), |
| metadata_.get(), nullptr); |
| return processor.ApplyUserChangeList(kBaseStartPageToken, kRootId, |
| std::move(changes), |
| false /* is_delta_update */); |
| } |
| |
| // Applies |changes| to |metadata_| as a delta update. The |changes| are |
| // treated as user's changelists. Delta changelists should contain their |
| // start page token in themselves. |changede_team_drives| returns any team |
| // drives that were added or removed as part of the change list. |
| FileError ApplyUserChangeList( |
| std::vector<std::unique_ptr<ChangeList>> changes, |
| FileChange* changed_files, |
| FileChange* changed_team_drives) { |
| ChangeListProcessor processor(util::kTeamDriveIdDefaultCorpus, |
| util::GetDriveMyDriveRootPath(), |
| metadata_.get(), nullptr); |
| FileError error = processor.ApplyUserChangeList(kBaseStartPageToken, |
| kRootId, std::move(changes), |
| true /* is_delta_update */); |
| *changed_files = processor.changed_files(); |
| *changed_team_drives = processor.changed_team_drives(); |
| return error; |
| } |
| |
| // Gets the resource entry for the path from |metadata_| synchronously. |
| // Returns null if the entry does not exist. |
| std::unique_ptr<ResourceEntry> GetResourceEntry(const std::string& path) { |
| std::unique_ptr<ResourceEntry> entry(new ResourceEntry); |
| FileError error = metadata_->GetResourceEntryByPath( |
| base::FilePath::FromUTF8Unsafe(path), entry.get()); |
| if (error != FILE_ERROR_OK) |
| entry.reset(); |
| return entry; |
| } |
| |
| content::TestBrowserThreadBundle thread_bundle_; |
| base::ScopedTempDir temp_dir_; |
| std::unique_ptr<ResourceMetadataStorage, test_util::DestroyHelperForTests> |
| metadata_storage_; |
| std::unique_ptr<FakeFreeDiskSpaceGetter> fake_free_disk_space_getter_; |
| std::unique_ptr<FileCache, test_util::DestroyHelperForTests> cache_; |
| std::unique_ptr<ResourceMetadata, test_util::DestroyHelperForTests> metadata_; |
| }; |
| |
| } // namespace |
| |
| TEST_F(ChangeListProcessorTest, ApplyFullResourceList) { |
| EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList())); |
| |
| const EntryExpectation kExpected[] = { |
| // Root files |
| {"drive/root", kRootId, "", DIRECTORY}, |
| {"drive/root/File 1.txt", |
| "2_file_resource_id", kRootId, FILE}, |
| // Subdirectory files |
| {"drive/root/Directory 1", |
| "1_folder_resource_id", kRootId, DIRECTORY}, |
| {"drive/root/Directory 1/SubDirectory File 1.txt", |
| "subdirectory_file_1_id", "1_folder_resource_id", FILE}, |
| {"drive/root/Directory 2 excludeDir-test", |
| "sub_dir_folder_2_self_link", kRootId, DIRECTORY}, |
| // Deeper |
| {"drive/root/Directory 1/Sub Directory Folder", |
| "sub_dir_folder_resource_id", |
| "1_folder_resource_id", DIRECTORY}, |
| {"drive/root/Directory 1/Sub Directory Folder/Sub Sub Directory Folder", |
| "sub_sub_directory_folder_id", |
| "sub_dir_folder_resource_id", DIRECTORY}, |
| // Orphan |
| {"drive/other/Orphan File 1.txt", "1_orphanfile_resource_id", |
| "", FILE}, |
| }; |
| |
| for (size_t i = 0; i < base::size(kExpected); ++i) { |
| std::unique_ptr<ResourceEntry> entry = GetResourceEntry(kExpected[i].path); |
| ASSERT_TRUE(entry) << "for path: " << kExpected[i].path; |
| EXPECT_EQ(kExpected[i].id, entry->resource_id()); |
| |
| ResourceEntry parent_entry; |
| EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryById( |
| entry->parent_local_id(), &parent_entry)); |
| EXPECT_EQ(kExpected[i].parent_id, parent_entry.resource_id()); |
| EXPECT_EQ(kExpected[i].type, |
| entry->file_info().is_directory() ? DIRECTORY : FILE); |
| } |
| |
| std::string start_page_token; |
| EXPECT_EQ(FILE_ERROR_OK, metadata_->GetStartPageToken(&start_page_token)); |
| EXPECT_EQ(kBaseStartPageToken, start_page_token); |
| } |
| |
| TEST_F(ChangeListProcessorTest, DeltaFileAddedInNewDirectory) { |
| std::vector<std::unique_ptr<ChangeList>> change_lists; |
| change_lists.push_back(std::make_unique<ChangeList>()); |
| |
| ResourceEntry new_folder; |
| new_folder.set_resource_id("new_folder_resource_id"); |
| new_folder.set_title("New Directory"); |
| new_folder.mutable_file_info()->set_is_directory(true); |
| change_lists[0]->mutable_entries()->push_back(new_folder); |
| change_lists[0]->mutable_parent_resource_ids()->push_back(kRootId); |
| |
| ResourceEntry new_file; |
| new_file.set_resource_id("file_added_in_new_dir_id"); |
| new_file.set_title("File in new dir.txt"); |
| change_lists[0]->mutable_entries()->push_back(new_file); |
| change_lists[0]->mutable_parent_resource_ids()->push_back( |
| new_folder.resource_id()); |
| |
| change_lists[0]->set_new_start_page_token("16730"); |
| |
| // Apply the changelist and check the effect. |
| EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList())); |
| |
| FileChange changed_files; |
| FileChange changed_team_drives; |
| EXPECT_EQ(FILE_ERROR_OK, |
| ApplyUserChangeList(std::move(change_lists), &changed_files, |
| &changed_team_drives)); |
| |
| std::string start_page_token; |
| EXPECT_EQ(FILE_ERROR_OK, metadata_->GetStartPageToken(&start_page_token)); |
| EXPECT_EQ("16730", start_page_token); |
| EXPECT_TRUE(GetResourceEntry("drive/root/New Directory")); |
| EXPECT_TRUE(GetResourceEntry( |
| "drive/root/New Directory/File in new dir.txt")); |
| |
| EXPECT_TRUE(changed_team_drives.empty()); |
| EXPECT_EQ(2U, changed_files.size()); |
| EXPECT_TRUE(changed_files.count(base::FilePath::FromUTF8Unsafe( |
| "drive/root/New Directory/File in new dir.txt"))); |
| EXPECT_TRUE(changed_files.count( |
| base::FilePath::FromUTF8Unsafe("drive/root/New Directory"))); |
| } |
| |
| TEST_F(ChangeListProcessorTest, DeltaDirMovedFromRootToDirectory) { |
| std::vector<std::unique_ptr<ChangeList>> change_lists; |
| change_lists.push_back(std::make_unique<ChangeList>()); |
| |
| ResourceEntry entry; |
| entry.set_resource_id("1_folder_resource_id"); |
| entry.set_title("Directory 1"); |
| entry.mutable_file_info()->set_is_directory(true); |
| change_lists[0]->mutable_entries()->push_back(entry); |
| change_lists[0]->mutable_parent_resource_ids()->push_back( |
| "sub_dir_folder_2_self_link"); |
| |
| change_lists[0]->set_new_start_page_token("16809"); |
| |
| // Apply the changelist and check the effect. |
| EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList())); |
| |
| FileChange changed_files; |
| FileChange changed_team_drives; |
| EXPECT_EQ(FILE_ERROR_OK, |
| ApplyUserChangeList(std::move(change_lists), &changed_files, |
| &changed_team_drives)); |
| |
| std::string start_page_token; |
| EXPECT_EQ(FILE_ERROR_OK, metadata_->GetStartPageToken(&start_page_token)); |
| EXPECT_EQ("16809", start_page_token); |
| EXPECT_FALSE(GetResourceEntry("drive/root/Directory 1")); |
| EXPECT_TRUE(GetResourceEntry( |
| "drive/root/Directory 2 excludeDir-test/Directory 1")); |
| |
| EXPECT_TRUE(changed_team_drives.empty()); |
| EXPECT_EQ(2U, changed_files.size()); |
| EXPECT_TRUE(changed_files.CountDirectory( |
| base::FilePath::FromUTF8Unsafe("drive/root"))); |
| EXPECT_TRUE(changed_files.count( |
| base::FilePath::FromUTF8Unsafe("drive/root/Directory 1"))); |
| EXPECT_TRUE(changed_files.CountDirectory(base::FilePath::FromUTF8Unsafe( |
| "drive/root/Directory 2 excludeDir-test"))); |
| EXPECT_TRUE(changed_files.count(base::FilePath::FromUTF8Unsafe( |
| "drive/root/Directory 2 excludeDir-test/Directory 1"))); |
| } |
| |
| TEST_F(ChangeListProcessorTest, DeltaFileMovedFromDirectoryToRoot) { |
| std::vector<std::unique_ptr<ChangeList>> change_lists; |
| change_lists.push_back(std::make_unique<ChangeList>()); |
| |
| ResourceEntry entry; |
| entry.set_resource_id("subdirectory_file_1_id"); |
| entry.set_title("SubDirectory File 1.txt"); |
| change_lists[0]->mutable_entries()->push_back(entry); |
| change_lists[0]->mutable_parent_resource_ids()->push_back(kRootId); |
| |
| change_lists[0]->set_new_start_page_token("16815"); |
| |
| // Apply the changelist and check the effect. |
| EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList())); |
| FileChange changed_files; |
| FileChange changed_team_drives; |
| EXPECT_EQ(FILE_ERROR_OK, |
| ApplyUserChangeList(std::move(change_lists), &changed_files, |
| &changed_team_drives)); |
| |
| std::string start_page_token; |
| EXPECT_EQ(FILE_ERROR_OK, metadata_->GetStartPageToken(&start_page_token)); |
| EXPECT_EQ("16815", start_page_token); |
| EXPECT_FALSE(GetResourceEntry( |
| "drive/root/Directory 1/SubDirectory File 1.txt")); |
| EXPECT_TRUE(GetResourceEntry("drive/root/SubDirectory File 1.txt")); |
| |
| EXPECT_TRUE(changed_team_drives.empty()); |
| EXPECT_EQ(2U, changed_files.size()); |
| EXPECT_TRUE(changed_files.count( |
| base::FilePath::FromUTF8Unsafe("drive/root/SubDirectory File 1.txt"))); |
| EXPECT_TRUE(changed_files.count(base::FilePath::FromUTF8Unsafe( |
| "drive/root/Directory 1/SubDirectory File 1.txt"))); |
| } |
| |
| TEST_F(ChangeListProcessorTest, DeltaFileRenamedInDirectory) { |
| std::vector<std::unique_ptr<ChangeList>> change_lists; |
| change_lists.push_back(std::make_unique<ChangeList>()); |
| |
| ResourceEntry entry; |
| entry.set_resource_id("subdirectory_file_1_id"); |
| entry.set_title("New SubDirectory File 1.txt"); |
| change_lists[0]->mutable_entries()->push_back(entry); |
| change_lists[0]->mutable_parent_resource_ids()->push_back( |
| "1_folder_resource_id"); |
| |
| change_lists[0]->set_new_start_page_token("16767"); |
| |
| // Apply the changelist and check the effect. |
| EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList())); |
| FileChange changed_files; |
| FileChange changed_team_drives; |
| EXPECT_EQ(FILE_ERROR_OK, |
| ApplyUserChangeList(std::move(change_lists), &changed_files, |
| &changed_team_drives)); |
| |
| EXPECT_TRUE(changed_team_drives.empty()); |
| EXPECT_EQ(2U, changed_files.size()); |
| EXPECT_TRUE(changed_files.count(base::FilePath::FromUTF8Unsafe( |
| "drive/root/Directory 1/SubDirectory File 1.txt"))); |
| EXPECT_TRUE(changed_files.count(base::FilePath::FromUTF8Unsafe( |
| "drive/root/Directory 1/New SubDirectory File 1.txt"))); |
| |
| std::string start_page_token; |
| EXPECT_EQ(FILE_ERROR_OK, metadata_->GetStartPageToken(&start_page_token)); |
| EXPECT_EQ("16767", start_page_token); |
| EXPECT_FALSE(GetResourceEntry( |
| "drive/root/Directory 1/SubDirectory File 1.txt")); |
| std::unique_ptr<ResourceEntry> new_entry( |
| GetResourceEntry("drive/root/Directory 1/New SubDirectory File 1.txt")); |
| ASSERT_TRUE(new_entry); |
| |
| // Keep the to-be-synced properties. |
| ASSERT_EQ(1, new_entry->mutable_new_properties()->size()); |
| const Property& new_property = new_entry->new_properties().Get(0); |
| EXPECT_EQ("hello", new_property.key()); |
| } |
| |
| TEST_F(ChangeListProcessorTest, DeltaAddAndDeleteFileInRoot) { |
| // Create ChangeList to add a file. |
| std::vector<std::unique_ptr<ChangeList>> change_lists; |
| change_lists.push_back(std::make_unique<ChangeList>()); |
| |
| ResourceEntry entry; |
| entry.set_resource_id("added_in_root_id"); |
| entry.set_title("Added file.txt"); |
| change_lists[0]->mutable_entries()->push_back(entry); |
| change_lists[0]->mutable_parent_resource_ids()->push_back(kRootId); |
| |
| change_lists[0]->set_new_start_page_token("16683"); |
| |
| // Apply. |
| EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList())); |
| FileChange changed_files; |
| FileChange changed_team_drives; |
| EXPECT_EQ(FILE_ERROR_OK, |
| ApplyUserChangeList(std::move(change_lists), &changed_files, |
| &changed_team_drives)); |
| |
| std::string start_page_token; |
| EXPECT_EQ(FILE_ERROR_OK, metadata_->GetStartPageToken(&start_page_token)); |
| EXPECT_EQ("16683", start_page_token); |
| EXPECT_TRUE(GetResourceEntry("drive/root/Added file.txt")); |
| EXPECT_TRUE(changed_team_drives.empty()); |
| EXPECT_EQ(1U, changed_files.size()); |
| EXPECT_TRUE(changed_files.count( |
| base::FilePath::FromUTF8Unsafe("drive/root/Added file.txt"))); |
| |
| // Create ChangeList to delete the file. |
| change_lists.push_back(std::make_unique<ChangeList>()); |
| |
| entry.set_deleted(true); |
| change_lists[0]->mutable_entries()->push_back(entry); |
| change_lists[0]->mutable_parent_resource_ids()->push_back(kRootId); |
| |
| change_lists[0]->set_new_start_page_token("16687"); |
| |
| // Apply. |
| EXPECT_EQ(FILE_ERROR_OK, |
| ApplyUserChangeList(std::move(change_lists), &changed_files, |
| &changed_team_drives)); |
| EXPECT_EQ(FILE_ERROR_OK, metadata_->GetStartPageToken(&start_page_token)); |
| EXPECT_EQ("16687", start_page_token); |
| EXPECT_FALSE(GetResourceEntry("drive/root/Added file.txt")); |
| EXPECT_TRUE(changed_team_drives.empty()); |
| EXPECT_EQ(1U, changed_files.size()); |
| EXPECT_TRUE(changed_files.count( |
| base::FilePath::FromUTF8Unsafe("drive/root/Added file.txt"))); |
| } |
| |
| |
| TEST_F(ChangeListProcessorTest, DeltaAddAndDeleteFileFromExistingDirectory) { |
| // Create ChangeList to add a file. |
| std::vector<std::unique_ptr<ChangeList>> change_lists; |
| change_lists.push_back(std::make_unique<ChangeList>()); |
| |
| ResourceEntry entry; |
| entry.set_resource_id("added_in_root_id"); |
| entry.set_title("Added file.txt"); |
| change_lists[0]->mutable_entries()->push_back(entry); |
| change_lists[0]->mutable_parent_resource_ids()->push_back( |
| "1_folder_resource_id"); |
| |
| change_lists[0]->set_new_start_page_token("16730"); |
| |
| // Apply. |
| EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList())); |
| FileChange changed_files; |
| FileChange changed_team_drives; |
| EXPECT_EQ(FILE_ERROR_OK, |
| ApplyUserChangeList(std::move(change_lists), &changed_files, |
| &changed_team_drives)); |
| std::string start_page_token; |
| EXPECT_EQ(FILE_ERROR_OK, metadata_->GetStartPageToken(&start_page_token)); |
| EXPECT_EQ("16730", start_page_token); |
| EXPECT_TRUE(GetResourceEntry("drive/root/Directory 1/Added file.txt")); |
| |
| EXPECT_TRUE(changed_team_drives.empty()); |
| EXPECT_EQ(1U, changed_files.size()); |
| EXPECT_TRUE(changed_files.count( |
| base::FilePath::FromUTF8Unsafe("drive/root/Directory 1/Added file.txt"))); |
| |
| // Create ChangeList to delete the file. |
| change_lists.push_back(std::make_unique<ChangeList>()); |
| |
| entry.set_deleted(true); |
| change_lists[0]->mutable_entries()->push_back(entry); |
| change_lists[0]->mutable_parent_resource_ids()->push_back( |
| "1_folder_resource_id"); |
| |
| change_lists[0]->set_new_start_page_token("16770"); |
| |
| // Apply. |
| EXPECT_EQ(FILE_ERROR_OK, |
| ApplyUserChangeList(std::move(change_lists), &changed_files, |
| &changed_team_drives)); |
| EXPECT_EQ(FILE_ERROR_OK, metadata_->GetStartPageToken(&start_page_token)); |
| EXPECT_EQ("16770", start_page_token); |
| EXPECT_FALSE(GetResourceEntry("drive/root/Directory 1/Added file.txt")); |
| |
| EXPECT_TRUE(changed_team_drives.empty()); |
| EXPECT_EQ(1U, changed_files.size()); |
| EXPECT_TRUE(changed_files.count( |
| base::FilePath::FromUTF8Unsafe("drive/root/Directory 1/Added file.txt"))); |
| } |
| |
| TEST_F(ChangeListProcessorTest, DeltaAddFileToNewButDeletedDirectory) { |
| // Create a change which contains the following updates: |
| // 1) A new PDF file is added to a new directory |
| // 2) but the new directory is marked "deleted" (i.e. moved to Trash) |
| // Hence, the PDF file should be just ignored. |
| std::vector<std::unique_ptr<ChangeList>> change_lists; |
| change_lists.push_back(std::make_unique<ChangeList>()); |
| |
| ResourceEntry file; |
| file.set_resource_id("file_added_in_deleted_id"); |
| file.set_title("new_pdf_file.pdf"); |
| file.set_deleted(true); |
| change_lists[0]->mutable_entries()->push_back(file); |
| change_lists[0]->mutable_parent_resource_ids()->push_back( |
| "new_folder_resource_id"); |
| |
| ResourceEntry directory; |
| directory.set_resource_id("new_folder_resource_id"); |
| directory.set_title("New Directory"); |
| directory.mutable_file_info()->set_is_directory(true); |
| directory.set_deleted(true); |
| change_lists[0]->mutable_entries()->push_back(directory); |
| change_lists[0]->mutable_parent_resource_ids()->push_back(kRootId); |
| |
| change_lists[0]->set_new_start_page_token("16730"); |
| |
| // Apply the changelist and check the effect. |
| EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList())); |
| FileChange changed_files; |
| FileChange changed_team_drives; |
| EXPECT_EQ(FILE_ERROR_OK, |
| ApplyUserChangeList(std::move(change_lists), &changed_files, |
| &changed_team_drives)); |
| |
| std::string start_page_token; |
| EXPECT_EQ(FILE_ERROR_OK, metadata_->GetStartPageToken(&start_page_token)); |
| EXPECT_EQ("16730", start_page_token); |
| EXPECT_FALSE(GetResourceEntry("drive/root/New Directory/new_pdf_file.pdf")); |
| |
| EXPECT_TRUE(changed_team_drives.empty()); |
| EXPECT_TRUE(changed_files.empty()); |
| } |
| |
| TEST_F(ChangeListProcessorTest, RefreshDirectory) { |
| // Prepare metadata. |
| EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList())); |
| |
| // Create change list. |
| std::unique_ptr<ChangeList> change_list(new ChangeList); |
| |
| // Add a new file to the change list. |
| ResourceEntry new_file; |
| new_file.set_title("new_file"); |
| new_file.set_resource_id("new_file_id"); |
| change_list->mutable_entries()->push_back(new_file); |
| change_list->mutable_parent_resource_ids()->push_back(kRootId); |
| |
| // Add "Directory 1" to the map with a new name. |
| ResourceEntry dir1; |
| EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath( |
| util::GetDriveMyDriveRootPath().AppendASCII("Directory 1"), &dir1)); |
| dir1.set_title(dir1.title() + " (renamed)"); |
| change_list->mutable_entries()->push_back(dir1); |
| change_list->mutable_parent_resource_ids()->push_back(kRootId); |
| |
| // Update the directory with the map. |
| ResourceEntry root; |
| EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath( |
| util::GetDriveMyDriveRootPath(), &root)); |
| const std::string kNewStartpageToken = "12345"; |
| ResourceEntryVector refreshed_entries; |
| EXPECT_EQ(FILE_ERROR_OK, |
| ChangeListProcessor::RefreshDirectory( |
| metadata_.get(), |
| DirectoryFetchInfo(root.local_id(), kRootId, kNewStartpageToken, |
| util::GetDriveMyDriveRootPath(), |
| util::GetDriveMyDriveRootPath()), |
| std::move(change_list), &refreshed_entries)); |
| |
| // "new_file" should be added. |
| ResourceEntry entry; |
| EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath( |
| util::GetDriveMyDriveRootPath().AppendASCII(new_file.title()), &entry)); |
| |
| // "Directory 1" should be renamed. |
| EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath( |
| util::GetDriveMyDriveRootPath().AppendASCII(dir1.title()), &entry)); |
| } |
| |
| TEST_F(ChangeListProcessorTest, RefreshDirectory_WrongParentId) { |
| // Prepare metadata. |
| EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList())); |
| |
| // Create change list and add a new file to it. |
| std::unique_ptr<ChangeList> change_list(new ChangeList); |
| ResourceEntry new_file; |
| new_file.set_title("new_file"); |
| new_file.set_resource_id("new_file_id"); |
| // This entry should not be added because the parent ID does not match. |
| change_list->mutable_parent_resource_ids()->push_back( |
| "some-random-resource-id"); |
| change_list->mutable_entries()->push_back(new_file); |
| |
| |
| // Update the directory. |
| ResourceEntry root; |
| EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath( |
| util::GetDriveMyDriveRootPath(), &root)); |
| const std::string kNewStartpageToken = "12345"; |
| ResourceEntryVector refreshed_entries; |
| EXPECT_EQ(FILE_ERROR_OK, |
| ChangeListProcessor::RefreshDirectory( |
| metadata_.get(), |
| DirectoryFetchInfo(root.local_id(), kRootId, kNewStartpageToken, |
| util::GetDriveMyDriveRootPath(), |
| util::GetDriveMyDriveRootPath()), |
| std::move(change_list), &refreshed_entries)); |
| |
| // "new_file" should not be added. |
| ResourceEntry entry; |
| EXPECT_EQ(FILE_ERROR_NOT_FOUND, metadata_->GetResourceEntryByPath( |
| util::GetDriveMyDriveRootPath().AppendASCII(new_file.title()), &entry)); |
| } |
| |
| TEST_F(ChangeListProcessorTest, SharedFilesWithNoParentInFeed) { |
| // Prepare metadata. |
| EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList())); |
| |
| // Create change lists. |
| std::vector<std::unique_ptr<ChangeList>> change_lists; |
| change_lists.push_back(std::make_unique<ChangeList>()); |
| |
| // Add a new file with non-existing parent resource id to the change lists. |
| ResourceEntry new_file; |
| new_file.set_title("new_file"); |
| new_file.set_resource_id("new_file_id"); |
| change_lists[0]->mutable_entries()->push_back(new_file); |
| change_lists[0]->mutable_parent_resource_ids()->push_back("nonexisting"); |
| change_lists[0]->set_new_start_page_token("123"); |
| |
| FileChange changed_files; |
| FileChange changed_team_drives; |
| EXPECT_EQ(FILE_ERROR_OK, |
| ApplyUserChangeList(std::move(change_lists), &changed_files, |
| &changed_team_drives)); |
| |
| // "new_file" should be added under drive/other. |
| ResourceEntry entry; |
| EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath( |
| util::GetDriveGrandRootPath().AppendASCII("other/new_file"), &entry)); |
| } |
| |
| TEST_F(ChangeListProcessorTest, ModificationDate) { |
| // Prepare metadata. |
| EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList())); |
| |
| // Create change lists with a new file. |
| std::vector<std::unique_ptr<ChangeList>> change_lists; |
| change_lists.push_back(std::make_unique<ChangeList>()); |
| |
| const base::Time now = base::Time::Now(); |
| ResourceEntry new_file_remote; |
| new_file_remote.set_title("new_file_remote"); |
| new_file_remote.set_resource_id("new_file_id"); |
| new_file_remote.set_modification_date(now.ToInternalValue()); |
| |
| change_lists[0]->mutable_entries()->push_back(new_file_remote); |
| change_lists[0]->mutable_parent_resource_ids()->push_back(kRootId); |
| change_lists[0]->set_new_start_page_token("123"); |
| |
| // Add the same file locally, but with a different name, a dirty metadata |
| // state, and a newer modification date. |
| ResourceEntry root; |
| EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath( |
| util::GetDriveMyDriveRootPath(), &root)); |
| |
| ResourceEntry new_file_local; |
| new_file_local.set_resource_id(new_file_remote.resource_id()); |
| new_file_local.set_parent_local_id(root.local_id()); |
| new_file_local.set_title("new_file_local"); |
| new_file_local.set_metadata_edit_state(ResourceEntry::DIRTY); |
| new_file_local.set_modification_date( |
| (now + base::TimeDelta::FromSeconds(1)).ToInternalValue()); |
| std::string local_id; |
| EXPECT_EQ(FILE_ERROR_OK, metadata_->AddEntry(new_file_local, &local_id)); |
| |
| // Apply the change. |
| FileChange changed_files; |
| FileChange changed_team_drives; |
| EXPECT_EQ(FILE_ERROR_OK, |
| ApplyUserChangeList(std::move(change_lists), &changed_files, |
| &changed_team_drives)); |
| |
| // The change is rejected due to the old modification date. |
| ResourceEntry entry; |
| EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryById(local_id, &entry)); |
| EXPECT_EQ(new_file_local.title(), entry.title()); |
| } |
| |
| TEST_F(ChangeListProcessorTest, AddNewTeamDrive) { |
| std::vector<std::unique_ptr<ChangeList>> change_lists; |
| change_lists.push_back(std::make_unique<ChangeList>()); |
| |
| ResourceEntry team_drive; |
| team_drive.set_resource_id("team_drive_resource_id"); |
| team_drive.set_title("New Team Drive"); |
| team_drive.mutable_file_info()->set_is_directory(true); |
| team_drive.mutable_file_info()->set_is_team_drive_root(true); |
| team_drive.set_parent_local_id(util::kDriveTeamDrivesDirLocalId); |
| change_lists[0]->mutable_entries()->push_back(team_drive); |
| change_lists[0]->mutable_parent_resource_ids()->push_back( |
| util::kDriveTeamDrivesDirLocalId); |
| |
| change_lists[0]->set_new_start_page_token("16730"); |
| |
| // Apply the changelist and check the effect. |
| EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList())); |
| |
| FileChange changed_files; |
| FileChange changed_team_drives; |
| EXPECT_EQ(FILE_ERROR_OK, |
| ApplyUserChangeList(std::move(change_lists), &changed_files, |
| &changed_team_drives)); |
| |
| std::string start_page_token; |
| EXPECT_EQ(FILE_ERROR_OK, metadata_->GetStartPageToken(&start_page_token)); |
| EXPECT_EQ("16730", start_page_token); |
| |
| constexpr char kExpectedPath[] = "drive/team_drives/New Team Drive"; |
| EXPECT_TRUE(GetResourceEntry(kExpectedPath)); |
| |
| // A new team drive will be in both changed_files and changed_team_drives. |
| EXPECT_EQ(1U, changed_files.size()); |
| EXPECT_TRUE( |
| changed_files.count(base::FilePath::FromUTF8Unsafe(kExpectedPath))); |
| |
| EXPECT_EQ(1U, changed_team_drives.size()); |
| EXPECT_TRUE( |
| changed_team_drives.count(base::FilePath::FromUTF8Unsafe(kExpectedPath))); |
| } |
| |
| TEST_F(ChangeListProcessorTest, AddAndDeleteTeamDrive) { |
| // Create ChangeList to add a file. |
| std::vector<std::unique_ptr<ChangeList>> change_lists; |
| change_lists.push_back(std::make_unique<ChangeList>()); |
| |
| ResourceEntry team_drive; |
| team_drive.set_resource_id("team_drive_resource_id"); |
| team_drive.set_title("New Team Drive"); |
| team_drive.mutable_file_info()->set_is_directory(true); |
| team_drive.mutable_file_info()->set_is_team_drive_root(true); |
| team_drive.set_parent_local_id(util::kDriveTeamDrivesDirLocalId); |
| change_lists[0]->mutable_entries()->push_back(team_drive); |
| change_lists[0]->mutable_parent_resource_ids()->push_back( |
| util::kDriveTeamDrivesDirLocalId); |
| |
| change_lists[0]->set_new_start_page_token("16683"); |
| |
| // Apply. |
| EXPECT_EQ(FILE_ERROR_OK, ApplyFullResourceList(CreateBaseChangeList())); |
| FileChange changed_files; |
| FileChange changed_team_drives; |
| EXPECT_EQ(FILE_ERROR_OK, |
| ApplyUserChangeList(std::move(change_lists), &changed_files, |
| &changed_team_drives)); |
| |
| std::string start_page_token; |
| EXPECT_EQ(FILE_ERROR_OK, metadata_->GetStartPageToken(&start_page_token)); |
| EXPECT_EQ("16683", start_page_token); |
| constexpr char kExpectedPath[] = "drive/team_drives/New Team Drive"; |
| |
| EXPECT_TRUE(GetResourceEntry(kExpectedPath)); |
| EXPECT_EQ(1U, changed_files.size()); |
| EXPECT_TRUE( |
| changed_files.count(base::FilePath::FromUTF8Unsafe(kExpectedPath))); |
| EXPECT_EQ(1U, changed_team_drives.size()); |
| EXPECT_TRUE( |
| changed_team_drives.count(base::FilePath::FromUTF8Unsafe(kExpectedPath))); |
| |
| // Create ChangeList to delete the file. |
| change_lists.push_back(std::make_unique<ChangeList>()); |
| |
| team_drive.set_deleted(true); |
| change_lists[0]->mutable_entries()->push_back(team_drive); |
| change_lists[0]->mutable_parent_resource_ids()->push_back( |
| util::kDriveTeamDrivesDirLocalId); |
| |
| change_lists[0]->set_new_start_page_token("16687"); |
| |
| // Apply. |
| EXPECT_EQ(FILE_ERROR_OK, |
| ApplyUserChangeList(std::move(change_lists), &changed_files, |
| &changed_team_drives)); |
| EXPECT_EQ(FILE_ERROR_OK, metadata_->GetStartPageToken(&start_page_token)); |
| EXPECT_EQ("16687", start_page_token); |
| EXPECT_FALSE(GetResourceEntry(kExpectedPath)); |
| EXPECT_EQ(1U, changed_files.size()); |
| EXPECT_TRUE( |
| changed_files.count(base::FilePath::FromUTF8Unsafe(kExpectedPath))); |
| EXPECT_EQ(1U, changed_team_drives.size()); |
| EXPECT_TRUE( |
| changed_team_drives.count(base::FilePath::FromUTF8Unsafe(kExpectedPath))); |
| } |
| |
| } // namespace internal |
| } // namespace drive |