Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / drive / resource_metadata_storage_unittest.cc
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