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