Home | History | Annotate | Download | only in drive
      1 // Copyright (c) 2012 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/resource_metadata.h"
      6 
      7 #include <algorithm>
      8 #include <string>
      9 #include <vector>
     10 
     11 #include "base/files/scoped_temp_dir.h"
     12 #include "base/strings/stringprintf.h"
     13 #include "chrome/browser/chromeos/drive/drive.pb.h"
     14 #include "chrome/browser/chromeos/drive/fake_free_disk_space_getter.h"
     15 #include "chrome/browser/chromeos/drive/file_cache.h"
     16 #include "chrome/browser/chromeos/drive/file_system_util.h"
     17 #include "chrome/browser/chromeos/drive/test_util.h"
     18 #include "content/public/test/test_browser_thread_bundle.h"
     19 #include "testing/gtest/include/gtest/gtest.h"
     20 
     21 namespace drive {
     22 namespace internal {
     23 namespace {
     24 
     25 // The changestamp of the resource metadata used in
     26 // ResourceMetadataTest.
     27 const int64 kTestChangestamp = 100;
     28 
     29 // Returns the sorted base names from |entries|.
     30 std::vector<std::string> GetSortedBaseNames(
     31     const ResourceEntryVector& entries) {
     32   std::vector<std::string> base_names;
     33   for (size_t i = 0; i < entries.size(); ++i)
     34     base_names.push_back(entries[i].base_name());
     35   std::sort(base_names.begin(), base_names.end());
     36 
     37   return base_names;
     38 }
     39 
     40 // Creates a ResourceEntry for a directory with explicitly set resource_id.
     41 ResourceEntry CreateDirectoryEntryWithResourceId(
     42     const std::string& title,
     43     const std::string& resource_id,
     44     const std::string& parent_local_id) {
     45   ResourceEntry entry;
     46   entry.set_title(title);
     47   entry.set_resource_id(resource_id);
     48   entry.set_parent_local_id(parent_local_id);
     49   entry.mutable_file_info()->set_is_directory(true);
     50   entry.mutable_directory_specific_info()->set_changestamp(kTestChangestamp);
     51   return entry;
     52 }
     53 
     54 // Creates a ResourceEntry for a directory.
     55 ResourceEntry CreateDirectoryEntry(const std::string& title,
     56                                    const std::string& parent_local_id) {
     57   return CreateDirectoryEntryWithResourceId(
     58       title, "id:" + title, parent_local_id);
     59 }
     60 
     61 // Creates a ResourceEntry for a file with explicitly set resource_id.
     62 ResourceEntry CreateFileEntryWithResourceId(
     63     const std::string& title,
     64     const std::string& resource_id,
     65     const std::string& parent_local_id) {
     66   ResourceEntry entry;
     67   entry.set_title(title);
     68   entry.set_resource_id(resource_id);
     69   entry.set_parent_local_id(parent_local_id);
     70   entry.mutable_file_info()->set_is_directory(false);
     71   entry.mutable_file_info()->set_size(1024);
     72   entry.mutable_file_specific_info()->set_md5("md5:" + title);
     73   return entry;
     74 }
     75 
     76 // Creates a ResourceEntry for a file.
     77 ResourceEntry CreateFileEntry(const std::string& title,
     78                               const std::string& parent_local_id) {
     79   return CreateFileEntryWithResourceId(title, "id:" + title, parent_local_id);
     80 }
     81 
     82 // Creates the following files/directories
     83 // drive/root/dir1/
     84 // drive/root/dir2/
     85 // drive/root/dir1/dir3/
     86 // drive/root/dir1/file4
     87 // drive/root/dir1/file5
     88 // drive/root/dir2/file6
     89 // drive/root/dir2/file7
     90 // drive/root/dir2/file8
     91 // drive/root/dir1/dir3/file9
     92 // drive/root/dir1/dir3/file10
     93 void SetUpEntries(ResourceMetadata* resource_metadata) {
     94   std::string local_id;
     95   ASSERT_EQ(FILE_ERROR_OK, resource_metadata->GetIdByPath(
     96       util::GetDriveMyDriveRootPath(), &local_id));
     97   const std::string root_local_id = local_id;
     98 
     99   ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(
    100       CreateDirectoryEntry("dir1", root_local_id), &local_id));
    101   const std::string local_id_dir1 = local_id;
    102 
    103   ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(
    104       CreateDirectoryEntry("dir2", root_local_id), &local_id));
    105   const std::string local_id_dir2 = local_id;
    106 
    107   ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(
    108       CreateDirectoryEntry("dir3", local_id_dir1), &local_id));
    109   const std::string local_id_dir3 = local_id;
    110 
    111   ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(
    112       CreateFileEntry("file4", local_id_dir1), &local_id));
    113   ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(
    114       CreateFileEntry("file5", local_id_dir1), &local_id));
    115 
    116   ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(
    117       CreateFileEntry("file6", local_id_dir2), &local_id));
    118   ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(
    119       CreateFileEntry("file7", local_id_dir2), &local_id));
    120   ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(
    121       CreateFileEntry("file8", local_id_dir2), &local_id));
    122 
    123   ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(
    124       CreateFileEntry("file9", local_id_dir3), &local_id));
    125   ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(
    126       CreateFileEntry("file10", local_id_dir3), &local_id));
    127 
    128   ASSERT_EQ(FILE_ERROR_OK,
    129             resource_metadata->SetLargestChangestamp(kTestChangestamp));
    130 }
    131 
    132 }  // namespace
    133 
    134 // Tests for methods running on the blocking task runner.
    135 class ResourceMetadataTest : public testing::Test {
    136  protected:
    137   virtual void SetUp() OVERRIDE {
    138     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
    139 
    140     metadata_storage_.reset(new ResourceMetadataStorage(
    141         temp_dir_.path(), base::MessageLoopProxy::current().get()));
    142     ASSERT_TRUE(metadata_storage_->Initialize());
    143 
    144     fake_free_disk_space_getter_.reset(new FakeFreeDiskSpaceGetter);
    145     cache_.reset(new FileCache(metadata_storage_.get(),
    146                                temp_dir_.path(),
    147                                base::MessageLoopProxy::current().get(),
    148                                fake_free_disk_space_getter_.get()));
    149     ASSERT_TRUE(cache_->Initialize());
    150 
    151     resource_metadata_.reset(new ResourceMetadata(
    152         metadata_storage_.get(), cache_.get(),
    153         base::MessageLoopProxy::current()));
    154 
    155     ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->Initialize());
    156 
    157     SetUpEntries(resource_metadata_.get());
    158   }
    159 
    160   base::ScopedTempDir temp_dir_;
    161   content::TestBrowserThreadBundle thread_bundle_;
    162   scoped_ptr<ResourceMetadataStorage, test_util::DestroyHelperForTests>
    163       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>
    167       resource_metadata_;
    168 };
    169 
    170 TEST_F(ResourceMetadataTest, LargestChangestamp) {
    171   const int64 kChangestamp = 123456;
    172   EXPECT_EQ(FILE_ERROR_OK,
    173             resource_metadata_->SetLargestChangestamp(kChangestamp));
    174   int64 changestamp = 0;
    175   EXPECT_EQ(FILE_ERROR_OK,
    176             resource_metadata_->GetLargestChangestamp(&changestamp));
    177   EXPECT_EQ(kChangestamp, changestamp);
    178 }
    179 
    180 TEST_F(ResourceMetadataTest, GetResourceEntryByPath) {
    181   // Confirm that an existing file is found.
    182   ResourceEntry entry;
    183   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath(
    184       base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"), &entry));
    185   EXPECT_EQ("file4", entry.base_name());
    186 
    187   // Confirm that a non existing file is not found.
    188   EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->GetResourceEntryByPath(
    189       base::FilePath::FromUTF8Unsafe("drive/root/dir1/non_existing"), &entry));
    190 
    191   // Confirm that the root is found.
    192   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath(
    193       base::FilePath::FromUTF8Unsafe("drive"), &entry));
    194 
    195   // Confirm that a non existing file is not found at the root level.
    196   EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->GetResourceEntryByPath(
    197       base::FilePath::FromUTF8Unsafe("non_existing"), &entry));
    198 
    199    // Confirm that an entry is not found with a wrong root.
    200   EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->GetResourceEntryByPath(
    201       base::FilePath::FromUTF8Unsafe("non_existing/root"), &entry));
    202 }
    203 
    204 TEST_F(ResourceMetadataTest, ReadDirectoryByPath) {
    205   // Confirm that an existing directory is found.
    206   ResourceEntryVector entries;
    207   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->ReadDirectoryByPath(
    208       base::FilePath::FromUTF8Unsafe("drive/root/dir1"), &entries));
    209   ASSERT_EQ(3U, entries.size());
    210   // The order is not guaranteed so we should sort the base names.
    211   std::vector<std::string> base_names = GetSortedBaseNames(entries);
    212   EXPECT_EQ("dir3", base_names[0]);
    213   EXPECT_EQ("file4", base_names[1]);
    214   EXPECT_EQ("file5", base_names[2]);
    215 
    216   // Confirm that a non existing directory is not found.
    217   EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->ReadDirectoryByPath(
    218       base::FilePath::FromUTF8Unsafe("drive/root/non_existing"), &entries));
    219 
    220   // Confirm that reading a file results in FILE_ERROR_NOT_A_DIRECTORY.
    221   EXPECT_EQ(FILE_ERROR_NOT_A_DIRECTORY, resource_metadata_->ReadDirectoryByPath(
    222       base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"), &entries));
    223 }
    224 
    225 TEST_F(ResourceMetadataTest, RefreshEntry) {
    226   base::FilePath drive_file_path;
    227   ResourceEntry entry;
    228 
    229   // Get file9.
    230   std::string file_id;
    231   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
    232       base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3/file9"), &file_id));
    233   EXPECT_EQ(FILE_ERROR_OK,
    234             resource_metadata_->GetResourceEntryById(file_id, &entry));
    235   EXPECT_EQ("file9", entry.base_name());
    236   EXPECT_TRUE(!entry.file_info().is_directory());
    237   EXPECT_EQ("md5:file9", entry.file_specific_info().md5());
    238 
    239   // Rename it.
    240   ResourceEntry file_entry(entry);
    241   file_entry.set_title("file100");
    242   EXPECT_EQ(FILE_ERROR_OK,
    243             resource_metadata_->RefreshEntry(file_entry));
    244 
    245   base::FilePath path;
    246   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetFilePath(file_id, &path));
    247   EXPECT_EQ("drive/root/dir1/dir3/file100", path.AsUTF8Unsafe());
    248   entry.Clear();
    249   EXPECT_EQ(FILE_ERROR_OK,
    250             resource_metadata_->GetResourceEntryById(file_id, &entry));
    251   EXPECT_EQ("file100", entry.base_name());
    252   EXPECT_TRUE(!entry.file_info().is_directory());
    253   EXPECT_EQ("md5:file9", entry.file_specific_info().md5());
    254 
    255   // Update the file md5.
    256   const std::string updated_md5("md5:updated");
    257   file_entry = entry;
    258   file_entry.mutable_file_specific_info()->set_md5(updated_md5);
    259   EXPECT_EQ(FILE_ERROR_OK,
    260             resource_metadata_->RefreshEntry(file_entry));
    261 
    262   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetFilePath(file_id, &path));
    263   EXPECT_EQ("drive/root/dir1/dir3/file100", path.AsUTF8Unsafe());
    264   entry.Clear();
    265   EXPECT_EQ(FILE_ERROR_OK,
    266             resource_metadata_->GetResourceEntryById(file_id, &entry));
    267   EXPECT_EQ("file100", entry.base_name());
    268   EXPECT_TRUE(!entry.file_info().is_directory());
    269   EXPECT_EQ(updated_md5, entry.file_specific_info().md5());
    270 
    271   // Make sure we get the same thing from GetResourceEntryByPath.
    272   entry.Clear();
    273   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath(
    274       base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3/file100"), &entry));
    275   EXPECT_EQ("file100", entry.base_name());
    276   ASSERT_TRUE(!entry.file_info().is_directory());
    277   EXPECT_EQ(updated_md5, entry.file_specific_info().md5());
    278 
    279   // Get dir2.
    280   entry.Clear();
    281   std::string dir_id;
    282   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
    283       base::FilePath::FromUTF8Unsafe("drive/root/dir2"), &dir_id));
    284   EXPECT_EQ(FILE_ERROR_OK,
    285             resource_metadata_->GetResourceEntryById(dir_id, &entry));
    286   EXPECT_EQ("dir2", entry.base_name());
    287   ASSERT_TRUE(entry.file_info().is_directory());
    288 
    289   // Get dir3's ID.
    290   std::string dir3_id;
    291   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
    292       base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3"), &dir3_id));
    293 
    294   // Change the name to dir100 and change the parent to drive/dir1/dir3.
    295   ResourceEntry dir_entry(entry);
    296   dir_entry.set_title("dir100");
    297   dir_entry.set_parent_local_id(dir3_id);
    298   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->RefreshEntry(dir_entry));
    299 
    300   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetFilePath(dir_id, &path));
    301   EXPECT_EQ("drive/root/dir1/dir3/dir100", path.AsUTF8Unsafe());
    302   entry.Clear();
    303   EXPECT_EQ(FILE_ERROR_OK,
    304             resource_metadata_->GetResourceEntryById(dir_id, &entry));
    305   EXPECT_EQ("dir100", entry.base_name());
    306   EXPECT_TRUE(entry.file_info().is_directory());
    307   EXPECT_EQ("id:dir2", entry.resource_id());
    308 
    309   // Make sure the children have moved over. Test file6.
    310   entry.Clear();
    311   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath(
    312       base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3/dir100/file6"),
    313       &entry));
    314   EXPECT_EQ("file6", entry.base_name());
    315 
    316   // Make sure dir2 no longer exists.
    317   EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->GetResourceEntryByPath(
    318       base::FilePath::FromUTF8Unsafe("drive/root/dir2"), &entry));
    319 
    320   // Make sure that directory cannot move under a file.
    321   dir_entry.set_parent_local_id(file_id);
    322   EXPECT_EQ(FILE_ERROR_NOT_A_DIRECTORY,
    323             resource_metadata_->RefreshEntry(dir_entry));
    324 
    325   // Cannot refresh root.
    326   dir_entry.Clear();
    327   dir_entry.set_local_id(util::kDriveGrandRootLocalId);
    328   dir_entry.set_title("new-root-name");
    329   dir_entry.set_parent_local_id(dir3_id);
    330   EXPECT_EQ(FILE_ERROR_INVALID_OPERATION,
    331             resource_metadata_->RefreshEntry(dir_entry));
    332 }
    333 
    334 TEST_F(ResourceMetadataTest, RefreshEntry_ResourceIDCheck) {
    335   // Get an entry with a non-empty resource ID.
    336   ResourceEntry entry;
    337   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath(
    338       base::FilePath::FromUTF8Unsafe("drive/root/dir1"), &entry));
    339   EXPECT_FALSE(entry.resource_id().empty());
    340 
    341   // Add a new entry with an empty resource ID.
    342   ResourceEntry new_entry;
    343   new_entry.set_parent_local_id(entry.local_id());
    344   new_entry.set_title("new entry");
    345   std::string local_id;
    346   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(new_entry, &local_id));
    347 
    348   // Try to refresh the new entry with a used resource ID.
    349   new_entry.set_local_id(local_id);
    350   new_entry.set_resource_id(entry.resource_id());
    351   EXPECT_EQ(FILE_ERROR_INVALID_OPERATION,
    352             resource_metadata_->RefreshEntry(new_entry));
    353 }
    354 
    355 TEST_F(ResourceMetadataTest, RefreshEntry_DoNotOverwriteCacheState) {
    356   ResourceEntry entry;
    357   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath(
    358       base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"), &entry));
    359 
    360   // Try to set MD5 with RefreshEntry.
    361   entry.mutable_file_specific_info()->mutable_cache_state()->set_md5("md5");
    362   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->RefreshEntry(entry));
    363 
    364   // Cache state is unchanged.
    365   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath(
    366       base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"), &entry));
    367   EXPECT_TRUE(entry.file_specific_info().cache_state().md5().empty());
    368 
    369   // Pin the file.
    370   EXPECT_EQ(FILE_ERROR_OK, cache_->Pin(entry.local_id()));
    371 
    372   // Try to clear the cache state with RefreshEntry.
    373   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath(
    374       base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"), &entry));
    375   entry.mutable_file_specific_info()->clear_cache_state();
    376   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->RefreshEntry(entry));
    377 
    378   // Cache state is not cleared.
    379   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath(
    380       base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"), &entry));
    381   EXPECT_TRUE(entry.file_specific_info().cache_state().is_pinned());
    382 }
    383 
    384 TEST_F(ResourceMetadataTest, GetSubDirectoriesRecursively) {
    385   std::set<base::FilePath> sub_directories;
    386 
    387   // file9: not a directory, so no children.
    388   std::string local_id;
    389   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
    390       base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3/file9"), &local_id));
    391   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetSubDirectoriesRecursively(
    392       local_id, &sub_directories));
    393   EXPECT_TRUE(sub_directories.empty());
    394 
    395   // dir2: no child directories.
    396   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
    397       base::FilePath::FromUTF8Unsafe("drive/root/dir2"), &local_id));
    398   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetSubDirectoriesRecursively(
    399       local_id, &sub_directories));
    400   EXPECT_TRUE(sub_directories.empty());
    401   const std::string dir2_id = local_id;
    402 
    403   // dir1: dir3 is the only child
    404   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
    405       base::FilePath::FromUTF8Unsafe("drive/root/dir1"), &local_id));
    406   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetSubDirectoriesRecursively(
    407       local_id, &sub_directories));
    408   EXPECT_EQ(1u, sub_directories.size());
    409   EXPECT_EQ(1u, sub_directories.count(
    410       base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3")));
    411   sub_directories.clear();
    412 
    413   // Add a few more directories to make sure deeper nesting works.
    414   // dir2/dir100
    415   // dir2/dir101
    416   // dir2/dir101/dir102
    417   // dir2/dir101/dir103
    418   // dir2/dir101/dir104
    419   // dir2/dir101/dir104/dir105
    420   // dir2/dir101/dir104/dir105/dir106
    421   // dir2/dir101/dir104/dir105/dir106/dir107
    422   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
    423       CreateDirectoryEntry("dir100", dir2_id), &local_id));
    424   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
    425       CreateDirectoryEntry("dir101", dir2_id), &local_id));
    426   const std::string dir101_id = local_id;
    427   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
    428       CreateDirectoryEntry("dir102", dir101_id), &local_id));
    429   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
    430       CreateDirectoryEntry("dir103", dir101_id), &local_id));
    431   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
    432       CreateDirectoryEntry("dir104", dir101_id), &local_id));
    433   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
    434       CreateDirectoryEntry("dir105", local_id), &local_id));
    435   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
    436       CreateDirectoryEntry("dir106", local_id), &local_id));
    437   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
    438       CreateDirectoryEntry("dir107", local_id), &local_id));
    439 
    440   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetSubDirectoriesRecursively(
    441       dir2_id, &sub_directories));
    442   EXPECT_EQ(8u, sub_directories.size());
    443   EXPECT_EQ(1u, sub_directories.count(base::FilePath::FromUTF8Unsafe(
    444       "drive/root/dir2/dir101")));
    445   EXPECT_EQ(1u, sub_directories.count(base::FilePath::FromUTF8Unsafe(
    446       "drive/root/dir2/dir101/dir104")));
    447   EXPECT_EQ(1u, sub_directories.count(base::FilePath::FromUTF8Unsafe(
    448       "drive/root/dir2/dir101/dir104/dir105/dir106/dir107")));
    449 }
    450 
    451 TEST_F(ResourceMetadataTest, AddEntry) {
    452   // Add a file to dir3.
    453   std::string local_id;
    454   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
    455       base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3"), &local_id));
    456   ResourceEntry file_entry = CreateFileEntry("file100", local_id);
    457   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(file_entry, &local_id));
    458   base::FilePath path;
    459   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetFilePath(local_id, &path));
    460   EXPECT_EQ("drive/root/dir1/dir3/file100", path.AsUTF8Unsafe());
    461 
    462   // Add a directory.
    463   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
    464       base::FilePath::FromUTF8Unsafe("drive/root/dir1"), &local_id));
    465   ResourceEntry dir_entry = CreateDirectoryEntry("dir101", local_id);
    466   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(dir_entry, &local_id));
    467   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetFilePath(local_id, &path));
    468   EXPECT_EQ("drive/root/dir1/dir101", path.AsUTF8Unsafe());
    469 
    470   // Add to an invalid parent.
    471   ResourceEntry file_entry3 = CreateFileEntry("file103", "id:invalid");
    472   EXPECT_EQ(FILE_ERROR_NOT_FOUND,
    473             resource_metadata_->AddEntry(file_entry3, &local_id));
    474 
    475   // Add an existing file.
    476   EXPECT_EQ(FILE_ERROR_EXISTS,
    477             resource_metadata_->AddEntry(file_entry, &local_id));
    478 }
    479 
    480 TEST_F(ResourceMetadataTest, RemoveEntry) {
    481   // Make sure file9 is found.
    482   std::string file9_local_id;
    483   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
    484       base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3/file9"),
    485       &file9_local_id));
    486   ResourceEntry entry;
    487   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
    488       file9_local_id, &entry));
    489   EXPECT_EQ("file9", entry.base_name());
    490 
    491   // Remove file9.
    492   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->RemoveEntry(file9_local_id));
    493 
    494   // file9 should no longer exist.
    495   EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->GetResourceEntryById(
    496       file9_local_id, &entry));
    497 
    498   // Look for dir3.
    499   std::string dir3_local_id;
    500   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
    501       base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3"), &dir3_local_id));
    502   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
    503       dir3_local_id, &entry));
    504   EXPECT_EQ("dir3", entry.base_name());
    505 
    506   // Remove dir3.
    507   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->RemoveEntry(dir3_local_id));
    508 
    509   // dir3 should no longer exist.
    510   EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->GetResourceEntryById(
    511       dir3_local_id, &entry));
    512 
    513   // Remove unknown local_id using RemoveEntry.
    514   EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->RemoveEntry("foo"));
    515 
    516   // Try removing root. This should fail.
    517   EXPECT_EQ(FILE_ERROR_ACCESS_DENIED, resource_metadata_->RemoveEntry(
    518       util::kDriveGrandRootLocalId));
    519 }
    520 
    521 TEST_F(ResourceMetadataTest, GetResourceEntryById_RootDirectory) {
    522   // Look up the root directory by its ID.
    523   ResourceEntry entry;
    524   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
    525       util::kDriveGrandRootLocalId, &entry));
    526   EXPECT_EQ("drive", entry.base_name());
    527 }
    528 
    529 TEST_F(ResourceMetadataTest, GetResourceEntryById) {
    530   // Get file4 by path.
    531   std::string local_id;
    532   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
    533       base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"), &local_id));
    534 
    535   // Confirm that an existing file is found.
    536   ResourceEntry entry;
    537   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
    538       local_id, &entry));
    539   EXPECT_EQ("file4", entry.base_name());
    540 
    541   // Confirm that a non existing file is not found.
    542   EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->GetResourceEntryById(
    543       "file:non_existing", &entry));
    544 }
    545 
    546 TEST_F(ResourceMetadataTest, Iterate) {
    547   scoped_ptr<ResourceMetadata::Iterator> it = resource_metadata_->GetIterator();
    548   ASSERT_TRUE(it);
    549 
    550   int file_count = 0, directory_count = 0;
    551   for (; !it->IsAtEnd(); it->Advance()) {
    552     if (!it->GetValue().file_info().is_directory())
    553       ++file_count;
    554     else
    555       ++directory_count;
    556   }
    557 
    558   EXPECT_EQ(7, file_count);
    559   EXPECT_EQ(7, directory_count);
    560 }
    561 
    562 TEST_F(ResourceMetadataTest, DuplicatedNames) {
    563   std::string root_local_id;
    564   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
    565       base::FilePath::FromUTF8Unsafe("drive/root"), &root_local_id));
    566 
    567   ResourceEntry entry;
    568 
    569   // When multiple entries with the same title are added in a single directory,
    570   // their base_names are de-duped.
    571   // - drive/root/foo
    572   // - drive/root/foo (1)
    573   std::string dir_id_0;
    574   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
    575       CreateDirectoryEntryWithResourceId(
    576           "foo", "foo0", root_local_id), &dir_id_0));
    577   std::string dir_id_1;
    578   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
    579       CreateDirectoryEntryWithResourceId(
    580           "foo", "foo1", root_local_id), &dir_id_1));
    581 
    582   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
    583       dir_id_0, &entry));
    584   EXPECT_EQ("foo", entry.base_name());
    585   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
    586       dir_id_1, &entry));
    587   EXPECT_EQ("foo (1)", entry.base_name());
    588 
    589   // - drive/root/foo/bar.txt
    590   // - drive/root/foo/bar (1).txt
    591   // - drive/root/foo/bar (2).txt
    592   // ...
    593   // - drive/root/foo/bar (99).txt
    594   std::vector<std::string> file_ids(100);
    595   for (size_t i = 0; i < file_ids.size(); ++i) {
    596     ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
    597         CreateFileEntryWithResourceId(
    598             "bar.txt", base::StringPrintf("bar%d", static_cast<int>(i)),
    599             dir_id_0), &file_ids[i]));
    600   }
    601 
    602   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
    603       file_ids[0], &entry));
    604   EXPECT_EQ("bar.txt", entry.base_name());
    605   for (size_t i = 1; i < file_ids.size(); ++i) {
    606     ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
    607         file_ids[i], &entry)) << i;
    608     EXPECT_EQ(base::StringPrintf("bar (%d).txt", static_cast<int>(i)),
    609               entry.base_name());
    610   }
    611 
    612   // Same name but different parent. No renaming.
    613   // - drive/root/foo (1)/bar.txt
    614   std::string file_id_3;
    615   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
    616       CreateFileEntryWithResourceId(
    617           "bar.txt", "bar_different_parent", dir_id_1), &file_id_3));
    618 
    619   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
    620       file_id_3, &entry));
    621   EXPECT_EQ("bar.txt", entry.base_name());
    622 
    623   // Checks that the entries can be looked up by the de-duped paths.
    624   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath(
    625       base::FilePath::FromUTF8Unsafe("drive/root/foo/bar (2).txt"), &entry));
    626   EXPECT_EQ("bar2", entry.resource_id());
    627   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath(
    628       base::FilePath::FromUTF8Unsafe("drive/root/foo (1)/bar.txt"), &entry));
    629   EXPECT_EQ("bar_different_parent", entry.resource_id());
    630 }
    631 
    632 TEST_F(ResourceMetadataTest, EncodedNames) {
    633   std::string root_local_id;
    634   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
    635       base::FilePath::FromUTF8Unsafe("drive/root"), &root_local_id));
    636 
    637   ResourceEntry entry;
    638 
    639   std::string dir_id;
    640   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
    641       CreateDirectoryEntry("\\(^o^)/", root_local_id), &dir_id));
    642   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
    643       dir_id, &entry));
    644   EXPECT_EQ("\\(^o^)_", entry.base_name());
    645 
    646   std::string file_id;
    647   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
    648       CreateFileEntryWithResourceId("Slash /.txt", "myfile", dir_id),
    649       &file_id));
    650   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
    651       file_id, &entry));
    652   EXPECT_EQ("Slash _.txt", entry.base_name());
    653 
    654   ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath(
    655       base::FilePath::FromUTF8Unsafe(
    656           "drive/root/\\(^o^)_/Slash _.txt"),
    657       &entry));
    658   EXPECT_EQ("myfile", entry.resource_id());
    659 }
    660 
    661 TEST_F(ResourceMetadataTest, Reset) {
    662   // The grand root has "root" which is not empty.
    663   std::vector<ResourceEntry> entries;
    664   ASSERT_EQ(FILE_ERROR_OK,
    665             resource_metadata_->ReadDirectoryByPath(
    666                 base::FilePath::FromUTF8Unsafe("drive/root"), &entries));
    667   ASSERT_FALSE(entries.empty());
    668 
    669   // Reset.
    670   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->Reset());
    671 
    672   // change stamp should be reset.
    673   int64 changestamp = 0;
    674   EXPECT_EQ(FILE_ERROR_OK,
    675             resource_metadata_->GetLargestChangestamp(&changestamp));
    676   EXPECT_EQ(0, changestamp);
    677 
    678   // root should continue to exist.
    679   ResourceEntry entry;
    680   ASSERT_EQ(FILE_ERROR_OK,
    681             resource_metadata_->GetResourceEntryByPath(
    682                 base::FilePath::FromUTF8Unsafe("drive"), &entry));
    683   EXPECT_EQ("drive", entry.base_name());
    684   ASSERT_TRUE(entry.file_info().is_directory());
    685   EXPECT_EQ(util::kDriveGrandRootLocalId, entry.local_id());
    686 
    687   // There are "other", "trash" and "root" under "drive".
    688   ASSERT_EQ(FILE_ERROR_OK,
    689             resource_metadata_->ReadDirectoryByPath(
    690                 base::FilePath::FromUTF8Unsafe("drive"), &entries));
    691   EXPECT_EQ(3U, entries.size());
    692 
    693   // The "other" directory should be empty.
    694   ASSERT_EQ(FILE_ERROR_OK,
    695             resource_metadata_->ReadDirectoryByPath(
    696                 base::FilePath::FromUTF8Unsafe("drive/other"), &entries));
    697   EXPECT_TRUE(entries.empty());
    698 
    699   // The "trash" directory should be empty.
    700   ASSERT_EQ(FILE_ERROR_OK,
    701             resource_metadata_->ReadDirectoryByPath(
    702                 base::FilePath::FromUTF8Unsafe("drive/trash"), &entries));
    703   EXPECT_TRUE(entries.empty());
    704 }
    705 
    706 }  // namespace internal
    707 }  // namespace drive
    708