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