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