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 "chrome/browser/drive/drive_api_util.h"
     14 #include "content/public/test/test_browser_thread_bundle.h"
     15 #include "testing/gtest/include/gtest/gtest.h"
     16 #include "third_party/leveldatabase/src/include/leveldb/db.h"
     17 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
     18 
     19 namespace drive {
     20 namespace internal {
     21 
     22 class ResourceMetadataStorageTest : public testing::Test {
     23  protected:
     24   virtual void SetUp() OVERRIDE {
     25     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     26 
     27     storage_.reset(new ResourceMetadataStorage(
     28         temp_dir_.path(), base::MessageLoopProxy::current().get()));
     29     ASSERT_TRUE(storage_->Initialize());
     30   }
     31 
     32   // Overwrites |storage_|'s version.
     33   void SetDBVersion(int version) {
     34     ResourceMetadataHeader header;
     35     ASSERT_TRUE(storage_->GetHeader(&header));
     36     header.set_version(version);
     37     EXPECT_TRUE(storage_->PutHeader(header));
     38   }
     39 
     40   bool CheckValidity() {
     41     return storage_->CheckValidity();
     42   }
     43 
     44   leveldb::DB* resource_map() { return storage_->resource_map_.get(); }
     45 
     46   // Puts a child entry.
     47   void PutChild(const std::string& parent_id,
     48                 const std::string& child_base_name,
     49                 const std::string& child_id) {
     50     storage_->resource_map_->Put(
     51         leveldb::WriteOptions(),
     52         ResourceMetadataStorage::GetChildEntryKey(parent_id, child_base_name),
     53         child_id);
     54   }
     55 
     56   // Removes a child entry.
     57   void RemoveChild(const std::string& parent_id,
     58                    const std::string& child_base_name) {
     59     storage_->resource_map_->Delete(
     60         leveldb::WriteOptions(),
     61         ResourceMetadataStorage::GetChildEntryKey(parent_id, child_base_name));
     62   }
     63 
     64   content::TestBrowserThreadBundle thread_bundle_;
     65   base::ScopedTempDir temp_dir_;
     66   scoped_ptr<ResourceMetadataStorage,
     67              test_util::DestroyHelperForTests> storage_;
     68 };
     69 
     70 TEST_F(ResourceMetadataStorageTest, LargestChangestamp) {
     71   const int64 kLargestChangestamp = 1234567890;
     72   EXPECT_TRUE(storage_->SetLargestChangestamp(kLargestChangestamp));
     73   EXPECT_EQ(kLargestChangestamp, storage_->GetLargestChangestamp());
     74 }
     75 
     76 TEST_F(ResourceMetadataStorageTest, PutEntry) {
     77   const std::string key1 = "abcdefg";
     78   const std::string key2 = "abcd";
     79   const std::string key3 = "efgh";
     80   const std::string name2 = "ABCD";
     81   const std::string name3 = "EFGH";
     82 
     83   // key1 not found.
     84   ResourceEntry result;
     85   EXPECT_FALSE(storage_->GetEntry(key1, &result));
     86 
     87   // Put entry1.
     88   ResourceEntry entry1;
     89   entry1.set_local_id(key1);
     90   EXPECT_TRUE(storage_->PutEntry(entry1));
     91 
     92   // key1 found.
     93   EXPECT_TRUE(storage_->GetEntry(key1, &result));
     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_local_id(key2);
    101   entry2.set_parent_local_id(key1);
    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_local_id(key3);
    112   entry3.set_parent_local_id(key2);
    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_local_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<std::string> keys;
    140 
    141   keys.push_back("entry1");
    142   keys.push_back("entry2");
    143   keys.push_back("entry3");
    144   keys.push_back("entry4");
    145 
    146   for (size_t i = 0; i < keys.size(); ++i) {
    147     ResourceEntry entry;
    148     entry.set_local_id(keys[i]);
    149     EXPECT_TRUE(storage_->PutEntry(entry));
    150   }
    151 
    152   // Insert some cache entries.
    153   std::map<std::string, FileCacheEntry> cache_entries;
    154   cache_entries[keys[0]].set_md5("aaaaaa");
    155   cache_entries[keys[1]].set_md5("bbbbbb");
    156   for (std::map<std::string, FileCacheEntry>::iterator it =
    157            cache_entries.begin(); it != cache_entries.end(); ++it)
    158     EXPECT_TRUE(storage_->PutCacheEntry(it->first, it->second));
    159 
    160   // Iterate and check the result.
    161   std::map<std::string, ResourceEntry> found_entries;
    162   std::map<std::string, FileCacheEntry> found_cache_entries;
    163   scoped_ptr<ResourceMetadataStorage::Iterator> it = storage_->GetIterator();
    164   ASSERT_TRUE(it);
    165   for (; !it->IsAtEnd(); it->Advance()) {
    166     const ResourceEntry& entry = it->GetValue();
    167     found_entries[it->GetID()] = entry;
    168 
    169     FileCacheEntry cache_entry;
    170     if (it->GetCacheEntry(&cache_entry))
    171       found_cache_entries[it->GetID()] = cache_entry;
    172   }
    173   EXPECT_FALSE(it->HasError());
    174 
    175   EXPECT_EQ(keys.size(), found_entries.size());
    176   for (size_t i = 0; i < keys.size(); ++i)
    177     EXPECT_EQ(1U, found_entries.count(keys[i]));
    178 
    179   EXPECT_EQ(cache_entries.size(), found_cache_entries.size());
    180   for (std::map<std::string, FileCacheEntry>::iterator it =
    181            cache_entries.begin(); it != cache_entries.end(); ++it) {
    182     ASSERT_EQ(1U, found_cache_entries.count(it->first));
    183     EXPECT_EQ(it->second.md5(), found_cache_entries[it->first].md5());
    184   }
    185 }
    186 
    187 TEST_F(ResourceMetadataStorageTest, PutCacheEntry) {
    188   FileCacheEntry entry;
    189   const std::string key1 = "abcdefg";
    190   const std::string key2 = "abcd";
    191   const std::string md5_1 = "foo";
    192   const std::string md5_2 = "bar";
    193 
    194   // Put cache entries.
    195   entry.set_md5(md5_1);
    196   EXPECT_TRUE(storage_->PutCacheEntry(key1, entry));
    197   entry.set_md5(md5_2);
    198   EXPECT_TRUE(storage_->PutCacheEntry(key2, entry));
    199 
    200   // Get cache entires.
    201   EXPECT_TRUE(storage_->GetCacheEntry(key1, &entry));
    202   EXPECT_EQ(md5_1, entry.md5());
    203   EXPECT_TRUE(storage_->GetCacheEntry(key2, &entry));
    204   EXPECT_EQ(md5_2, entry.md5());
    205 
    206   // Remove cache entries.
    207   EXPECT_TRUE(storage_->RemoveCacheEntry(key1));
    208   EXPECT_FALSE(storage_->GetCacheEntry(key1, &entry));
    209 
    210   EXPECT_TRUE(storage_->RemoveCacheEntry(key2));
    211   EXPECT_FALSE(storage_->GetCacheEntry(key2, &entry));
    212 }
    213 
    214 TEST_F(ResourceMetadataStorageTest, CacheEntryIterator) {
    215   // Prepare data.
    216   std::map<std::string, FileCacheEntry> entries;
    217   FileCacheEntry cache_entry;
    218 
    219   cache_entry.set_md5("aA");
    220   entries["entry1"] = cache_entry;
    221   cache_entry.set_md5("bB");
    222   entries["entry2"] = cache_entry;
    223   cache_entry.set_md5("cC");
    224   entries["entry3"] = cache_entry;
    225   cache_entry.set_md5("dD");
    226   entries["entry4"] = cache_entry;
    227 
    228   for (std::map<std::string, FileCacheEntry>::iterator it = entries.begin();
    229        it != entries.end(); ++it)
    230     EXPECT_TRUE(storage_->PutCacheEntry(it->first, it->second));
    231 
    232   // Insert some dummy entries.
    233   ResourceEntry entry;
    234   entry.set_local_id("entry1");
    235   EXPECT_TRUE(storage_->PutEntry(entry));
    236   entry.set_local_id("entry2");
    237   EXPECT_TRUE(storage_->PutEntry(entry));
    238 
    239   // Iterate and check the result.
    240   scoped_ptr<ResourceMetadataStorage::CacheEntryIterator> it =
    241       storage_->GetCacheEntryIterator();
    242   ASSERT_TRUE(it);
    243   size_t num_entries = 0;
    244   for (; !it->IsAtEnd(); it->Advance()) {
    245     EXPECT_EQ(1U, entries.count(it->GetID()));
    246     EXPECT_EQ(entries[it->GetID()].md5(), it->GetValue().md5());
    247     ++num_entries;
    248   }
    249   EXPECT_FALSE(it->HasError());
    250   EXPECT_EQ(entries.size(), num_entries);
    251 }
    252 
    253 TEST_F(ResourceMetadataStorageTest, GetIdByResourceId) {
    254   const std::string local_id = "local_id";
    255   const std::string resource_id = "resource_id";
    256 
    257   // Resource ID to local ID mapping is not stored yet.
    258   std::string id;
    259   EXPECT_FALSE(storage_->GetIdByResourceId(resource_id, &id));
    260 
    261   // Put an entry with the resource ID.
    262   ResourceEntry entry;
    263   entry.set_local_id(local_id);
    264   entry.set_resource_id(resource_id);
    265   EXPECT_TRUE(storage_->PutEntry(entry));
    266 
    267   // Can get local ID by resource ID.
    268   EXPECT_TRUE(storage_->GetIdByResourceId(resource_id, &id));
    269   EXPECT_EQ(local_id, id);
    270 
    271   // Resource ID to local ID mapping is removed.
    272   EXPECT_TRUE(storage_->RemoveEntry(local_id));
    273   EXPECT_FALSE(storage_->GetIdByResourceId(resource_id, &id));
    274 }
    275 
    276 TEST_F(ResourceMetadataStorageTest, GetChildren) {
    277   const std::string parents_id[] = { "mercury", "venus", "mars", "jupiter",
    278                                      "saturn" };
    279   std::vector<std::vector<std::pair<std::string, std::string> > >
    280       children_name_id(arraysize(parents_id));
    281   // Skip children_name_id[0/1] here because Mercury and Venus have no moon.
    282   children_name_id[2].push_back(std::make_pair("phobos", "mars_i"));
    283   children_name_id[2].push_back(std::make_pair("deimos", "mars_ii"));
    284   children_name_id[3].push_back(std::make_pair("io", "jupiter_i"));
    285   children_name_id[3].push_back(std::make_pair("europa", "jupiter_ii"));
    286   children_name_id[3].push_back(std::make_pair("ganymede", "jupiter_iii"));
    287   children_name_id[3].push_back(std::make_pair("calisto", "jupiter_iv"));
    288   children_name_id[4].push_back(std::make_pair("mimas", "saturn_i"));
    289   children_name_id[4].push_back(std::make_pair("enceladus", "saturn_ii"));
    290   children_name_id[4].push_back(std::make_pair("tethys", "saturn_iii"));
    291   children_name_id[4].push_back(std::make_pair("dione", "saturn_iv"));
    292   children_name_id[4].push_back(std::make_pair("rhea", "saturn_v"));
    293   children_name_id[4].push_back(std::make_pair("titan", "saturn_vi"));
    294   children_name_id[4].push_back(std::make_pair("iapetus", "saturn_vii"));
    295 
    296   // Put parents.
    297   for (size_t i = 0; i < arraysize(parents_id); ++i) {
    298     ResourceEntry entry;
    299     entry.set_local_id(parents_id[i]);
    300     EXPECT_TRUE(storage_->PutEntry(entry));
    301   }
    302 
    303   // Put children.
    304   for (size_t i = 0; i < children_name_id.size(); ++i) {
    305     for (size_t j = 0; j < children_name_id[i].size(); ++j) {
    306       ResourceEntry entry;
    307       entry.set_local_id(children_name_id[i][j].second);
    308       entry.set_parent_local_id(parents_id[i]);
    309       entry.set_base_name(children_name_id[i][j].first);
    310       EXPECT_TRUE(storage_->PutEntry(entry));
    311     }
    312   }
    313 
    314   // Put some dummy cache entries.
    315   for (size_t i = 0; i < arraysize(parents_id); ++i) {
    316     FileCacheEntry cache_entry;
    317     EXPECT_TRUE(storage_->PutCacheEntry(parents_id[i], cache_entry));
    318   }
    319 
    320   // Try to get children.
    321   for (size_t i = 0; i < children_name_id.size(); ++i) {
    322     std::vector<std::string> children;
    323     storage_->GetChildren(parents_id[i], &children);
    324     EXPECT_EQ(children_name_id[i].size(), children.size());
    325     for (size_t j = 0; j < children_name_id[i].size(); ++j) {
    326       EXPECT_EQ(1, std::count(children.begin(),
    327                               children.end(),
    328                               children_name_id[i][j].second));
    329     }
    330   }
    331 }
    332 
    333 TEST_F(ResourceMetadataStorageTest, OpenExistingDB) {
    334   const std::string parent_id1 = "abcdefg";
    335   const std::string child_name1 = "WXYZABC";
    336   const std::string child_id1 = "qwerty";
    337 
    338   ResourceEntry entry1;
    339   entry1.set_local_id(parent_id1);
    340   ResourceEntry entry2;
    341   entry2.set_local_id(child_id1);
    342   entry2.set_parent_local_id(parent_id1);
    343   entry2.set_base_name(child_name1);
    344 
    345   // Put some data.
    346   EXPECT_TRUE(storage_->PutEntry(entry1));
    347   EXPECT_TRUE(storage_->PutEntry(entry2));
    348 
    349   // Close DB and reopen.
    350   storage_.reset(new ResourceMetadataStorage(
    351       temp_dir_.path(), base::MessageLoopProxy::current().get()));
    352   ASSERT_TRUE(storage_->Initialize());
    353 
    354   // Can read data.
    355   ResourceEntry result;
    356   EXPECT_TRUE(storage_->GetEntry(parent_id1, &result));
    357 
    358   EXPECT_TRUE(storage_->GetEntry(child_id1, &result));
    359   EXPECT_EQ(parent_id1, result.parent_local_id());
    360   EXPECT_EQ(child_name1, result.base_name());
    361 
    362   EXPECT_EQ(child_id1, storage_->GetChild(parent_id1, child_name1));
    363 }
    364 
    365 TEST_F(ResourceMetadataStorageTest, IncompatibleDB_M29) {
    366   const int64 kLargestChangestamp = 1234567890;
    367 
    368   // Construct M29 version DB.
    369   SetDBVersion(6);
    370   EXPECT_TRUE(storage_->SetLargestChangestamp(kLargestChangestamp));
    371 
    372   leveldb::WriteBatch batch;
    373 
    374   // Put a file entry and its cache entry.
    375   ResourceEntry entry;
    376   std::string serialized_entry;
    377   entry.set_resource_id("file:abcd");
    378   EXPECT_TRUE(entry.SerializeToString(&serialized_entry));
    379   batch.Put("file:abcd", serialized_entry);
    380 
    381   FileCacheEntry cache_entry;
    382   EXPECT_TRUE(cache_entry.SerializeToString(&serialized_entry));
    383   batch.Put(std::string("file:abcd") + '\0' + "CACHE", serialized_entry);
    384 
    385   EXPECT_TRUE(resource_map()->Write(leveldb::WriteOptions(), &batch).ok());
    386 
    387   // Upgrade and reopen.
    388   storage_.reset();
    389   EXPECT_TRUE(ResourceMetadataStorage::UpgradeOldDB(
    390       temp_dir_.path(), base::Bind(&util::CanonicalizeResourceId)));
    391   storage_.reset(new ResourceMetadataStorage(
    392       temp_dir_.path(), base::MessageLoopProxy::current().get()));
    393   ASSERT_TRUE(storage_->Initialize());
    394 
    395   // Resource-ID-to-local-ID mapping is added.
    396   std::string id;
    397   EXPECT_TRUE(storage_->GetIdByResourceId("abcd", &id));  // "file:" is dropped.
    398 
    399   // Data is erased, except cache entries.
    400   EXPECT_EQ(0, storage_->GetLargestChangestamp());
    401   EXPECT_FALSE(storage_->GetEntry(id, &entry));
    402   EXPECT_TRUE(storage_->GetCacheEntry(id, &cache_entry));
    403 }
    404 
    405 TEST_F(ResourceMetadataStorageTest, IncompatibleDB_M32) {
    406   const int64 kLargestChangestamp = 1234567890;
    407   const std::string resource_id = "abcd";
    408   const std::string local_id = "local-abcd";
    409 
    410   // Construct M32 version DB.
    411   SetDBVersion(11);
    412   EXPECT_TRUE(storage_->SetLargestChangestamp(kLargestChangestamp));
    413 
    414   leveldb::WriteBatch batch;
    415 
    416   // Put a file entry and its cache and id entry.
    417   ResourceEntry entry;
    418   std::string serialized_entry;
    419   entry.set_resource_id(resource_id);
    420   EXPECT_TRUE(entry.SerializeToString(&serialized_entry));
    421   batch.Put(local_id, serialized_entry);
    422 
    423   FileCacheEntry cache_entry;
    424   EXPECT_TRUE(cache_entry.SerializeToString(&serialized_entry));
    425   batch.Put(local_id + '\0' + "CACHE", serialized_entry);
    426 
    427   batch.Put('\0' + std::string("ID") + '\0' + resource_id, local_id);
    428 
    429   EXPECT_TRUE(resource_map()->Write(leveldb::WriteOptions(), &batch).ok());
    430 
    431   // Upgrade and reopen.
    432   storage_.reset();
    433   EXPECT_TRUE(ResourceMetadataStorage::UpgradeOldDB(
    434       temp_dir_.path(), base::Bind(&util::CanonicalizeResourceId)));
    435   storage_.reset(new ResourceMetadataStorage(
    436       temp_dir_.path(), base::MessageLoopProxy::current().get()));
    437   ASSERT_TRUE(storage_->Initialize());
    438 
    439   // Data is erased, except cache and id mapping entries.
    440   std::string id;
    441   EXPECT_TRUE(storage_->GetIdByResourceId(resource_id, &id));
    442   EXPECT_EQ(local_id, id);
    443   EXPECT_EQ(0, storage_->GetLargestChangestamp());
    444   EXPECT_FALSE(storage_->GetEntry(id, &entry));
    445   EXPECT_TRUE(storage_->GetCacheEntry(id, &cache_entry));
    446 }
    447 
    448 TEST_F(ResourceMetadataStorageTest, IncompatibleDB_Unknown) {
    449   const int64 kLargestChangestamp = 1234567890;
    450   const std::string key1 = "abcd";
    451 
    452   // Put some data.
    453   EXPECT_TRUE(storage_->SetLargestChangestamp(kLargestChangestamp));
    454   ResourceEntry entry;
    455   entry.set_local_id(key1);
    456   EXPECT_TRUE(storage_->PutEntry(entry));
    457   FileCacheEntry cache_entry;
    458   EXPECT_TRUE(storage_->PutCacheEntry(key1, cache_entry));
    459 
    460   // Set newer version, upgrade and reopen DB.
    461   SetDBVersion(ResourceMetadataStorage::kDBVersion + 1);
    462   storage_.reset();
    463   EXPECT_FALSE(ResourceMetadataStorage::UpgradeOldDB(
    464       temp_dir_.path(), base::Bind(&util::CanonicalizeResourceId)));
    465   storage_.reset(new ResourceMetadataStorage(
    466       temp_dir_.path(), base::MessageLoopProxy::current().get()));
    467   ASSERT_TRUE(storage_->Initialize());
    468 
    469   // Data is erased because of the incompatible version.
    470   EXPECT_EQ(0, storage_->GetLargestChangestamp());
    471   EXPECT_FALSE(storage_->GetEntry(key1, &entry));
    472   EXPECT_FALSE(storage_->GetCacheEntry(key1, &cache_entry));
    473 }
    474 
    475 TEST_F(ResourceMetadataStorageTest, WrongPath) {
    476   // Create a file.
    477   base::FilePath path;
    478   ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(), &path));
    479 
    480   storage_.reset(new ResourceMetadataStorage(
    481       path, base::MessageLoopProxy::current().get()));
    482   // Cannot initialize DB beacause the path does not point a directory.
    483   ASSERT_FALSE(storage_->Initialize());
    484 }
    485 
    486 TEST_F(ResourceMetadataStorageTest, RecoverCacheEntriesFromTrashedResourceMap) {
    487   // Put some cache entries.
    488   FileCacheEntry cache_entry;
    489   cache_entry.set_md5("md5_foo");
    490   EXPECT_TRUE(storage_->PutCacheEntry("id_foo", cache_entry));
    491   cache_entry.set_md5("md5_bar");
    492   cache_entry.set_is_dirty(true);
    493   EXPECT_TRUE(storage_->PutCacheEntry("id_bar", cache_entry));
    494 
    495   // Put entry with id_foo.
    496   ResourceEntry entry;
    497   entry.set_local_id("id_foo");
    498   entry.set_base_name("foo");
    499   entry.set_title("foo");
    500   EXPECT_TRUE(storage_->PutEntry(entry));
    501 
    502   // Put entry with id_bar as a id_foo's child.
    503   entry.set_local_id("id_bar");
    504   entry.set_parent_local_id("id_foo");
    505   entry.set_base_name("bar");
    506   entry.set_title("bar");
    507   EXPECT_TRUE(storage_->PutEntry(entry));
    508 
    509   // Remove parent-child relationship to make the DB invalid.
    510   RemoveChild("id_foo", "bar");
    511   EXPECT_FALSE(CheckValidity());
    512 
    513   // Reopen. This should result in trashing the DB.
    514   storage_.reset(new ResourceMetadataStorage(
    515       temp_dir_.path(), base::MessageLoopProxy::current().get()));
    516   ASSERT_TRUE(storage_->Initialize());
    517 
    518   // Recover cache entries from the trashed DB.
    519   ResourceMetadataStorage::RecoveredCacheInfoMap recovered_cache_info;
    520   storage_->RecoverCacheInfoFromTrashedResourceMap(&recovered_cache_info);
    521   EXPECT_EQ(2U, recovered_cache_info.size());
    522   EXPECT_FALSE(recovered_cache_info["id_foo"].is_dirty);
    523   EXPECT_EQ("md5_foo", recovered_cache_info["id_foo"].md5);
    524   EXPECT_EQ("foo", recovered_cache_info["id_foo"].title);
    525   EXPECT_TRUE(recovered_cache_info["id_bar"].is_dirty);
    526   EXPECT_EQ("md5_bar", recovered_cache_info["id_bar"].md5);
    527   EXPECT_EQ("bar", recovered_cache_info["id_bar"].title);
    528 }
    529 
    530 TEST_F(ResourceMetadataStorageTest, CheckValidity) {
    531   const std::string key1 = "foo";
    532   const std::string name1 = "hoge";
    533   const std::string key2 = "bar";
    534   const std::string name2 = "fuga";
    535   const std::string key3 = "boo";
    536   const std::string name3 = "piyo";
    537 
    538   // Empty storage is valid.
    539   EXPECT_TRUE(CheckValidity());
    540 
    541   // Put entry with key1.
    542   ResourceEntry entry;
    543   entry.set_local_id(key1);
    544   entry.set_base_name(name1);
    545   EXPECT_TRUE(storage_->PutEntry(entry));
    546   EXPECT_TRUE(CheckValidity());
    547 
    548   // Put entry with key2 under key1.
    549   entry.set_local_id(key2);
    550   entry.set_parent_local_id(key1);
    551   entry.set_base_name(name2);
    552   EXPECT_TRUE(storage_->PutEntry(entry));
    553   EXPECT_TRUE(CheckValidity());
    554 
    555   RemoveChild(key1, name2);
    556   EXPECT_FALSE(CheckValidity());  // Missing parent-child relationship.
    557 
    558   // Add back parent-child relationship between key1 and key2.
    559   PutChild(key1, name2, key2);
    560   EXPECT_TRUE(CheckValidity());
    561 
    562   // Add parent-child relationship between key2 and key3.
    563   PutChild(key2, name3, key3);
    564   EXPECT_FALSE(CheckValidity());  // key3 is not stored in the storage.
    565 
    566   // Put entry with key3 under key2.
    567   entry.set_local_id(key3);
    568   entry.set_parent_local_id(key2);
    569   entry.set_base_name(name3);
    570   EXPECT_TRUE(storage_->PutEntry(entry));
    571   EXPECT_TRUE(CheckValidity());
    572 
    573   // Parent-child relationship with wrong name.
    574   RemoveChild(key2, name3);
    575   EXPECT_FALSE(CheckValidity());
    576   PutChild(key2, name2, key3);
    577   EXPECT_FALSE(CheckValidity());
    578 
    579   // Fix up the relationship between key2 and key3.
    580   RemoveChild(key2, name2);
    581   EXPECT_FALSE(CheckValidity());
    582   PutChild(key2, name3, key3);
    583   EXPECT_TRUE(CheckValidity());
    584 
    585   // Add some cache entries.
    586   FileCacheEntry cache_entry;
    587   EXPECT_TRUE(storage_->PutCacheEntry(key1, cache_entry));
    588   EXPECT_TRUE(storage_->PutCacheEntry(key2, cache_entry));
    589 
    590   // Remove key2.
    591   RemoveChild(key1, name2);
    592   EXPECT_FALSE(CheckValidity());
    593   EXPECT_TRUE(storage_->RemoveEntry(key2));
    594   EXPECT_FALSE(CheckValidity());
    595 
    596   // Remove key3.
    597   RemoveChild(key2, name3);
    598   EXPECT_FALSE(CheckValidity());
    599   EXPECT_TRUE(storage_->RemoveEntry(key3));
    600   EXPECT_TRUE(CheckValidity());
    601 
    602   // Remove key1.
    603   EXPECT_TRUE(storage_->RemoveEntry(key1));
    604   EXPECT_TRUE(CheckValidity());
    605 }
    606 
    607 }  // namespace internal
    608 }  // namespace drive
    609