Upstream version 9.38.198.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/file_util.h"
10 #include "base/files/scoped_temp_dir.h"
11 #include "chrome/browser/chromeos/drive/drive.pb.h"
12 #include "chrome/browser/chromeos/drive/test_util.h"
13 #include "content/public/test/test_browser_thread_bundle.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "third_party/leveldatabase/src/include/leveldb/db.h"
16 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
17
18 namespace drive {
19 namespace internal {
20
21 class ResourceMetadataStorageTest : public testing::Test {
22  protected:
23   virtual void SetUp() OVERRIDE {
24     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
25
26     storage_.reset(new ResourceMetadataStorage(
27         temp_dir_.path(), base::MessageLoopProxy::current().get()));
28     ASSERT_TRUE(storage_->Initialize());
29   }
30
31   // Overwrites |storage_|'s version.
32   void SetDBVersion(int version) {
33     ResourceMetadataHeader header;
34     ASSERT_EQ(FILE_ERROR_OK, storage_->GetHeader(&header));
35     header.set_version(version);
36     EXPECT_EQ(FILE_ERROR_OK, storage_->PutHeader(header));
37   }
38
39   bool CheckValidity() {
40     return storage_->CheckValidity();
41   }
42
43   leveldb::DB* resource_map() { return storage_->resource_map_.get(); }
44
45   // Puts a child entry.
46   void PutChild(const std::string& parent_id,
47                 const std::string& child_base_name,
48                 const std::string& child_id) {
49     storage_->resource_map_->Put(
50         leveldb::WriteOptions(),
51         ResourceMetadataStorage::GetChildEntryKey(parent_id, child_base_name),
52         child_id);
53   }
54
55   // Removes a child entry.
56   void RemoveChild(const std::string& parent_id,
57                    const std::string& child_base_name) {
58     storage_->resource_map_->Delete(
59         leveldb::WriteOptions(),
60         ResourceMetadataStorage::GetChildEntryKey(parent_id, child_base_name));
61   }
62
63   content::TestBrowserThreadBundle thread_bundle_;
64   base::ScopedTempDir temp_dir_;
65   scoped_ptr<ResourceMetadataStorage,
66              test_util::DestroyHelperForTests> storage_;
67 };
68
69 TEST_F(ResourceMetadataStorageTest, LargestChangestamp) {
70   const int64 kLargestChangestamp = 1234567890;
71   EXPECT_EQ(FILE_ERROR_OK,
72             storage_->SetLargestChangestamp(kLargestChangestamp));
73   int64 value = 0;
74   EXPECT_EQ(FILE_ERROR_OK, storage_->GetLargestChangestamp(&value));
75   EXPECT_EQ(kLargestChangestamp, value);
76 }
77
78 TEST_F(ResourceMetadataStorageTest, PutEntry) {
79   const std::string key1 = "abcdefg";
80   const std::string key2 = "abcd";
81   const std::string key3 = "efgh";
82   const std::string name2 = "ABCD";
83   const std::string name3 = "EFGH";
84
85   // key1 not found.
86   ResourceEntry result;
87   EXPECT_EQ(FILE_ERROR_NOT_FOUND, storage_->GetEntry(key1, &result));
88
89   // Put entry1.
90   ResourceEntry entry1;
91   entry1.set_local_id(key1);
92   EXPECT_EQ(FILE_ERROR_OK, storage_->PutEntry(entry1));
93
94   // key1 found.
95   EXPECT_EQ(FILE_ERROR_OK, storage_->GetEntry(key1, &result));
96
97   // key2 not found.
98   EXPECT_EQ(FILE_ERROR_NOT_FOUND, storage_->GetEntry(key2, &result));
99
100   // Put entry2 as a child of entry1.
101   ResourceEntry entry2;
102   entry2.set_local_id(key2);
103   entry2.set_parent_local_id(key1);
104   entry2.set_base_name(name2);
105   EXPECT_EQ(FILE_ERROR_OK, storage_->PutEntry(entry2));
106
107   // key2 found.
108   std::string child_id;
109   EXPECT_EQ(FILE_ERROR_OK, storage_->GetEntry(key2, &result));
110   EXPECT_EQ(FILE_ERROR_OK, storage_->GetChild(key1, name2, &child_id));
111   EXPECT_EQ(key2, child_id);
112
113   // Put entry3 as a child of entry2.
114   ResourceEntry entry3;
115   entry3.set_local_id(key3);
116   entry3.set_parent_local_id(key2);
117   entry3.set_base_name(name3);
118   EXPECT_EQ(FILE_ERROR_OK, storage_->PutEntry(entry3));
119
120   // key3 found.
121   EXPECT_EQ(FILE_ERROR_OK, storage_->GetEntry(key3, &result));
122   EXPECT_EQ(FILE_ERROR_OK, storage_->GetChild(key2, name3, &child_id));
123   EXPECT_EQ(key3, child_id);
124
125   // Change entry3's parent to entry1.
126   entry3.set_parent_local_id(key1);
127   EXPECT_EQ(FILE_ERROR_OK, storage_->PutEntry(entry3));
128
129   // entry3 is a child of entry1 now.
130   EXPECT_EQ(FILE_ERROR_NOT_FOUND, storage_->GetChild(key2, name3, &child_id));
131   EXPECT_EQ(FILE_ERROR_OK, storage_->GetChild(key1, name3, &child_id));
132   EXPECT_EQ(key3, child_id);
133
134   // Remove entries.
135   EXPECT_EQ(FILE_ERROR_OK, storage_->RemoveEntry(key3));
136   EXPECT_EQ(FILE_ERROR_NOT_FOUND, storage_->GetEntry(key3, &result));
137   EXPECT_EQ(FILE_ERROR_OK, storage_->RemoveEntry(key2));
138   EXPECT_EQ(FILE_ERROR_NOT_FOUND, storage_->GetEntry(key2, &result));
139   EXPECT_EQ(FILE_ERROR_OK, storage_->RemoveEntry(key1));
140   EXPECT_EQ(FILE_ERROR_NOT_FOUND, storage_->GetEntry(key1, &result));
141 }
142
143 TEST_F(ResourceMetadataStorageTest, Iterator) {
144   // Prepare data.
145   std::vector<std::string> keys;
146
147   keys.push_back("entry1");
148   keys.push_back("entry2");
149   keys.push_back("entry3");
150   keys.push_back("entry4");
151
152   for (size_t i = 0; i < keys.size(); ++i) {
153     ResourceEntry entry;
154     entry.set_local_id(keys[i]);
155     EXPECT_EQ(FILE_ERROR_OK, storage_->PutEntry(entry));
156   }
157
158   // Iterate and check the result.
159   std::map<std::string, ResourceEntry> found_entries;
160   scoped_ptr<ResourceMetadataStorage::Iterator> it = storage_->GetIterator();
161   ASSERT_TRUE(it);
162   for (; !it->IsAtEnd(); it->Advance()) {
163     const ResourceEntry& entry = it->GetValue();
164     found_entries[it->GetID()] = entry;
165   }
166   EXPECT_FALSE(it->HasError());
167
168   EXPECT_EQ(keys.size(), found_entries.size());
169   for (size_t i = 0; i < keys.size(); ++i)
170     EXPECT_EQ(1U, found_entries.count(keys[i]));
171 }
172
173 TEST_F(ResourceMetadataStorageTest, GetIdByResourceId) {
174   const std::string local_id = "local_id";
175   const std::string resource_id = "resource_id";
176
177   // Resource ID to local ID mapping is not stored yet.
178   std::string id;
179   EXPECT_EQ(FILE_ERROR_NOT_FOUND,
180             storage_->GetIdByResourceId(resource_id, &id));
181
182   // Put an entry with the resource ID.
183   ResourceEntry entry;
184   entry.set_local_id(local_id);
185   entry.set_resource_id(resource_id);
186   EXPECT_EQ(FILE_ERROR_OK, storage_->PutEntry(entry));
187
188   // Can get local ID by resource ID.
189   EXPECT_EQ(FILE_ERROR_OK, storage_->GetIdByResourceId(resource_id, &id));
190   EXPECT_EQ(local_id, id);
191
192   // Resource ID to local ID mapping is removed.
193   EXPECT_EQ(FILE_ERROR_OK, storage_->RemoveEntry(local_id));
194   EXPECT_EQ(FILE_ERROR_NOT_FOUND,
195             storage_->GetIdByResourceId(resource_id, &id));
196 }
197
198 TEST_F(ResourceMetadataStorageTest, GetChildren) {
199   const std::string parents_id[] = { "mercury", "venus", "mars", "jupiter",
200                                      "saturn" };
201   std::vector<std::vector<std::pair<std::string, std::string> > >
202       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