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 "chrome/browser/chromeos/drive/resource_metadata_storage.h"
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"
22 class ResourceMetadataStorageTest
: public testing::Test
{
24 void SetUp() override
{
25 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
27 storage_
.reset(new ResourceMetadataStorage(
28 temp_dir_
.path(), base::MessageLoopProxy::current().get()));
29 ASSERT_TRUE(storage_
->Initialize());
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
));
40 bool CheckValidity() {
41 return storage_
->CheckValidity();
44 leveldb::DB
* resource_map() { return storage_
->resource_map_
.get(); }
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
),
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
));
64 content::TestBrowserThreadBundle thread_bundle_
;
65 base::ScopedTempDir temp_dir_
;
66 scoped_ptr
<ResourceMetadataStorage
,
67 test_util::DestroyHelperForTests
> storage_
;
70 TEST_F(ResourceMetadataStorageTest
, LargestChangestamp
) {
71 const int64 kLargestChangestamp
= 1234567890;
72 EXPECT_EQ(FILE_ERROR_OK
,
73 storage_
->SetLargestChangestamp(kLargestChangestamp
));
75 EXPECT_EQ(FILE_ERROR_OK
, storage_
->GetLargestChangestamp(&value
));
76 EXPECT_EQ(kLargestChangestamp
, value
);
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";
88 EXPECT_EQ(FILE_ERROR_NOT_FOUND
, storage_
->GetEntry(key1
, &result
));
92 entry1
.set_local_id(key1
);
93 EXPECT_EQ(FILE_ERROR_OK
, storage_
->PutEntry(entry1
));
96 EXPECT_EQ(FILE_ERROR_OK
, storage_
->GetEntry(key1
, &result
));
99 EXPECT_EQ(FILE_ERROR_NOT_FOUND
, storage_
->GetEntry(key2
, &result
));
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
));
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
);
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
));
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
);
126 // Change entry3's parent to entry1.
127 entry3
.set_parent_local_id(key1
);
128 EXPECT_EQ(FILE_ERROR_OK
, storage_
->PutEntry(entry3
));
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
);
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
));
144 TEST_F(ResourceMetadataStorageTest
, Iterator
) {
146 std::vector
<std::string
> keys
;
148 keys
.push_back("entry1");
149 keys
.push_back("entry2");
150 keys
.push_back("entry3");
151 keys
.push_back("entry4");
153 for (size_t i
= 0; i
< keys
.size(); ++i
) {
155 entry
.set_local_id(keys
[i
]);
156 EXPECT_EQ(FILE_ERROR_OK
, storage_
->PutEntry(entry
));
159 // Iterate and check the result.
160 std::map
<std::string
, ResourceEntry
> found_entries
;
161 scoped_ptr
<ResourceMetadataStorage::Iterator
> it
= storage_
->GetIterator();
163 for (; !it
->IsAtEnd(); it
->Advance()) {
164 const ResourceEntry
& entry
= it
->GetValue();
165 found_entries
[it
->GetID()] = entry
;
167 EXPECT_FALSE(it
->HasError());
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
]));
174 TEST_F(ResourceMetadataStorageTest
, GetIdByResourceId
) {
175 const std::string local_id
= "local_id";
176 const std::string resource_id
= "resource_id";
178 // Resource ID to local ID mapping is not stored yet.
180 EXPECT_EQ(FILE_ERROR_NOT_FOUND
,
181 storage_
->GetIdByResourceId(resource_id
, &id
));
183 // Put an entry with the resource ID.
185 entry
.set_local_id(local_id
);
186 entry
.set_resource_id(resource_id
);
187 EXPECT_EQ(FILE_ERROR_OK
, storage_
->PutEntry(entry
));
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
);
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
));
199 TEST_F(ResourceMetadataStorageTest
, GetChildren
) {
200 const std::string parents_id
[] = { "mercury", "venus", "mars", "jupiter",
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"));
219 for (size_t i
= 0; i
< arraysize(parents_id
); ++i
) {
221 entry
.set_local_id(parents_id
[i
]);
222 EXPECT_EQ(FILE_ERROR_OK
, storage_
->PutEntry(entry
));
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
) {
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
));
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(),
244 children_name_id
[i
][j
].second
));
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";
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
);
262 EXPECT_EQ(FILE_ERROR_OK
, storage_
->PutEntry(entry1
));
263 EXPECT_EQ(FILE_ERROR_OK
, storage_
->PutEntry(entry2
));
265 // Close DB and reopen.
266 storage_
.reset(new ResourceMetadataStorage(
267 temp_dir_
.path(), base::MessageLoopProxy::current().get()));
268 ASSERT_TRUE(storage_
->Initialize());
271 ResourceEntry result
;
272 EXPECT_EQ(FILE_ERROR_OK
, storage_
->GetEntry(parent_id1
, &result
));
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());
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
);
284 TEST_F(ResourceMetadataStorageTest
, IncompatibleDB_M29
) {
285 const int64 kLargestChangestamp
= 1234567890;
286 const std::string title
= "title";
288 // Construct M29 version DB.
290 EXPECT_EQ(FILE_ERROR_OK
,
291 storage_
->SetLargestChangestamp(kLargestChangestamp
));
293 leveldb::WriteBatch batch
;
295 // Put a file entry and its cache 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
);
303 FileCacheEntry cache_entry
;
304 EXPECT_TRUE(cache_entry
.SerializeToString(&serialized_entry
));
305 batch
.Put(std::string("file:abcd") + '\0' + "CACHE", serialized_entry
);
307 EXPECT_TRUE(resource_map()->Write(leveldb::WriteOptions(), &batch
).ok());
309 // Upgrade and reopen.
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());
316 // Resource-ID-to-local-ID mapping is added.
318 EXPECT_EQ(FILE_ERROR_OK
,
319 storage_
->GetIdByResourceId("abcd", &id
)); // "file:" is dropped.
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());
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";
337 // Construct M32 version DB.
339 EXPECT_EQ(FILE_ERROR_OK
,
340 storage_
->SetLargestChangestamp(kLargestChangestamp
));
342 leveldb::WriteBatch batch
;
344 // Put a file entry and its cache and id 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
);
353 FileCacheEntry cache_entry
;
354 EXPECT_TRUE(cache_entry
.SerializeToString(&serialized_entry
));
355 batch
.Put(local_id
+ '\0' + "CACHE", serialized_entry
);
357 batch
.Put('\0' + std::string("ID") + '\0' + resource_id
, local_id
);
359 EXPECT_TRUE(resource_map()->Write(leveldb::WriteOptions(), &batch
).ok());
361 // Upgrade and reopen.
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());
368 // Data is erased, except cache and id mapping entries.
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());
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";
391 // Construct M33 version DB.
393 EXPECT_EQ(FILE_ERROR_OK
,
394 storage_
->SetLargestChangestamp(kLargestChangestamp
));
396 leveldb::WriteBatch batch
;
398 // Put a file entry and its cache and id 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
);
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
);
412 batch
.Put('\0' + std::string("ID") + '\0' + resource_id
, local_id
);
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
);
420 EXPECT_TRUE(resource_map()->Write(leveldb::WriteOptions(), &batch
).ok());
422 // Upgrade and reopen.
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());
430 int64 largest_changestamp
= 0;
431 EXPECT_EQ(FILE_ERROR_OK
,
432 storage_
->GetLargestChangestamp(&largest_changestamp
));
433 EXPECT_EQ(kLargestChangestamp
, largest_changestamp
);
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());
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());
448 TEST_F(ResourceMetadataStorageTest
, IncompatibleDB_Unknown
) {
449 const int64 kLargestChangestamp
= 1234567890;
450 const std::string key1
= "abcd";
453 EXPECT_EQ(FILE_ERROR_OK
,
454 storage_
->SetLargestChangestamp(kLargestChangestamp
));
456 entry
.set_local_id(key1
);
457 EXPECT_EQ(FILE_ERROR_OK
, storage_
->PutEntry(entry
));
459 // Set newer version, upgrade and reopen DB.
460 SetDBVersion(ResourceMetadataStorage::kDBVersion
+ 1);
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());
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
));
475 TEST_F(ResourceMetadataStorageTest
, DeleteUnusedIDEntries
) {
476 leveldb::WriteBatch batch
;
478 // Put an ID entry with a corresponding ResourceEntry.
480 entry
.set_local_id("id1");
481 entry
.set_resource_id("resource_id1");
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");
488 // Put an ID entry without any corresponding entries.
489 batch
.Put('\0' + std::string("ID") + '\0' + "resource_id2", "id3");
491 EXPECT_TRUE(resource_map()->Write(leveldb::WriteOptions(), &batch
).ok());
493 // Upgrade and reopen.
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());
500 // Only the unused entry is deleted.
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
));
508 TEST_F(ResourceMetadataStorageTest
, WrongPath
) {
511 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_
.path(), &path
));
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());
519 TEST_F(ResourceMetadataStorageTest
, RecoverCacheEntriesFromTrashedResourceMap
) {
520 // Put entry with id_foo.
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
));
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
));
537 // Remove parent-child relationship to make the DB invalid.
538 RemoveChild("id_foo", "bar");
539 EXPECT_FALSE(CheckValidity());
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());
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
);
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";
566 // Empty storage is valid.
567 EXPECT_TRUE(CheckValidity());
569 // Put entry with key1.
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());
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());
583 RemoveChild(key1
, name2
);
584 EXPECT_FALSE(CheckValidity()); // Missing parent-child relationship.
586 // Add back parent-child relationship between key1 and key2.
587 PutChild(key1
, name2
, key2
);
588 EXPECT_TRUE(CheckValidity());
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.
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());
601 // Parent-child relationship with wrong name.
602 RemoveChild(key2
, name3
);
603 EXPECT_FALSE(CheckValidity());
604 PutChild(key2
, name2
, key3
);
605 EXPECT_FALSE(CheckValidity());
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());
614 RemoveChild(key1
, name2
);
615 EXPECT_FALSE(CheckValidity());
616 EXPECT_EQ(FILE_ERROR_OK
, storage_
->RemoveEntry(key2
));
617 EXPECT_FALSE(CheckValidity());
620 RemoveChild(key2
, name3
);
621 EXPECT_FALSE(CheckValidity());
622 EXPECT_EQ(FILE_ERROR_OK
, storage_
->RemoveEntry(key3
));
623 EXPECT_TRUE(CheckValidity());
626 EXPECT_EQ(FILE_ERROR_OK
, storage_
->RemoveEntry(key1
));
627 EXPECT_TRUE(CheckValidity());
630 } // namespace internal