| // 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/resource_metadata.h" |
| |
| #include <stddef.h> |
| #include <stdint.h> |
| |
| #include <algorithm> |
| #include <string> |
| #include <vector> |
| |
| #include "base/files/scoped_temp_dir.h" |
| #include "base/single_thread_task_runner.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/threading/thread_task_runner_handle.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/drive.pb.h" |
| #include "components/drive/file_system_core_util.h" |
| #include "content/public/test/test_browser_thread_bundle.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace drive { |
| namespace internal { |
| namespace { |
| |
| // The changestamp of the resource metadata used in |
| // ResourceMetadataTest. |
| const int64_t kTestChangestamp = 100; |
| |
| // Returns the sorted base names from |entries|. |
| std::vector<std::string> GetSortedBaseNames( |
| const ResourceEntryVector& entries) { |
| std::vector<std::string> base_names; |
| for (size_t i = 0; i < entries.size(); ++i) |
| base_names.push_back(entries[i].base_name()); |
| std::sort(base_names.begin(), base_names.end()); |
| |
| return base_names; |
| } |
| |
| // Creates a ResourceEntry for a directory with explicitly set resource_id. |
| ResourceEntry CreateDirectoryEntryWithResourceId( |
| const std::string& title, |
| const std::string& resource_id, |
| const std::string& parent_local_id) { |
| ResourceEntry entry; |
| entry.set_title(title); |
| entry.set_resource_id(resource_id); |
| entry.set_parent_local_id(parent_local_id); |
| entry.mutable_file_info()->set_is_directory(true); |
| entry.mutable_directory_specific_info()->set_changestamp(kTestChangestamp); |
| return entry; |
| } |
| |
| // Creates a ResourceEntry for a directory. |
| ResourceEntry CreateDirectoryEntry(const std::string& title, |
| const std::string& parent_local_id) { |
| return CreateDirectoryEntryWithResourceId( |
| title, "id:" + title, parent_local_id); |
| } |
| |
| // Creates a ResourceEntry for a file with explicitly set resource_id. |
| ResourceEntry CreateFileEntryWithResourceId( |
| const std::string& title, |
| const std::string& resource_id, |
| const std::string& parent_local_id) { |
| ResourceEntry entry; |
| entry.set_title(title); |
| entry.set_resource_id(resource_id); |
| entry.set_parent_local_id(parent_local_id); |
| entry.mutable_file_info()->set_is_directory(false); |
| entry.mutable_file_info()->set_size(1024); |
| entry.mutable_file_specific_info()->set_md5("md5:" + title); |
| return entry; |
| } |
| |
| // Creates a ResourceEntry for a file. |
| ResourceEntry CreateFileEntry(const std::string& title, |
| const std::string& parent_local_id) { |
| return CreateFileEntryWithResourceId(title, "id:" + title, parent_local_id); |
| } |
| |
| // Creates the following files/directories |
| // drive/root/dir1/ |
| // drive/root/dir2/ |
| // drive/root/dir1/dir3/ |
| // drive/root/dir1/file4 |
| // drive/root/dir1/file5 |
| // drive/root/dir2/file6 |
| // drive/root/dir2/file7 |
| // drive/root/dir2/file8 |
| // drive/root/dir1/dir3/file9 |
| // drive/root/dir1/dir3/file10 |
| void SetUpEntries(ResourceMetadata* resource_metadata) { |
| std::string local_id; |
| ASSERT_EQ(FILE_ERROR_OK, resource_metadata->GetIdByPath( |
| util::GetDriveMyDriveRootPath(), &local_id)); |
| const std::string root_local_id = local_id; |
| |
| ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry( |
| CreateDirectoryEntry("dir1", root_local_id), &local_id)); |
| const std::string local_id_dir1 = local_id; |
| |
| ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry( |
| CreateDirectoryEntry("dir2", root_local_id), &local_id)); |
| const std::string local_id_dir2 = local_id; |
| |
| ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry( |
| CreateDirectoryEntry("dir3", local_id_dir1), &local_id)); |
| const std::string local_id_dir3 = local_id; |
| |
| ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry( |
| CreateFileEntry("file4", local_id_dir1), &local_id)); |
| ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry( |
| CreateFileEntry("file5", local_id_dir1), &local_id)); |
| |
| ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry( |
| CreateFileEntry("file6", local_id_dir2), &local_id)); |
| ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry( |
| CreateFileEntry("file7", local_id_dir2), &local_id)); |
| ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry( |
| CreateFileEntry("file8", local_id_dir2), &local_id)); |
| |
| ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry( |
| CreateFileEntry("file9", local_id_dir3), &local_id)); |
| ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry( |
| CreateFileEntry("file10", local_id_dir3), &local_id)); |
| |
| ASSERT_EQ(FILE_ERROR_OK, |
| resource_metadata->SetLargestChangestamp(kTestChangestamp)); |
| } |
| |
| } // namespace |
| |
| // Tests for methods running on the blocking task runner. |
| class ResourceMetadataTest : public testing::Test { |
| protected: |
| void SetUp() override { |
| ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| |
| metadata_storage_.reset(new ResourceMetadataStorage( |
| temp_dir_.path(), base::ThreadTaskRunnerHandle::Get().get())); |
| ASSERT_TRUE(metadata_storage_->Initialize()); |
| |
| fake_free_disk_space_getter_.reset(new FakeFreeDiskSpaceGetter); |
| cache_.reset(new FileCache(metadata_storage_.get(), |
| temp_dir_.path(), |
| base::ThreadTaskRunnerHandle::Get().get(), |
| fake_free_disk_space_getter_.get())); |
| ASSERT_TRUE(cache_->Initialize()); |
| |
| resource_metadata_.reset(new ResourceMetadata( |
| metadata_storage_.get(), cache_.get(), |
| base::ThreadTaskRunnerHandle::Get())); |
| |
| ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->Initialize()); |
| |
| SetUpEntries(resource_metadata_.get()); |
| } |
| |
| base::ScopedTempDir temp_dir_; |
| content::TestBrowserThreadBundle thread_bundle_; |
| 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> |
| resource_metadata_; |
| }; |
| |
| TEST_F(ResourceMetadataTest, LargestChangestamp) { |
| const int64_t kChangestamp = 123456; |
| EXPECT_EQ(FILE_ERROR_OK, |
| resource_metadata_->SetLargestChangestamp(kChangestamp)); |
| int64_t changestamp = 0; |
| EXPECT_EQ(FILE_ERROR_OK, |
| resource_metadata_->GetLargestChangestamp(&changestamp)); |
| EXPECT_EQ(kChangestamp, changestamp); |
| } |
| |
| TEST_F(ResourceMetadataTest, GetResourceEntryByPath) { |
| // Confirm that an existing file is found. |
| ResourceEntry entry; |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath( |
| base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"), &entry)); |
| EXPECT_EQ("file4", entry.base_name()); |
| |
| // Confirm that a non existing file is not found. |
| EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->GetResourceEntryByPath( |
| base::FilePath::FromUTF8Unsafe("drive/root/dir1/non_existing"), &entry)); |
| |
| // Confirm that the root is found. |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath( |
| base::FilePath::FromUTF8Unsafe("drive"), &entry)); |
| |
| // Confirm that a non existing file is not found at the root level. |
| EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->GetResourceEntryByPath( |
| base::FilePath::FromUTF8Unsafe("non_existing"), &entry)); |
| |
| // Confirm that an entry is not found with a wrong root. |
| EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->GetResourceEntryByPath( |
| base::FilePath::FromUTF8Unsafe("non_existing/root"), &entry)); |
| } |
| |
| TEST_F(ResourceMetadataTest, ReadDirectoryByPath) { |
| // Confirm that an existing directory is found. |
| ResourceEntryVector entries; |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->ReadDirectoryByPath( |
| base::FilePath::FromUTF8Unsafe("drive/root/dir1"), &entries)); |
| ASSERT_EQ(3U, entries.size()); |
| // The order is not guaranteed so we should sort the base names. |
| std::vector<std::string> base_names = GetSortedBaseNames(entries); |
| EXPECT_EQ("dir3", base_names[0]); |
| EXPECT_EQ("file4", base_names[1]); |
| EXPECT_EQ("file5", base_names[2]); |
| |
| // Confirm that a non existing directory is not found. |
| EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->ReadDirectoryByPath( |
| base::FilePath::FromUTF8Unsafe("drive/root/non_existing"), &entries)); |
| |
| // Confirm that reading a file results in FILE_ERROR_NOT_A_DIRECTORY. |
| EXPECT_EQ(FILE_ERROR_NOT_A_DIRECTORY, resource_metadata_->ReadDirectoryByPath( |
| base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"), &entries)); |
| } |
| |
| TEST_F(ResourceMetadataTest, RefreshEntry) { |
| base::FilePath drive_file_path; |
| ResourceEntry entry; |
| |
| // Get file9. |
| std::string file_id; |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath( |
| base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3/file9"), &file_id)); |
| EXPECT_EQ(FILE_ERROR_OK, |
| resource_metadata_->GetResourceEntryById(file_id, &entry)); |
| EXPECT_EQ("file9", entry.base_name()); |
| EXPECT_TRUE(!entry.file_info().is_directory()); |
| EXPECT_EQ("md5:file9", entry.file_specific_info().md5()); |
| |
| // Rename it. |
| ResourceEntry file_entry(entry); |
| file_entry.set_title("file100"); |
| EXPECT_EQ(FILE_ERROR_OK, |
| resource_metadata_->RefreshEntry(file_entry)); |
| |
| base::FilePath path; |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetFilePath(file_id, &path)); |
| EXPECT_EQ("drive/root/dir1/dir3/file100", path.AsUTF8Unsafe()); |
| entry.Clear(); |
| EXPECT_EQ(FILE_ERROR_OK, |
| resource_metadata_->GetResourceEntryById(file_id, &entry)); |
| EXPECT_EQ("file100", entry.base_name()); |
| EXPECT_TRUE(!entry.file_info().is_directory()); |
| EXPECT_EQ("md5:file9", entry.file_specific_info().md5()); |
| |
| // Update the file md5. |
| const std::string updated_md5("md5:updated"); |
| file_entry = entry; |
| file_entry.mutable_file_specific_info()->set_md5(updated_md5); |
| EXPECT_EQ(FILE_ERROR_OK, |
| resource_metadata_->RefreshEntry(file_entry)); |
| |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetFilePath(file_id, &path)); |
| EXPECT_EQ("drive/root/dir1/dir3/file100", path.AsUTF8Unsafe()); |
| entry.Clear(); |
| EXPECT_EQ(FILE_ERROR_OK, |
| resource_metadata_->GetResourceEntryById(file_id, &entry)); |
| EXPECT_EQ("file100", entry.base_name()); |
| EXPECT_TRUE(!entry.file_info().is_directory()); |
| EXPECT_EQ(updated_md5, entry.file_specific_info().md5()); |
| |
| // Make sure we get the same thing from GetResourceEntryByPath. |
| entry.Clear(); |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath( |
| base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3/file100"), &entry)); |
| EXPECT_EQ("file100", entry.base_name()); |
| ASSERT_TRUE(!entry.file_info().is_directory()); |
| EXPECT_EQ(updated_md5, entry.file_specific_info().md5()); |
| |
| // Get dir2. |
| entry.Clear(); |
| std::string dir_id; |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath( |
| base::FilePath::FromUTF8Unsafe("drive/root/dir2"), &dir_id)); |
| EXPECT_EQ(FILE_ERROR_OK, |
| resource_metadata_->GetResourceEntryById(dir_id, &entry)); |
| EXPECT_EQ("dir2", entry.base_name()); |
| ASSERT_TRUE(entry.file_info().is_directory()); |
| |
| // Get dir3's ID. |
| std::string dir3_id; |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath( |
| base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3"), &dir3_id)); |
| |
| // Change the name to dir100 and change the parent to drive/dir1/dir3. |
| ResourceEntry dir_entry(entry); |
| dir_entry.set_title("dir100"); |
| dir_entry.set_parent_local_id(dir3_id); |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->RefreshEntry(dir_entry)); |
| |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetFilePath(dir_id, &path)); |
| EXPECT_EQ("drive/root/dir1/dir3/dir100", path.AsUTF8Unsafe()); |
| entry.Clear(); |
| EXPECT_EQ(FILE_ERROR_OK, |
| resource_metadata_->GetResourceEntryById(dir_id, &entry)); |
| EXPECT_EQ("dir100", entry.base_name()); |
| EXPECT_TRUE(entry.file_info().is_directory()); |
| EXPECT_EQ("id:dir2", entry.resource_id()); |
| |
| // Make sure the children have moved over. Test file6. |
| entry.Clear(); |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath( |
| base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3/dir100/file6"), |
| &entry)); |
| EXPECT_EQ("file6", entry.base_name()); |
| |
| // Make sure dir2 no longer exists. |
| EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->GetResourceEntryByPath( |
| base::FilePath::FromUTF8Unsafe("drive/root/dir2"), &entry)); |
| |
| // Make sure that directory cannot move under a file. |
| dir_entry.set_parent_local_id(file_id); |
| EXPECT_EQ(FILE_ERROR_NOT_A_DIRECTORY, |
| resource_metadata_->RefreshEntry(dir_entry)); |
| |
| // Cannot refresh root. |
| dir_entry.Clear(); |
| dir_entry.set_local_id(util::kDriveGrandRootLocalId); |
| dir_entry.set_title("new-root-name"); |
| dir_entry.set_parent_local_id(dir3_id); |
| EXPECT_EQ(FILE_ERROR_INVALID_OPERATION, |
| resource_metadata_->RefreshEntry(dir_entry)); |
| } |
| |
| TEST_F(ResourceMetadataTest, RefreshEntry_ResourceIDCheck) { |
| // Get an entry with a non-empty resource ID. |
| ResourceEntry entry; |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath( |
| base::FilePath::FromUTF8Unsafe("drive/root/dir1"), &entry)); |
| EXPECT_FALSE(entry.resource_id().empty()); |
| |
| // Add a new entry with an empty resource ID. |
| ResourceEntry new_entry; |
| new_entry.set_parent_local_id(entry.local_id()); |
| new_entry.set_title("new entry"); |
| std::string local_id; |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(new_entry, &local_id)); |
| |
| // Try to refresh the new entry with a used resource ID. |
| new_entry.set_local_id(local_id); |
| new_entry.set_resource_id(entry.resource_id()); |
| EXPECT_EQ(FILE_ERROR_INVALID_OPERATION, |
| resource_metadata_->RefreshEntry(new_entry)); |
| } |
| |
| TEST_F(ResourceMetadataTest, RefreshEntry_DoNotOverwriteCacheState) { |
| ResourceEntry entry; |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath( |
| base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"), &entry)); |
| |
| // Try to set MD5 with RefreshEntry. |
| entry.mutable_file_specific_info()->mutable_cache_state()->set_md5("md5"); |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->RefreshEntry(entry)); |
| |
| // Cache state is unchanged. |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath( |
| base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"), &entry)); |
| EXPECT_TRUE(entry.file_specific_info().cache_state().md5().empty()); |
| |
| // Pin the file. |
| EXPECT_EQ(FILE_ERROR_OK, cache_->Pin(entry.local_id())); |
| |
| // Try to clear the cache state with RefreshEntry. |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath( |
| base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"), &entry)); |
| entry.mutable_file_specific_info()->clear_cache_state(); |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->RefreshEntry(entry)); |
| |
| // Cache state is not cleared. |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath( |
| base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"), &entry)); |
| EXPECT_TRUE(entry.file_specific_info().cache_state().is_pinned()); |
| } |
| |
| TEST_F(ResourceMetadataTest, GetSubDirectoriesRecursively) { |
| std::set<base::FilePath> sub_directories; |
| |
| // file9: not a directory, so no children. |
| std::string local_id; |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath( |
| base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3/file9"), &local_id)); |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetSubDirectoriesRecursively( |
| local_id, &sub_directories)); |
| EXPECT_TRUE(sub_directories.empty()); |
| |
| // dir2: no child directories. |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath( |
| base::FilePath::FromUTF8Unsafe("drive/root/dir2"), &local_id)); |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetSubDirectoriesRecursively( |
| local_id, &sub_directories)); |
| EXPECT_TRUE(sub_directories.empty()); |
| const std::string dir2_id = local_id; |
| |
| // dir1: dir3 is the only child |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath( |
| base::FilePath::FromUTF8Unsafe("drive/root/dir1"), &local_id)); |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetSubDirectoriesRecursively( |
| local_id, &sub_directories)); |
| EXPECT_EQ(1u, sub_directories.size()); |
| EXPECT_EQ(1u, sub_directories.count( |
| base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3"))); |
| sub_directories.clear(); |
| |
| // Add a few more directories to make sure deeper nesting works. |
| // dir2/dir100 |
| // dir2/dir101 |
| // dir2/dir101/dir102 |
| // dir2/dir101/dir103 |
| // dir2/dir101/dir104 |
| // dir2/dir101/dir104/dir105 |
| // dir2/dir101/dir104/dir105/dir106 |
| // dir2/dir101/dir104/dir105/dir106/dir107 |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( |
| CreateDirectoryEntry("dir100", dir2_id), &local_id)); |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( |
| CreateDirectoryEntry("dir101", dir2_id), &local_id)); |
| const std::string dir101_id = local_id; |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( |
| CreateDirectoryEntry("dir102", dir101_id), &local_id)); |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( |
| CreateDirectoryEntry("dir103", dir101_id), &local_id)); |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( |
| CreateDirectoryEntry("dir104", dir101_id), &local_id)); |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( |
| CreateDirectoryEntry("dir105", local_id), &local_id)); |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( |
| CreateDirectoryEntry("dir106", local_id), &local_id)); |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( |
| CreateDirectoryEntry("dir107", local_id), &local_id)); |
| |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetSubDirectoriesRecursively( |
| dir2_id, &sub_directories)); |
| EXPECT_EQ(8u, sub_directories.size()); |
| EXPECT_EQ(1u, sub_directories.count(base::FilePath::FromUTF8Unsafe( |
| "drive/root/dir2/dir101"))); |
| EXPECT_EQ(1u, sub_directories.count(base::FilePath::FromUTF8Unsafe( |
| "drive/root/dir2/dir101/dir104"))); |
| EXPECT_EQ(1u, sub_directories.count(base::FilePath::FromUTF8Unsafe( |
| "drive/root/dir2/dir101/dir104/dir105/dir106/dir107"))); |
| } |
| |
| TEST_F(ResourceMetadataTest, AddEntry) { |
| // Add a file to dir3. |
| std::string local_id; |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath( |
| base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3"), &local_id)); |
| ResourceEntry file_entry = CreateFileEntry("file100", local_id); |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(file_entry, &local_id)); |
| base::FilePath path; |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetFilePath(local_id, &path)); |
| EXPECT_EQ("drive/root/dir1/dir3/file100", path.AsUTF8Unsafe()); |
| |
| // Add a directory. |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath( |
| base::FilePath::FromUTF8Unsafe("drive/root/dir1"), &local_id)); |
| ResourceEntry dir_entry = CreateDirectoryEntry("dir101", local_id); |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(dir_entry, &local_id)); |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetFilePath(local_id, &path)); |
| EXPECT_EQ("drive/root/dir1/dir101", path.AsUTF8Unsafe()); |
| |
| // Add to an invalid parent. |
| ResourceEntry file_entry3 = CreateFileEntry("file103", "id:invalid"); |
| EXPECT_EQ(FILE_ERROR_NOT_FOUND, |
| resource_metadata_->AddEntry(file_entry3, &local_id)); |
| |
| // Add an existing file. |
| EXPECT_EQ(FILE_ERROR_EXISTS, |
| resource_metadata_->AddEntry(file_entry, &local_id)); |
| } |
| |
| TEST_F(ResourceMetadataTest, RemoveEntry) { |
| // Make sure file9 is found. |
| std::string file9_local_id; |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath( |
| base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3/file9"), |
| &file9_local_id)); |
| ResourceEntry entry; |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById( |
| file9_local_id, &entry)); |
| EXPECT_EQ("file9", entry.base_name()); |
| |
| // Remove file9. |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->RemoveEntry(file9_local_id)); |
| |
| // file9 should no longer exist. |
| EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->GetResourceEntryById( |
| file9_local_id, &entry)); |
| |
| // Look for dir3. |
| std::string dir3_local_id; |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath( |
| base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3"), &dir3_local_id)); |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById( |
| dir3_local_id, &entry)); |
| EXPECT_EQ("dir3", entry.base_name()); |
| |
| // Remove dir3. |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->RemoveEntry(dir3_local_id)); |
| |
| // dir3 should no longer exist. |
| EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->GetResourceEntryById( |
| dir3_local_id, &entry)); |
| |
| // Remove unknown local_id using RemoveEntry. |
| EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->RemoveEntry("foo")); |
| |
| // Try removing root. This should fail. |
| EXPECT_EQ(FILE_ERROR_ACCESS_DENIED, resource_metadata_->RemoveEntry( |
| util::kDriveGrandRootLocalId)); |
| } |
| |
| TEST_F(ResourceMetadataTest, GetResourceEntryById_RootDirectory) { |
| // Look up the root directory by its ID. |
| ResourceEntry entry; |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById( |
| util::kDriveGrandRootLocalId, &entry)); |
| EXPECT_EQ("drive", entry.base_name()); |
| } |
| |
| TEST_F(ResourceMetadataTest, GetResourceEntryById) { |
| // Get file4 by path. |
| std::string local_id; |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath( |
| base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"), &local_id)); |
| |
| // Confirm that an existing file is found. |
| ResourceEntry entry; |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById( |
| local_id, &entry)); |
| EXPECT_EQ("file4", entry.base_name()); |
| |
| // Confirm that a non existing file is not found. |
| EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->GetResourceEntryById( |
| "non_existing", &entry)); |
| } |
| |
| TEST_F(ResourceMetadataTest, Iterate) { |
| std::unique_ptr<ResourceMetadata::Iterator> it = |
| resource_metadata_->GetIterator(); |
| ASSERT_TRUE(it); |
| |
| int file_count = 0, directory_count = 0; |
| for (; !it->IsAtEnd(); it->Advance()) { |
| if (!it->GetValue().file_info().is_directory()) |
| ++file_count; |
| else |
| ++directory_count; |
| } |
| |
| EXPECT_EQ(7, file_count); |
| EXPECT_EQ(7, directory_count); |
| } |
| |
| TEST_F(ResourceMetadataTest, DuplicatedNames) { |
| std::string root_local_id; |
| ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath( |
| base::FilePath::FromUTF8Unsafe("drive/root"), &root_local_id)); |
| |
| ResourceEntry entry; |
| |
| // When multiple entries with the same title are added in a single directory, |
| // their base_names are de-duped. |
| // - drive/root/foo |
| // - drive/root/foo (1) |
| std::string dir_id_0; |
| ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( |
| CreateDirectoryEntryWithResourceId( |
| "foo", "foo0", root_local_id), &dir_id_0)); |
| std::string dir_id_1; |
| ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( |
| CreateDirectoryEntryWithResourceId( |
| "foo", "foo1", root_local_id), &dir_id_1)); |
| |
| ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById( |
| dir_id_0, &entry)); |
| EXPECT_EQ("foo", entry.base_name()); |
| ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById( |
| dir_id_1, &entry)); |
| EXPECT_EQ("foo (1)", entry.base_name()); |
| |
| // - drive/root/foo/bar.txt |
| // - drive/root/foo/bar (1).txt |
| // - drive/root/foo/bar (2).txt |
| // ... |
| // - drive/root/foo/bar (99).txt |
| std::vector<std::string> file_ids(100); |
| for (size_t i = 0; i < file_ids.size(); ++i) { |
| ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( |
| CreateFileEntryWithResourceId( |
| "bar.txt", base::StringPrintf("bar%d", static_cast<int>(i)), |
| dir_id_0), &file_ids[i])); |
| } |
| |
| ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById( |
| file_ids[0], &entry)); |
| EXPECT_EQ("bar.txt", entry.base_name()); |
| for (size_t i = 1; i < file_ids.size(); ++i) { |
| ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById( |
| file_ids[i], &entry)) << i; |
| EXPECT_EQ(base::StringPrintf("bar (%d).txt", static_cast<int>(i)), |
| entry.base_name()); |
| } |
| |
| // Same name but different parent. No renaming. |
| // - drive/root/foo (1)/bar.txt |
| std::string file_id_3; |
| ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( |
| CreateFileEntryWithResourceId( |
| "bar.txt", "bar_different_parent", dir_id_1), &file_id_3)); |
| |
| ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById( |
| file_id_3, &entry)); |
| EXPECT_EQ("bar.txt", entry.base_name()); |
| |
| // Checks that the entries can be looked up by the de-duped paths. |
| ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath( |
| base::FilePath::FromUTF8Unsafe("drive/root/foo/bar (2).txt"), &entry)); |
| EXPECT_EQ("bar2", entry.resource_id()); |
| ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath( |
| base::FilePath::FromUTF8Unsafe("drive/root/foo (1)/bar.txt"), &entry)); |
| EXPECT_EQ("bar_different_parent", entry.resource_id()); |
| } |
| |
| TEST_F(ResourceMetadataTest, EncodedNames) { |
| std::string root_local_id; |
| ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath( |
| base::FilePath::FromUTF8Unsafe("drive/root"), &root_local_id)); |
| |
| ResourceEntry entry; |
| |
| std::string dir_id; |
| ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( |
| CreateDirectoryEntry("\\(^o^)/", root_local_id), &dir_id)); |
| ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById( |
| dir_id, &entry)); |
| EXPECT_EQ("\\(^o^)_", entry.base_name()); |
| |
| std::string file_id; |
| ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry( |
| CreateFileEntryWithResourceId("Slash /.txt", "myfile", dir_id), |
| &file_id)); |
| ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById( |
| file_id, &entry)); |
| EXPECT_EQ("Slash _.txt", entry.base_name()); |
| |
| ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath( |
| base::FilePath::FromUTF8Unsafe( |
| "drive/root/\\(^o^)_/Slash _.txt"), |
| &entry)); |
| EXPECT_EQ("myfile", entry.resource_id()); |
| } |
| |
| TEST_F(ResourceMetadataTest, Reset) { |
| // The grand root has "root" which is not empty. |
| std::vector<ResourceEntry> entries; |
| ASSERT_EQ(FILE_ERROR_OK, |
| resource_metadata_->ReadDirectoryByPath( |
| base::FilePath::FromUTF8Unsafe("drive/root"), &entries)); |
| ASSERT_FALSE(entries.empty()); |
| |
| // Reset. |
| EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->Reset()); |
| |
| // change stamp should be reset. |
| int64_t changestamp = 0; |
| EXPECT_EQ(FILE_ERROR_OK, |
| resource_metadata_->GetLargestChangestamp(&changestamp)); |
| EXPECT_EQ(0, changestamp); |
| |
| // root should continue to exist. |
| ResourceEntry entry; |
| ASSERT_EQ(FILE_ERROR_OK, |
| resource_metadata_->GetResourceEntryByPath( |
| base::FilePath::FromUTF8Unsafe("drive"), &entry)); |
| EXPECT_EQ("drive", entry.base_name()); |
| ASSERT_TRUE(entry.file_info().is_directory()); |
| EXPECT_EQ(util::kDriveGrandRootLocalId, entry.local_id()); |
| |
| // There are "other", "trash" and "root" under "drive". |
| ASSERT_EQ(FILE_ERROR_OK, |
| resource_metadata_->ReadDirectoryByPath( |
| base::FilePath::FromUTF8Unsafe("drive"), &entries)); |
| EXPECT_EQ(3U, entries.size()); |
| |
| // The "other" directory should be empty. |
| ASSERT_EQ(FILE_ERROR_OK, |
| resource_metadata_->ReadDirectoryByPath( |
| base::FilePath::FromUTF8Unsafe("drive/other"), &entries)); |
| EXPECT_TRUE(entries.empty()); |
| |
| // The "trash" directory should be empty. |
| ASSERT_EQ(FILE_ERROR_OK, |
| resource_metadata_->ReadDirectoryByPath( |
| base::FilePath::FromUTF8Unsafe("drive/trash"), &entries)); |
| EXPECT_TRUE(entries.empty()); |
| } |
| |
| } // namespace internal |
| } // namespace drive |