Home | History | Annotate | Download | only in drive
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/chromeos/drive/resource_metadata_storage.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "base/file_util.h"
     10 #include "base/files/scoped_temp_dir.h"
     11 #include "chrome/browser/chromeos/drive/drive.pb.h"
     12 #include "chrome/browser/chromeos/drive/test_util.h"
     13 #include "content/public/test/test_browser_thread_bundle.h"
     14 #include "testing/gtest/include/gtest/gtest.h"
     15 #include "third_party/leveldatabase/src/include/leveldb/db.h"
     16 
     17 namespace drive {
     18 namespace internal {
     19 
     20 class ResourceMetadataStorageTest : public testing::Test {
     21  protected:
     22   virtual void SetUp() OVERRIDE {
     23     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     24 
     25     storage_.reset(new ResourceMetadataStorage(
     26         temp_dir_.path(), base::MessageLoopProxy::current().get()));
     27     ASSERT_TRUE(storage_->Initialize());
     28   }
     29 
     30   // Overwrites |storage_|'s version.
     31   void SetDBVersion(int version) {
     32     ResourceMetadataHeader header;
     33     ASSERT_TRUE(storage_->GetHeader(&header));
     34     header.set_version(version);
     35     EXPECT_TRUE(storage_->PutHeader(header));
     36   }
     37 
     38   bool CheckValidity() {
     39     return storage_->CheckValidity();
     40   }
     41 
     42   // Puts a child entry.
     43   void PutChild(const std::string& parent_resource_id,
     44                 const std::string& child_base_name,
     45                 const std::string& child_resource_id) {
     46     storage_->resource_map_->Put(
     47         leveldb::WriteOptions(),
     48         ResourceMetadataStorage::GetChildEntryKey(parent_resource_id,
     49                                                   child_base_name),
     50         child_resource_id);
     51   }
     52 
     53   // Removes a child entry.
     54   void RemoveChild(const std::string& parent_resource_id,
     55                    const std::string& child_base_name) {
     56     storage_->resource_map_->Delete(
     57         leveldb::WriteOptions(),
     58         ResourceMetadataStorage::GetChildEntryKey(parent_resource_id,
     59                                                   child_base_name));
     60   }
     61 
     62   content::TestBrowserThreadBundle thread_bundle_;
     63   base::ScopedTempDir temp_dir_;
     64   scoped_ptr<ResourceMetadataStorage,
     65              test_util::DestroyHelperForTests> storage_;
     66 };
     67 
     68 TEST_F(ResourceMetadataStorageTest, LargestChangestamp) {
     69   const int64 kLargestChangestamp = 1234567890;
     70   EXPECT_TRUE(storage_->SetLargestChangestamp(kLargestChangestamp));
     71   EXPECT_EQ(kLargestChangestamp, storage_->GetLargestChangestamp());
     72 }
     73 
     74 TEST_F(ResourceMetadataStorageTest, PutEntry) {
     75   const std::string key1 = "abcdefg";
     76   const std::string key2 = "abcd";
     77   const std::string key3 = "efgh";
     78   const std::string name2 = "ABCD";
     79   const std::string name3 = "EFGH";
     80 
     81   ResourceEntry entry1;
     82   entry1.set_resource_id(key1);
     83 
     84   // key1 not found.
     85   ResourceEntry result;
     86   EXPECT_FALSE(storage_->GetEntry(key1, &result));
     87 
     88   // Put entry1.
     89   EXPECT_TRUE(storage_->PutEntry(entry1));
     90 
     91   // key1 found.
     92   ASSERT_TRUE(storage_->GetEntry(key1, &result));
     93   EXPECT_EQ(key1, result.resource_id());
     94 
     95   // key2 not found.
     96   EXPECT_FALSE(storage_->GetEntry(key2, &result));
     97 
     98   // Put entry2 as a child of entry1.
     99   ResourceEntry entry2;
    100   entry2.set_parent_resource_id(key1);
    101   entry2.set_resource_id(key2);
    102   entry2.set_base_name(name2);
    103   EXPECT_TRUE(storage_->PutEntry(entry2));
    104 
    105   // key2 found.
    106   EXPECT_TRUE(storage_->GetEntry(key2, &result));
    107   EXPECT_EQ(key2, storage_->GetChild(key1, name2));
    108 
    109   // Put entry3 as a child of entry2.
    110   ResourceEntry entry3;
    111   entry3.set_parent_resource_id(key2);
    112   entry3.set_resource_id(key3);
    113   entry3.set_base_name(name3);
    114   EXPECT_TRUE(storage_->PutEntry(entry3));
    115 
    116   // key3 found.
    117   EXPECT_TRUE(storage_->GetEntry(key3, &result));
    118   EXPECT_EQ(key3, storage_->GetChild(key2, name3));
    119 
    120   // Change entry3's parent to entry1.
    121   entry3.set_parent_resource_id(key1);
    122   EXPECT_TRUE(storage_->PutEntry(entry3));
    123 
    124   // entry3 is a child of entry1 now.
    125   EXPECT_TRUE(storage_->GetChild(key2, name3).empty());
    126   EXPECT_EQ(key3, storage_->GetChild(key1, name3));
    127 
    128   // Remove entries.
    129   EXPECT_TRUE(storage_->RemoveEntry(key3));
    130   EXPECT_FALSE(storage_->GetEntry(key3, &result));
    131   EXPECT_TRUE(storage_->RemoveEntry(key2));
    132   EXPECT_FALSE(storage_->GetEntry(key2, &result));
    133   EXPECT_TRUE(storage_->RemoveEntry(key1));
    134   EXPECT_FALSE(storage_->GetEntry(key1, &result));
    135 }
    136 
    137 TEST_F(ResourceMetadataStorageTest, Iterator) {
    138   // Prepare data.
    139   std::vector<ResourceEntry> entries;
    140   ResourceEntry entry;
    141 
    142   entry.set_resource_id("entry1");
    143   entries.push_back(entry);
    144   entry.set_resource_id("entry2");
    145   entries.push_back(entry);
    146   entry.set_resource_id("entry3");
    147   entries.push_back(entry);
    148   entry.set_resource_id("entry4");
    149   entries.push_back(entry);
    150 
    151   for (size_t i = 0; i < entries.size(); ++i)
    152     EXPECT_TRUE(storage_->PutEntry(entries[i]));
    153 
    154   // Insert some cache entries.
    155   std::map<std::string, FileCacheEntry> cache_entries;
    156   cache_entries[entries[0].resource_id()].set_md5("aaaaaa");
    157   cache_entries[entries[1].resource_id()].set_md5("bbbbbb");
    158   for (std::map<std::string, FileCacheEntry>::iterator it =
    159            cache_entries.begin(); it != cache_entries.end(); ++it)
    160     EXPECT_TRUE(storage_->PutCacheEntry(it->first, it->second));
    161 
    162   // Iterate and check the result.
    163   std::map<std::string, ResourceEntry> found_entries;
    164   std::map<std::string, FileCacheEntry> found_cache_entries;
    165   scoped_ptr<ResourceMetadataStorage::Iterator> it = storage_->GetIterator();
    166   ASSERT_TRUE(it);
    167   for (; !it->IsAtEnd(); it->Advance()) {
    168     const ResourceEntry& entry = it->Get();
    169     found_entries[entry.resource_id()] = entry;
    170 
    171     FileCacheEntry cache_entry;
    172     if (it->GetCacheEntry(&cache_entry))
    173       found_cache_entries[entry.resource_id()] = cache_entry;
    174   }
    175   EXPECT_FALSE(it->HasError());
    176 
    177   EXPECT_EQ(entries.size(), found_entries.size());
    178   for (size_t i = 0; i < entries.size(); ++i)
    179     EXPECT_EQ(1U, found_entries.count(entries[i].resource_id()));
    180 
    181   EXPECT_EQ(cache_entries.size(), found_cache_entries.size());
    182   for (std::map<std::string, FileCacheEntry>::iterator it =
    183            cache_entries.begin(); it != cache_entries.end(); ++it) {
    184     ASSERT_EQ(1U, found_cache_entries.count(it->first));
    185     EXPECT_EQ(it->second.md5(), found_cache_entries[it->first].md5());
    186   }
    187 }
    188 
    189 TEST_F(ResourceMetadataStorageTest, PutCacheEntry) {
    190   FileCacheEntry entry;
    191   const std::string key1 = "abcdefg";
    192   const std::string key2 = "abcd";
    193   const std::string md5_1 = "foo";
    194   const std::string md5_2 = "bar";
    195 
    196   // Put cache entries.
    197   entry.set_md5(md5_1);
    198   EXPECT_TRUE(storage_->PutCacheEntry(key1, entry));
    199   entry.set_md5(md5_2);
    200   EXPECT_TRUE(storage_->PutCacheEntry(key2, entry));
    201 
    202   // Get cache entires.
    203   EXPECT_TRUE(storage_->GetCacheEntry(key1, &entry));
    204   EXPECT_EQ(md5_1, entry.md5());
    205   EXPECT_TRUE(storage_->GetCacheEntry(key2, &entry));
    206   EXPECT_EQ(md5_2, entry.md5());
    207 
    208   // Remove cache entries.
    209   EXPECT_TRUE(storage_->RemoveCacheEntry(key1));
    210   EXPECT_FALSE(storage_->GetCacheEntry(key1, &entry));
    211 
    212   EXPECT_TRUE(storage_->RemoveCacheEntry(key2));
    213   EXPECT_FALSE(storage_->GetCacheEntry(key2, &entry));
    214 }
    215 
    216 TEST_F(ResourceMetadataStorageTest, CacheEntryIterator) {
    217   // Prepare data.
    218   std::map<std::string, FileCacheEntry> entries;
    219   FileCacheEntry cache_entry;
    220 
    221   cache_entry.set_md5("aA");
    222   entries["entry1"] = cache_entry;
    223   cache_entry.set_md5("bB");
    224   entries["entry2"] = cache_entry;
    225   cache_entry.set_md5("cC");
    226   entries["entry3"] = cache_entry;
    227   cache_entry.set_md5("dD");
    228   entries["entry4"] = cache_entry;
    229 
    230   for (std::map<std::string, FileCacheEntry>::iterator it = entries.begin();
    231        it != entries.end(); ++it)
    232     EXPECT_TRUE(storage_->PutCacheEntry(it->first, it->second));
    233 
    234   // Insert some dummy entries.
    235   ResourceEntry entry;
    236   entry.set_resource_id("entry1");
    237   EXPECT_TRUE(storage_->PutEntry(entry));
    238   entry.set_resource_id("entry2");
    239   EXPECT_TRUE(storage_->PutEntry(entry));
    240 
    241   // Iterate and check the result.
    242   scoped_ptr<ResourceMetadataStorage::CacheEntryIterator> it =
    243       storage_->GetCacheEntryIterator();
    244   ASSERT_TRUE(it);
    245   size_t num_entries = 0;
    246   for (; !it->IsAtEnd(); it->Advance()) {
    247     EXPECT_EQ(1U, entries.count(it->GetID()));
    248     EXPECT_EQ(entries[it->GetID()].md5(), it->GetValue().md5());
    249     ++num_entries;
    250   }
    251   EXPECT_FALSE(it->HasError());
    252   EXPECT_EQ(entries.size(), num_entries);
    253 }
    254 
    255 TEST_F(ResourceMetadataStorageTest, GetChildren) {
    256   const std::string parents_id[] = { "mercury", "venus", "mars", "jupiter",
    257                                      "saturn" };
    258   std::vector<std::vector<std::pair<std::string, std::string> > >
    259       children_name_id(arraysize(parents_id));
    260   // Skip children_name_id[0/1] here because Mercury and Venus have no moon.
    261   children_name_id[2].push_back(std::make_pair("phobos", "mars_i"));
    262   children_name_id[2].push_back(std::make_pair("deimos", "mars_ii"));
    263   children_name_id[3].push_back(std::make_pair("io", "jupiter_i"));
    264   children_name_id[3].push_back(std::make_pair("europa", "jupiter_ii"));
    265   children_name_id[3].push_back(std::make_pair("ganymede", "jupiter_iii"));
    266   children_name_id[3].push_back(std::make_pair("calisto", "jupiter_iv"));
    267   children_name_id[4].push_back(std::make_pair("mimas", "saturn_i"));
    268   children_name_id[4].push_back(std::make_pair("enceladus", "saturn_ii"));
    269   children_name_id[4].push_back(std::make_pair("tethys", "saturn_iii"));
    270   children_name_id[4].push_back(std::make_pair("dione", "saturn_iv"));
    271   children_name_id[4].push_back(std::make_pair("rhea", "saturn_v"));
    272   children_name_id[4].push_back(std::make_pair("titan", "saturn_vi"));
    273   children_name_id[4].push_back(std::make_pair("iapetus", "saturn_vii"));
    274 
    275   // Put parents.
    276   for (size_t i = 0; i < arraysize(parents_id); ++i) {
    277     ResourceEntry entry;
    278     entry.set_resource_id(parents_id[i]);
    279     EXPECT_TRUE(storage_->PutEntry(entry));
    280   }
    281 
    282   // Put children.
    283   for (size_t i = 0; i < children_name_id.size(); ++i) {
    284     for (size_t j = 0; j < children_name_id[i].size(); ++j) {
    285       ResourceEntry entry;
    286       entry.set_parent_resource_id(parents_id[i]);
    287       entry.set_base_name(children_name_id[i][j].first);
    288       entry.set_resource_id(children_name_id[i][j].second);
    289       EXPECT_TRUE(storage_->PutEntry(entry));
    290     }
    291   }
    292 
    293   // Put some dummy cache entries.
    294   for (size_t i = 0; i < arraysize(parents_id); ++i) {
    295     FileCacheEntry cache_entry;
    296     EXPECT_TRUE(storage_->PutCacheEntry(parents_id[i], cache_entry));
    297   }
    298 
    299   // Try to get children.
    300   for (size_t i = 0; i < children_name_id.size(); ++i) {
    301     std::vector<std::string> children;
    302     storage_->GetChildren(parents_id[i], &children);
    303     EXPECT_EQ(children_name_id[i].size(), children.size());
    304     for (size_t j = 0; j < children_name_id[i].size(); ++j) {
    305       EXPECT_EQ(1, std::count(children.begin(),
    306                               children.end(),
    307                               children_name_id[i][j].second));
    308     }
    309   }
    310 }
    311 
    312 TEST_F(ResourceMetadataStorageTest, OpenExistingDB) {
    313   const std::string parent_id1 = "abcdefg";
    314   const std::string child_name1 = "WXYZABC";
    315   const std::string child_id1 = "qwerty";
    316 
    317   ResourceEntry entry1;
    318   entry1.set_resource_id(parent_id1);
    319   ResourceEntry entry2;
    320   entry2.set_resource_id(child_id1);
    321   entry2.set_parent_resource_id(parent_id1);
    322   entry2.set_base_name(child_name1);
    323 
    324   // Put some data.
    325   EXPECT_TRUE(storage_->PutEntry(entry1));
    326   EXPECT_TRUE(storage_->PutEntry(entry2));
    327 
    328   // Close DB and reopen.
    329   storage_.reset(new ResourceMetadataStorage(
    330       temp_dir_.path(), base::MessageLoopProxy::current().get()));
    331   ASSERT_TRUE(storage_->Initialize());
    332 
    333   // Can read data.
    334   ResourceEntry result;
    335   ASSERT_TRUE(storage_->GetEntry(parent_id1, &result));
    336   EXPECT_EQ(parent_id1, result.resource_id());
    337 
    338   ASSERT_TRUE(storage_->GetEntry(child_id1, &result));
    339   EXPECT_EQ(child_id1, result.resource_id());
    340   EXPECT_EQ(parent_id1, result.parent_resource_id());
    341   EXPECT_EQ(child_name1, result.base_name());
    342 
    343   EXPECT_EQ(child_id1, storage_->GetChild(parent_id1, child_name1));
    344 }
    345 
    346 TEST_F(ResourceMetadataStorageTest, IncompatibleDB) {
    347   const int64 kLargestChangestamp = 1234567890;
    348   const std::string key1 = "abcd";
    349 
    350   ResourceEntry entry;
    351   entry.set_resource_id(key1);
    352 
    353   // Put some data.
    354   ResourceEntry result;
    355   EXPECT_TRUE(storage_->SetLargestChangestamp(kLargestChangestamp));
    356   EXPECT_TRUE(storage_->PutEntry(entry));
    357   EXPECT_TRUE(storage_->GetEntry(key1, &result));
    358 
    359   // Set incompatible version and reopen DB.
    360   SetDBVersion(ResourceMetadataStorage::kDBVersion - 1);
    361   storage_.reset(new ResourceMetadataStorage(
    362       temp_dir_.path(), base::MessageLoopProxy::current().get()));
    363   ASSERT_TRUE(storage_->Initialize());
    364 
    365   // Data is erased because of the incompatible version.
    366   EXPECT_EQ(0, storage_->GetLargestChangestamp());
    367   EXPECT_FALSE(storage_->GetEntry(key1, &result));
    368 }
    369 
    370 TEST_F(ResourceMetadataStorageTest, WrongPath) {
    371   // Create a file.
    372   base::FilePath path;
    373   ASSERT_TRUE(file_util::CreateTemporaryFileInDir(temp_dir_.path(), &path));
    374 
    375   storage_.reset(new ResourceMetadataStorage(
    376       path, base::MessageLoopProxy::current().get()));
    377   // Cannot initialize DB beacause the path does not point a directory.
    378   ASSERT_FALSE(storage_->Initialize());
    379 }
    380 
    381 TEST_F(ResourceMetadataStorageTest, CheckValidity) {
    382   const std::string key1 = "foo";
    383   const std::string name1 = "hoge";
    384   const std::string key2 = "bar";
    385   const std::string name2 = "fuga";
    386   const std::string key3 = "boo";
    387   const std::string name3 = "piyo";
    388 
    389   // Empty storage is valid.
    390   EXPECT_TRUE(CheckValidity());
    391 
    392   // Put entry with key1.
    393   ResourceEntry entry;
    394   entry.set_resource_id(key1);
    395   entry.set_base_name(name1);
    396   EXPECT_TRUE(storage_->PutEntry(entry));
    397   EXPECT_TRUE(CheckValidity());
    398 
    399   // Put entry with key2 under key1.
    400   entry.set_resource_id(key2);
    401   entry.set_parent_resource_id(key1);
    402   entry.set_base_name(name2);
    403   EXPECT_TRUE(storage_->PutEntry(entry));
    404   EXPECT_TRUE(CheckValidity());
    405 
    406   RemoveChild(key1, name2);
    407   EXPECT_FALSE(CheckValidity());  // Missing parent-child relationship.
    408 
    409   // Add back parent-child relationship between key1 and key2.
    410   PutChild(key1, name2, key2);
    411   EXPECT_TRUE(CheckValidity());
    412 
    413   // Add parent-child relationship between key2 and key3.
    414   PutChild(key2, name3, key3);
    415   EXPECT_FALSE(CheckValidity());  // key3 is not stored in the storage.
    416 
    417   // Put entry with key3 under key2.
    418   entry.set_resource_id(key3);
    419   entry.set_parent_resource_id(key2);
    420   entry.set_base_name(name3);
    421   EXPECT_TRUE(storage_->PutEntry(entry));
    422   EXPECT_TRUE(CheckValidity());
    423 
    424   // Parent-child relationship with wrong name.
    425   RemoveChild(key2, name3);
    426   EXPECT_FALSE(CheckValidity());
    427   PutChild(key2, name2, key3);
    428   EXPECT_FALSE(CheckValidity());
    429 
    430   // Fix up the relationship between key2 and key3.
    431   RemoveChild(key2, name2);
    432   EXPECT_FALSE(CheckValidity());
    433   PutChild(key2, name3, key3);
    434   EXPECT_TRUE(CheckValidity());
    435 
    436   // Add some cache entries.
    437   FileCacheEntry cache_entry;
    438   EXPECT_TRUE(storage_->PutCacheEntry(key1, cache_entry));
    439   EXPECT_TRUE(storage_->PutCacheEntry(key2, cache_entry));
    440 
    441   // Remove key2.
    442   RemoveChild(key1, name2);
    443   EXPECT_FALSE(CheckValidity());
    444   EXPECT_TRUE(storage_->RemoveEntry(key2));
    445   EXPECT_FALSE(CheckValidity());
    446 
    447   // Remove key3.
    448   RemoveChild(key2, name3);
    449   EXPECT_FALSE(CheckValidity());
    450   EXPECT_TRUE(storage_->RemoveEntry(key3));
    451   EXPECT_TRUE(CheckValidity());
    452 
    453   // Remove key1.
    454   EXPECT_TRUE(storage_->RemoveEntry(key1));
    455   EXPECT_TRUE(CheckValidity());
    456 }
    457 
    458 }  // namespace internal
    459 }  // namespace drive
    460