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/files/file_util.h" 10 #include "base/files/scoped_temp_dir.h" 11 #include "base/strings/string_split.h" 12 #include "chrome/browser/chromeos/drive/drive.pb.h" 13 #include "chrome/browser/chromeos/drive/test_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_EQ(FILE_ERROR_OK, storage_->GetHeader(&header)); 36 header.set_version(version); 37 EXPECT_EQ(FILE_ERROR_OK, 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_EQ(FILE_ERROR_OK, 73 storage_->SetLargestChangestamp(kLargestChangestamp)); 74 int64 value = 0; 75 EXPECT_EQ(FILE_ERROR_OK, storage_->GetLargestChangestamp(&value)); 76 EXPECT_EQ(kLargestChangestamp, value); 77 } 78 79 TEST_F(ResourceMetadataStorageTest, PutEntry) { 80 const std::string key1 = "abcdefg"; 81 const std::string key2 = "abcd"; 82 const std::string key3 = "efgh"; 83 const std::string name2 = "ABCD"; 84 const std::string name3 = "EFGH"; 85 86 // key1 not found. 87 ResourceEntry result; 88 EXPECT_EQ(FILE_ERROR_NOT_FOUND, storage_->GetEntry(key1, &result)); 89 90 // Put entry1. 91 ResourceEntry entry1; 92 entry1.set_local_id(key1); 93 EXPECT_EQ(FILE_ERROR_OK, storage_->PutEntry(entry1)); 94 95 // key1 found. 96 EXPECT_EQ(FILE_ERROR_OK, storage_->GetEntry(key1, &result)); 97 98 // key2 not found. 99 EXPECT_EQ(FILE_ERROR_NOT_FOUND, storage_->GetEntry(key2, &result)); 100 101 // Put entry2 as a child of entry1. 102 ResourceEntry entry2; 103 entry2.set_local_id(key2); 104 entry2.set_parent_local_id(key1); 105 entry2.set_base_name(name2); 106 EXPECT_EQ(FILE_ERROR_OK, storage_->PutEntry(entry2)); 107 108 // key2 found. 109 std::string child_id; 110 EXPECT_EQ(FILE_ERROR_OK, storage_->GetEntry(key2, &result)); 111 EXPECT_EQ(FILE_ERROR_OK, storage_->GetChild(key1, name2, &child_id)); 112 EXPECT_EQ(key2, child_id); 113 114 // Put entry3 as a child of entry2. 115 ResourceEntry entry3; 116 entry3.set_local_id(key3); 117 entry3.set_parent_local_id(key2); 118 entry3.set_base_name(name3); 119 EXPECT_EQ(FILE_ERROR_OK, storage_->PutEntry(entry3)); 120 121 // key3 found. 122 EXPECT_EQ(FILE_ERROR_OK, storage_->GetEntry(key3, &result)); 123 EXPECT_EQ(FILE_ERROR_OK, storage_->GetChild(key2, name3, &child_id)); 124 EXPECT_EQ(key3, child_id); 125 126 // Change entry3's parent to entry1. 127 entry3.set_parent_local_id(key1); 128 EXPECT_EQ(FILE_ERROR_OK, storage_->PutEntry(entry3)); 129 130 // entry3 is a child of entry1 now. 131 EXPECT_EQ(FILE_ERROR_NOT_FOUND, storage_->GetChild(key2, name3, &child_id)); 132 EXPECT_EQ(FILE_ERROR_OK, storage_->GetChild(key1, name3, &child_id)); 133 EXPECT_EQ(key3, child_id); 134 135 // Remove entries. 136 EXPECT_EQ(FILE_ERROR_OK, storage_->RemoveEntry(key3)); 137 EXPECT_EQ(FILE_ERROR_NOT_FOUND, storage_->GetEntry(key3, &result)); 138 EXPECT_EQ(FILE_ERROR_OK, storage_->RemoveEntry(key2)); 139 EXPECT_EQ(FILE_ERROR_NOT_FOUND, storage_->GetEntry(key2, &result)); 140 EXPECT_EQ(FILE_ERROR_OK, storage_->RemoveEntry(key1)); 141 EXPECT_EQ(FILE_ERROR_NOT_FOUND, storage_->GetEntry(key1, &result)); 142 } 143 144 TEST_F(ResourceMetadataStorageTest, Iterator) { 145 // Prepare data. 146 std::vector<std::string> keys; 147 148 keys.push_back("entry1"); 149 keys.push_back("entry2"); 150 keys.push_back("entry3"); 151 keys.push_back("entry4"); 152 153 for (size_t i = 0; i < keys.size(); ++i) { 154 ResourceEntry entry; 155 entry.set_local_id(keys[i]); 156 EXPECT_EQ(FILE_ERROR_OK, storage_->PutEntry(entry)); 157 } 158 159 // Iterate and check the result. 160 std::map<std::string, ResourceEntry> found_entries; 161 scoped_ptr<ResourceMetadataStorage::Iterator> it = storage_->GetIterator(); 162 ASSERT_TRUE(it); 163 for (; !it->IsAtEnd(); it->Advance()) { 164 const ResourceEntry& entry = it->GetValue(); 165 found_entries[it->GetID()] = entry; 166 } 167 EXPECT_FALSE(it->HasError()); 168 169 EXPECT_EQ(keys.size(), found_entries.size()); 170 for (size_t i = 0; i < keys.size(); ++i) 171 EXPECT_EQ(1U, found_entries.count(keys[i])); 172 } 173 174 TEST_F(ResourceMetadataStorageTest, GetIdByResourceId) { 175 const std::string local_id = "local_id"; 176 const std::string resource_id = "resource_id"; 177 178 // Resource ID to local ID mapping is not stored yet. 179 std::string id; 180 EXPECT_EQ(FILE_ERROR_NOT_FOUND, 181 storage_->GetIdByResourceId(resource_id, &id)); 182 183 // Put an entry with the resource ID. 184 ResourceEntry entry; 185 entry.set_local_id(local_id); 186 entry.set_resource_id(resource_id); 187 EXPECT_EQ(FILE_ERROR_OK, storage_->PutEntry(entry)); 188 189 // Can get local ID by resource ID. 190 EXPECT_EQ(FILE_ERROR_OK, storage_->GetIdByResourceId(resource_id, &id)); 191 EXPECT_EQ(local_id, id); 192 193 // Resource ID to local ID mapping is removed. 194 EXPECT_EQ(FILE_ERROR_OK, storage_->RemoveEntry(local_id)); 195 EXPECT_EQ(FILE_ERROR_NOT_FOUND, 196 storage_->GetIdByResourceId(resource_id, &id)); 197 } 198 199 TEST_F(ResourceMetadataStorageTest, GetChildren) { 200 const std::string parents_id[] = { "mercury", "venus", "mars", "jupiter", 201 "saturn" }; 202 std::vector<base::StringPairs> children_name_id(arraysize(parents_id)); 203 // Skip children_name_id[0/1] here because Mercury and Venus have no moon. 204 children_name_id[2].push_back(std::make_pair("phobos", "mars_i")); 205 children_name_id[2].push_back(std::make_pair("deimos", "mars_ii")); 206 children_name_id[3].push_back(std::make_pair("io", "jupiter_i")); 207 children_name_id[3].push_back(std::make_pair("europa", "jupiter_ii")); 208 children_name_id[3].push_back(std::make_pair("ganymede", "jupiter_iii")); 209 children_name_id[3].push_back(std::make_pair("calisto", "jupiter_iv")); 210 children_name_id[4].push_back(std::make_pair("mimas", "saturn_i")); 211 children_name_id[4].push_back(std::make_pair("enceladus", "saturn_ii")); 212 children_name_id[4].push_back(std::make_pair("tethys", "saturn_iii")); 213 children_name_id[4].push_back(std::make_pair("dione", "saturn_iv")); 214 children_name_id[4].push_back(std::make_pair("rhea", "saturn_v")); 215 children_name_id[4].push_back(std::make_pair("titan", "saturn_vi")); 216 children_name_id[4].push_back(std::make_pair("iapetus", "saturn_vii")); 217 218 // Put parents. 219 for (size_t i = 0; i < arraysize(parents_id); ++i) { 220 ResourceEntry entry; 221 entry.set_local_id(parents_id[i]); 222 EXPECT_EQ(FILE_ERROR_OK, storage_->PutEntry(entry)); 223 } 224 225 // Put children. 226 for (size_t i = 0; i < children_name_id.size(); ++i) { 227 for (size_t j = 0; j < children_name_id[i].size(); ++j) { 228 ResourceEntry entry; 229 entry.set_local_id(children_name_id[i][j].second); 230 entry.set_parent_local_id(parents_id[i]); 231 entry.set_base_name(children_name_id[i][j].first); 232 EXPECT_EQ(FILE_ERROR_OK, storage_->PutEntry(entry)); 233 } 234 } 235 236 // Try to get children. 237 for (size_t i = 0; i < children_name_id.size(); ++i) { 238 std::vector<std::string> children; 239 storage_->GetChildren(parents_id[i], &children); 240 EXPECT_EQ(children_name_id[i].size(), children.size()); 241 for (size_t j = 0; j < children_name_id[i].size(); ++j) { 242 EXPECT_EQ(1, std::count(children.begin(), 243 children.end(), 244 children_name_id[i][j].second)); 245 } 246 } 247 } 248 249 TEST_F(ResourceMetadataStorageTest, OpenExistingDB) { 250 const std::string parent_id1 = "abcdefg"; 251 const std::string child_name1 = "WXYZABC"; 252 const std::string child_id1 = "qwerty"; 253 254 ResourceEntry entry1; 255 entry1.set_local_id(parent_id1); 256 ResourceEntry entry2; 257 entry2.set_local_id(child_id1); 258 entry2.set_parent_local_id(parent_id1); 259 entry2.set_base_name(child_name1); 260 261 // Put some data. 262 EXPECT_EQ(FILE_ERROR_OK, storage_->PutEntry(entry1)); 263 EXPECT_EQ(FILE_ERROR_OK, storage_->PutEntry(entry2)); 264 265 // Close DB and reopen. 266 storage_.reset(new ResourceMetadataStorage( 267 temp_dir_.path(), base::MessageLoopProxy::current().get())); 268 ASSERT_TRUE(storage_->Initialize()); 269 270 // Can read data. 271 ResourceEntry result; 272 EXPECT_EQ(FILE_ERROR_OK, storage_->GetEntry(parent_id1, &result)); 273 274 EXPECT_EQ(FILE_ERROR_OK, storage_->GetEntry(child_id1, &result)); 275 EXPECT_EQ(parent_id1, result.parent_local_id()); 276 EXPECT_EQ(child_name1, result.base_name()); 277 278 std::string child_id; 279 EXPECT_EQ(FILE_ERROR_OK, 280 storage_->GetChild(parent_id1, child_name1, &child_id)); 281 EXPECT_EQ(child_id1, child_id); 282 } 283 284 TEST_F(ResourceMetadataStorageTest, IncompatibleDB_M29) { 285 const int64 kLargestChangestamp = 1234567890; 286 const std::string title = "title"; 287 288 // Construct M29 version DB. 289 SetDBVersion(6); 290 EXPECT_EQ(FILE_ERROR_OK, 291 storage_->SetLargestChangestamp(kLargestChangestamp)); 292 293 leveldb::WriteBatch batch; 294 295 // Put a file entry and its cache entry. 296 ResourceEntry entry; 297 std::string serialized_entry; 298 entry.set_title(title); 299 entry.set_resource_id("file:abcd"); 300 EXPECT_TRUE(entry.SerializeToString(&serialized_entry)); 301 batch.Put("file:abcd", serialized_entry); 302 303 FileCacheEntry cache_entry; 304 EXPECT_TRUE(cache_entry.SerializeToString(&serialized_entry)); 305 batch.Put(std::string("file:abcd") + '\0' + "CACHE", serialized_entry); 306 307 EXPECT_TRUE(resource_map()->Write(leveldb::WriteOptions(), &batch).ok()); 308 309 // Upgrade and reopen. 310 storage_.reset(); 311 EXPECT_TRUE(ResourceMetadataStorage::UpgradeOldDB(temp_dir_.path())); 312 storage_.reset(new ResourceMetadataStorage( 313 temp_dir_.path(), base::MessageLoopProxy::current().get())); 314 ASSERT_TRUE(storage_->Initialize()); 315 316 // Resource-ID-to-local-ID mapping is added. 317 std::string id; 318 EXPECT_EQ(FILE_ERROR_OK, 319 storage_->GetIdByResourceId("abcd", &id)); // "file:" is dropped. 320 321 // Data is erased, except cache entries. 322 int64 largest_changestamp = 0; 323 EXPECT_EQ(FILE_ERROR_OK, 324 storage_->GetLargestChangestamp(&largest_changestamp)); 325 EXPECT_EQ(0, largest_changestamp); 326 EXPECT_EQ(FILE_ERROR_OK, storage_->GetEntry(id, &entry)); 327 EXPECT_TRUE(entry.title().empty()); 328 EXPECT_TRUE(entry.file_specific_info().has_cache_state()); 329 } 330 331 TEST_F(ResourceMetadataStorageTest, IncompatibleDB_M32) { 332 const int64 kLargestChangestamp = 1234567890; 333 const std::string title = "title"; 334 const std::string resource_id = "abcd"; 335 const std::string local_id = "local-abcd"; 336 337 // Construct M32 version DB. 338 SetDBVersion(11); 339 EXPECT_EQ(FILE_ERROR_OK, 340 storage_->SetLargestChangestamp(kLargestChangestamp)); 341 342 leveldb::WriteBatch batch; 343 344 // Put a file entry and its cache and id entry. 345 ResourceEntry entry; 346 std::string serialized_entry; 347 entry.set_title(title); 348 entry.set_local_id(local_id); 349 entry.set_resource_id(resource_id); 350 EXPECT_TRUE(entry.SerializeToString(&serialized_entry)); 351 batch.Put(local_id, serialized_entry); 352 353 FileCacheEntry cache_entry; 354 EXPECT_TRUE(cache_entry.SerializeToString(&serialized_entry)); 355 batch.Put(local_id + '\0' + "CACHE", serialized_entry); 356 357 batch.Put('\0' + std::string("ID") + '\0' + resource_id, local_id); 358 359 EXPECT_TRUE(resource_map()->Write(leveldb::WriteOptions(), &batch).ok()); 360 361 // Upgrade and reopen. 362 storage_.reset(); 363 EXPECT_TRUE(ResourceMetadataStorage::UpgradeOldDB(temp_dir_.path())); 364 storage_.reset(new ResourceMetadataStorage( 365 temp_dir_.path(), base::MessageLoopProxy::current().get())); 366 ASSERT_TRUE(storage_->Initialize()); 367 368 // Data is erased, except cache and id mapping entries. 369 std::string id; 370 EXPECT_EQ(FILE_ERROR_OK, storage_->GetIdByResourceId(resource_id, &id)); 371 EXPECT_EQ(local_id, id); 372 int64 largest_changestamp = 0; 373 EXPECT_EQ(FILE_ERROR_OK, 374 storage_->GetLargestChangestamp(&largest_changestamp)); 375 EXPECT_EQ(0, largest_changestamp); 376 EXPECT_EQ(FILE_ERROR_OK, storage_->GetEntry(id, &entry)); 377 EXPECT_TRUE(entry.title().empty()); 378 EXPECT_TRUE(entry.file_specific_info().has_cache_state()); 379 } 380 381 TEST_F(ResourceMetadataStorageTest, IncompatibleDB_M33) { 382 const int64 kLargestChangestamp = 1234567890; 383 const std::string title = "title"; 384 const std::string resource_id = "abcd"; 385 const std::string local_id = "local-abcd"; 386 const std::string md5 = "md5"; 387 const std::string resource_id2 = "efgh"; 388 const std::string local_id2 = "local-efgh"; 389 const std::string md5_2 = "md5_2"; 390 391 // Construct M33 version DB. 392 SetDBVersion(12); 393 EXPECT_EQ(FILE_ERROR_OK, 394 storage_->SetLargestChangestamp(kLargestChangestamp)); 395 396 leveldb::WriteBatch batch; 397 398 // Put a file entry and its cache and id entry. 399 ResourceEntry entry; 400 std::string serialized_entry; 401 entry.set_title(title); 402 entry.set_local_id(local_id); 403 entry.set_resource_id(resource_id); 404 EXPECT_TRUE(entry.SerializeToString(&serialized_entry)); 405 batch.Put(local_id, serialized_entry); 406 407 FileCacheEntry cache_entry; 408 cache_entry.set_md5(md5); 409 EXPECT_TRUE(cache_entry.SerializeToString(&serialized_entry)); 410 batch.Put(local_id + '\0' + "CACHE", serialized_entry); 411 412 batch.Put('\0' + std::string("ID") + '\0' + resource_id, local_id); 413 414 // Put another cache entry which is not accompanied by a ResourceEntry. 415 cache_entry.set_md5(md5_2); 416 EXPECT_TRUE(cache_entry.SerializeToString(&serialized_entry)); 417 batch.Put(local_id2 + '\0' + "CACHE", serialized_entry); 418 batch.Put('\0' + std::string("ID") + '\0' + resource_id2, local_id2); 419 420 EXPECT_TRUE(resource_map()->Write(leveldb::WriteOptions(), &batch).ok()); 421 422 // Upgrade and reopen. 423 storage_.reset(); 424 EXPECT_TRUE(ResourceMetadataStorage::UpgradeOldDB(temp_dir_.path())); 425 storage_.reset(new ResourceMetadataStorage( 426 temp_dir_.path(), base::MessageLoopProxy::current().get())); 427 ASSERT_TRUE(storage_->Initialize()); 428 429 // No data is lost. 430 int64 largest_changestamp = 0; 431 EXPECT_EQ(FILE_ERROR_OK, 432 storage_->GetLargestChangestamp(&largest_changestamp)); 433 EXPECT_EQ(kLargestChangestamp, largest_changestamp); 434 435 std::string id; 436 EXPECT_EQ(FILE_ERROR_OK, storage_->GetIdByResourceId(resource_id, &id)); 437 EXPECT_EQ(local_id, id); 438 EXPECT_EQ(FILE_ERROR_OK, storage_->GetEntry(id, &entry)); 439 EXPECT_EQ(title, entry.title()); 440 EXPECT_EQ(md5, entry.file_specific_info().cache_state().md5()); 441 442 EXPECT_EQ(FILE_ERROR_OK, storage_->GetIdByResourceId(resource_id2, &id)); 443 EXPECT_EQ(local_id2, id); 444 EXPECT_EQ(FILE_ERROR_OK, storage_->GetEntry(id, &entry)); 445 EXPECT_EQ(md5_2, entry.file_specific_info().cache_state().md5()); 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_EQ(FILE_ERROR_OK, 454 storage_->SetLargestChangestamp(kLargestChangestamp)); 455 ResourceEntry entry; 456 entry.set_local_id(key1); 457 EXPECT_EQ(FILE_ERROR_OK, storage_->PutEntry(entry)); 458 459 // Set newer version, upgrade and reopen DB. 460 SetDBVersion(ResourceMetadataStorage::kDBVersion + 1); 461 storage_.reset(); 462 EXPECT_FALSE(ResourceMetadataStorage::UpgradeOldDB(temp_dir_.path())); 463 storage_.reset(new ResourceMetadataStorage( 464 temp_dir_.path(), base::MessageLoopProxy::current().get())); 465 ASSERT_TRUE(storage_->Initialize()); 466 467 // Data is erased because of the incompatible version. 468 int64 largest_changestamp = 0; 469 EXPECT_EQ(FILE_ERROR_OK, 470 storage_->GetLargestChangestamp(&largest_changestamp)); 471 EXPECT_EQ(0, largest_changestamp); 472 EXPECT_EQ(FILE_ERROR_NOT_FOUND, storage_->GetEntry(key1, &entry)); 473 } 474 475 TEST_F(ResourceMetadataStorageTest, DeleteUnusedIDEntries) { 476 leveldb::WriteBatch batch; 477 478 // Put an ID entry with a corresponding ResourceEntry. 479 ResourceEntry entry; 480 entry.set_local_id("id1"); 481 entry.set_resource_id("resource_id1"); 482 483 std::string serialized_entry; 484 EXPECT_TRUE(entry.SerializeToString(&serialized_entry)); 485 batch.Put("id1", serialized_entry); 486 batch.Put('\0' + std::string("ID") + '\0' + "resource_id1", "id1"); 487 488 // Put an ID entry without any corresponding entries. 489 batch.Put('\0' + std::string("ID") + '\0' + "resource_id2", "id3"); 490 491 EXPECT_TRUE(resource_map()->Write(leveldb::WriteOptions(), &batch).ok()); 492 493 // Upgrade and reopen. 494 storage_.reset(); 495 EXPECT_TRUE(ResourceMetadataStorage::UpgradeOldDB(temp_dir_.path())); 496 storage_.reset(new ResourceMetadataStorage( 497 temp_dir_.path(), base::MessageLoopProxy::current().get())); 498 ASSERT_TRUE(storage_->Initialize()); 499 500 // Only the unused entry is deleted. 501 std::string id; 502 EXPECT_EQ(FILE_ERROR_OK, storage_->GetIdByResourceId("resource_id1", &id)); 503 EXPECT_EQ("id1", id); 504 EXPECT_EQ(FILE_ERROR_NOT_FOUND, 505 storage_->GetIdByResourceId("resource_id2", &id)); 506 } 507 508 TEST_F(ResourceMetadataStorageTest, WrongPath) { 509 // Create a file. 510 base::FilePath path; 511 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(), &path)); 512 513 storage_.reset(new ResourceMetadataStorage( 514 path, base::MessageLoopProxy::current().get())); 515 // Cannot initialize DB beacause the path does not point a directory. 516 ASSERT_FALSE(storage_->Initialize()); 517 } 518 519 TEST_F(ResourceMetadataStorageTest, RecoverCacheEntriesFromTrashedResourceMap) { 520 // Put entry with id_foo. 521 ResourceEntry entry; 522 entry.set_local_id("id_foo"); 523 entry.set_base_name("foo"); 524 entry.set_title("foo"); 525 entry.mutable_file_specific_info()->mutable_cache_state()->set_md5("md5_foo"); 526 EXPECT_EQ(FILE_ERROR_OK, storage_->PutEntry(entry)); 527 528 // Put entry with id_bar as a id_foo's child. 529 entry.set_local_id("id_bar"); 530 entry.set_parent_local_id("id_foo"); 531 entry.set_base_name("bar"); 532 entry.set_title("bar"); 533 entry.mutable_file_specific_info()->mutable_cache_state()->set_md5("md5_bar"); 534 entry.mutable_file_specific_info()->mutable_cache_state()->set_is_dirty(true); 535 EXPECT_EQ(FILE_ERROR_OK, storage_->PutEntry(entry)); 536 537 // Remove parent-child relationship to make the DB invalid. 538 RemoveChild("id_foo", "bar"); 539 EXPECT_FALSE(CheckValidity()); 540 541 // Reopen. This should result in trashing the DB. 542 storage_.reset(new ResourceMetadataStorage( 543 temp_dir_.path(), base::MessageLoopProxy::current().get())); 544 ASSERT_TRUE(storage_->Initialize()); 545 546 // Recover cache entries from the trashed DB. 547 ResourceMetadataStorage::RecoveredCacheInfoMap recovered_cache_info; 548 storage_->RecoverCacheInfoFromTrashedResourceMap(&recovered_cache_info); 549 EXPECT_EQ(2U, recovered_cache_info.size()); 550 EXPECT_FALSE(recovered_cache_info["id_foo"].is_dirty); 551 EXPECT_EQ("md5_foo", recovered_cache_info["id_foo"].md5); 552 EXPECT_EQ("foo", recovered_cache_info["id_foo"].title); 553 EXPECT_TRUE(recovered_cache_info["id_bar"].is_dirty); 554 EXPECT_EQ("md5_bar", recovered_cache_info["id_bar"].md5); 555 EXPECT_EQ("bar", recovered_cache_info["id_bar"].title); 556 } 557 558 TEST_F(ResourceMetadataStorageTest, CheckValidity) { 559 const std::string key1 = "foo"; 560 const std::string name1 = "hoge"; 561 const std::string key2 = "bar"; 562 const std::string name2 = "fuga"; 563 const std::string key3 = "boo"; 564 const std::string name3 = "piyo"; 565 566 // Empty storage is valid. 567 EXPECT_TRUE(CheckValidity()); 568 569 // Put entry with key1. 570 ResourceEntry entry; 571 entry.set_local_id(key1); 572 entry.set_base_name(name1); 573 EXPECT_EQ(FILE_ERROR_OK, storage_->PutEntry(entry)); 574 EXPECT_TRUE(CheckValidity()); 575 576 // Put entry with key2 under key1. 577 entry.set_local_id(key2); 578 entry.set_parent_local_id(key1); 579 entry.set_base_name(name2); 580 EXPECT_EQ(FILE_ERROR_OK, storage_->PutEntry(entry)); 581 EXPECT_TRUE(CheckValidity()); 582 583 RemoveChild(key1, name2); 584 EXPECT_FALSE(CheckValidity()); // Missing parent-child relationship. 585 586 // Add back parent-child relationship between key1 and key2. 587 PutChild(key1, name2, key2); 588 EXPECT_TRUE(CheckValidity()); 589 590 // Add parent-child relationship between key2 and key3. 591 PutChild(key2, name3, key3); 592 EXPECT_FALSE(CheckValidity()); // key3 is not stored in the storage. 593 594 // Put entry with key3 under key2. 595 entry.set_local_id(key3); 596 entry.set_parent_local_id(key2); 597 entry.set_base_name(name3); 598 EXPECT_EQ(FILE_ERROR_OK, storage_->PutEntry(entry)); 599 EXPECT_TRUE(CheckValidity()); 600 601 // Parent-child relationship with wrong name. 602 RemoveChild(key2, name3); 603 EXPECT_FALSE(CheckValidity()); 604 PutChild(key2, name2, key3); 605 EXPECT_FALSE(CheckValidity()); 606 607 // Fix up the relationship between key2 and key3. 608 RemoveChild(key2, name2); 609 EXPECT_FALSE(CheckValidity()); 610 PutChild(key2, name3, key3); 611 EXPECT_TRUE(CheckValidity()); 612 613 // Remove key2. 614 RemoveChild(key1, name2); 615 EXPECT_FALSE(CheckValidity()); 616 EXPECT_EQ(FILE_ERROR_OK, storage_->RemoveEntry(key2)); 617 EXPECT_FALSE(CheckValidity()); 618 619 // Remove key3. 620 RemoveChild(key2, name3); 621 EXPECT_FALSE(CheckValidity()); 622 EXPECT_EQ(FILE_ERROR_OK, storage_->RemoveEntry(key3)); 623 EXPECT_TRUE(CheckValidity()); 624 625 // Remove key1. 626 EXPECT_EQ(FILE_ERROR_OK, storage_->RemoveEntry(key1)); 627 EXPECT_TRUE(CheckValidity()); 628 } 629 630 } // namespace internal 631 } // namespace drive 632