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.
5 #include "components/drive/resource_metadata_storage.h"
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"
24 class ResourceMetadataStorageTest
: public testing::Test
{
26 void SetUp() override
{
27 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
29 storage_
.reset(new ResourceMetadataStorage(
30 temp_dir_
.path(), base::ThreadTaskRunnerHandle::Get().get()));
31 ASSERT_TRUE(storage_
->Initialize());
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
));
42 bool CheckValidity() {
43 return storage_
->CheckValidity();
46 leveldb::DB
* resource_map() { return storage_
->resource_map_
.get(); }
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
),
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
));
66 content::TestBrowserThreadBundle thread_bundle_
;
67 base::ScopedTempDir temp_dir_
;
68 scoped_ptr
<ResourceMetadataStorage
,
69 test_util::DestroyHelperForTests
> storage_
;
72 TEST_F(ResourceMetadataStorageTest
, LargestChangestamp
) {
73 const int64 kLargestChangestamp
= 1234567890;
74 EXPECT_EQ(FILE_ERROR_OK
,
75 storage_
->SetLargestChangestamp(kLargestChangestamp
));
77 EXPECT_EQ(FILE_ERROR_OK
, storage_
->GetLargestChangestamp(&value
));
78 EXPECT_EQ(kLargestChangestamp
, value
);
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";
90 EXPECT_EQ(FILE_ERROR_NOT_FOUND
, storage_
->GetEntry(key1
, &result
));
94 entry1
.set_local_id(key1
);
95 EXPECT_EQ(FILE_ERROR_OK
, storage_
->PutEntry(entry1
));
98 EXPECT_EQ(FILE_ERROR_OK
, storage_
->GetEntry(key1
, &result
));
101 EXPECT_EQ(FILE_ERROR_NOT_FOUND
, storage_
->GetEntry(key2
, &result
));
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
));
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
);
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
));
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
);
128 // Change entry3's parent to entry1.
129 entry3
.set_parent_local_id(key1
);
130 EXPECT_EQ(FILE_ERROR_OK
, storage_
->PutEntry(entry3
));
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
);
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
));
146 TEST_F(ResourceMetadataStorageTest
, Iterator
) {
148 std::vector
<std::string
> keys
;
150 keys
.push_back("entry1");
151 keys
.push_back("entry2");
152 keys
.push_back("entry3");
153 keys
.push_back("entry4");
155 for (size_t i
= 0; i
< keys
.size(); ++i
) {
157 entry
.set_local_id(keys
[i
]);
158 EXPECT_EQ(FILE_ERROR_OK
, storage_
->PutEntry(entry
));
161 // Iterate and check the result.
162 std::map
<std::string
, ResourceEntry
> found_entries
;
163 scoped_ptr
<ResourceMetadataStorage::Iterator
> it
= storage_
->GetIterator();
165 for (; !it
->IsAtEnd(); it
->Advance()) {
166 const ResourceEntry
& entry
= it
->GetValue();
167 found_entries
[it
->GetID()] = entry
;
169 EXPECT_FALSE(it
->HasError());
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
]));
176 TEST_F(ResourceMetadataStorageTest
, GetIdByResourceId
) {
177 const std::string local_id
= "local_id";
178 const std::string resource_id
= "resource_id";
180 // Resource ID to local ID mapping is not stored yet.
182 EXPECT_EQ(FILE_ERROR_NOT_FOUND
,
183 storage_
->GetIdByResourceId(resource_id
, &id
));
185 // Put an entry with the resource ID.
187 entry
.set_local_id(local_id
);
188 entry
.set_resource_id(resource_id
);
189 EXPECT_EQ(FILE_ERROR_OK
, storage_
->PutEntry(entry
));
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
);
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
));
201 TEST_F(ResourceMetadataStorageTest
, GetChildren
) {
202 const std::string parents_id
[] = { "mercury", "venus", "mars", "jupiter",
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"));
221 for (size_t i
= 0; i
< arraysize(parents_id
); ++i
) {
223 entry
.set_local_id(parents_id
[i
]);
224 EXPECT_EQ(FILE_ERROR_OK
, storage_
->PutEntry(entry
));
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
) {
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
));
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(),
246 children_name_id
[i
][j
].second
));
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";
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
);
264 EXPECT_EQ(FILE_ERROR_OK
, storage_
->PutEntry(entry1
));
265 EXPECT_EQ(FILE_ERROR_OK
, storage_
->PutEntry(entry2
));
267 // Close DB and reopen.
268 storage_
.reset(new ResourceMetadataStorage(
269 temp_dir_
.path(), base::ThreadTaskRunnerHandle::Get().get()));
270 ASSERT_TRUE(storage_
->Initialize());
273 ResourceEntry result
;
274 EXPECT_EQ(FILE_ERROR_OK
, storage_
->GetEntry(parent_id1
, &result
));
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());
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
);
286 TEST_F(ResourceMetadataStorageTest
, IncompatibleDB_M29
) {
287 const int64 kLargestChangestamp
= 1234567890;
288 const std::string title
= "title";
290 // Construct M29 version DB.
292 EXPECT_EQ(FILE_ERROR_OK
,
293 storage_
->SetLargestChangestamp(kLargestChangestamp
));
295 leveldb::WriteBatch batch
;
297 // Put a file entry and its cache 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
);
305 FileCacheEntry cache_entry
;
306 EXPECT_TRUE(cache_entry
.SerializeToString(&serialized_entry
));
307 batch
.Put(std::string("file:abcd") + '\0' + "CACHE", serialized_entry
);
309 EXPECT_TRUE(resource_map()->Write(leveldb::WriteOptions(), &batch
).ok());
311 // Upgrade and reopen.
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());
318 // Resource-ID-to-local-ID mapping is added.
320 EXPECT_EQ(FILE_ERROR_OK
,
321 storage_
->GetIdByResourceId("abcd", &id
)); // "file:" is dropped.
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());
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";
339 // Construct M32 version DB.
341 EXPECT_EQ(FILE_ERROR_OK
,
342 storage_
->SetLargestChangestamp(kLargestChangestamp
));
344 leveldb::WriteBatch batch
;
346 // Put a file entry and its cache and id 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
);
355 FileCacheEntry cache_entry
;
356 EXPECT_TRUE(cache_entry
.SerializeToString(&serialized_entry
));
357 batch
.Put(local_id
+ '\0' + "CACHE", serialized_entry
);
359 batch
.Put('\0' + std::string("ID") + '\0' + resource_id
, local_id
);
361 EXPECT_TRUE(resource_map()->Write(leveldb::WriteOptions(), &batch
).ok());
363 // Upgrade and reopen.
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());
370 // Data is erased, except cache and id mapping entries.
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());
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";
393 // Construct M33 version DB.
395 EXPECT_EQ(FILE_ERROR_OK
,
396 storage_
->SetLargestChangestamp(kLargestChangestamp
));
398 leveldb::WriteBatch batch
;
400 // Put a file entry and its cache and id 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
);
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
);
414 batch
.Put('\0' + std::string("ID") + '\0' + resource_id
, local_id
);
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
);
422 EXPECT_TRUE(resource_map()->Write(leveldb::WriteOptions(), &batch
).ok());
424 // Upgrade and reopen.
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());
432 int64 largest_changestamp
= 0;
433 EXPECT_EQ(FILE_ERROR_OK
,
434 storage_
->GetLargestChangestamp(&largest_changestamp
));
435 EXPECT_EQ(kLargestChangestamp
, largest_changestamp
);
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());
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());
450 TEST_F(ResourceMetadataStorageTest
, IncompatibleDB_Unknown
) {
451 const int64 kLargestChangestamp
= 1234567890;
452 const std::string key1
= "abcd";
455 EXPECT_EQ(FILE_ERROR_OK
,
456 storage_
->SetLargestChangestamp(kLargestChangestamp
));
458 entry
.set_local_id(key1
);
459 EXPECT_EQ(FILE_ERROR_OK
, storage_
->PutEntry(entry
));
461 // Set newer version, upgrade and reopen DB.
462 SetDBVersion(ResourceMetadataStorage::kDBVersion
+ 1);
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());
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
));
477 TEST_F(ResourceMetadataStorageTest
, DeleteUnusedIDEntries
) {
478 leveldb::WriteBatch batch
;
480 // Put an ID entry with a corresponding ResourceEntry.
482 entry
.set_local_id("id1");
483 entry
.set_resource_id("resource_id1");
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");
490 // Put an ID entry without any corresponding entries.
491 batch
.Put('\0' + std::string("ID") + '\0' + "resource_id2", "id3");
493 EXPECT_TRUE(resource_map()->Write(leveldb::WriteOptions(), &batch
).ok());
495 // Upgrade and reopen.
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());
502 // Only the unused entry is deleted.
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
));
510 TEST_F(ResourceMetadataStorageTest
, WrongPath
) {
513 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_
.path(), &path
));
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());
521 TEST_F(ResourceMetadataStorageTest
, RecoverCacheEntriesFromTrashedResourceMap
) {
522 // Put entry with id_foo.
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
));
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
));
539 // Remove parent-child relationship to make the DB invalid.
540 RemoveChild("id_foo", "bar");
541 EXPECT_FALSE(CheckValidity());
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());
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
);
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";
568 // Empty storage is valid.
569 EXPECT_TRUE(CheckValidity());
571 // Put entry with key1.
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());
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());
585 RemoveChild(key1
, name2
);
586 EXPECT_FALSE(CheckValidity()); // Missing parent-child relationship.
588 // Add back parent-child relationship between key1 and key2.
589 PutChild(key1
, name2
, key2
);
590 EXPECT_TRUE(CheckValidity());
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.
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());
603 // Parent-child relationship with wrong name.
604 RemoveChild(key2
, name3
);
605 EXPECT_FALSE(CheckValidity());
606 PutChild(key2
, name2
, key3
);
607 EXPECT_FALSE(CheckValidity());
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());
616 RemoveChild(key1
, name2
);
617 EXPECT_FALSE(CheckValidity());
618 EXPECT_EQ(FILE_ERROR_OK
, storage_
->RemoveEntry(key2
));
619 EXPECT_FALSE(CheckValidity());
622 RemoveChild(key2
, name3
);
623 EXPECT_FALSE(CheckValidity());
624 EXPECT_EQ(FILE_ERROR_OK
, storage_
->RemoveEntry(key3
));
625 EXPECT_TRUE(CheckValidity());
628 EXPECT_EQ(FILE_ERROR_OK
, storage_
->RemoveEntry(key1
));
629 EXPECT_TRUE(CheckValidity());
632 } // namespace internal