Delete chrome.mediaGalleriesPrivate because the functionality unique to it has since...
[chromium-blink-merge.git] / sync / internal_api / attachments / on_disk_attachment_store_unittest.cc
blobe46f060216094041516edca0248e1a323c4f1dab
1 // Copyright 2014 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 "sync/internal_api/public/attachments/on_disk_attachment_store.h"
7 #include "base/files/file_path.h"
8 #include "base/files/file_util.h"
9 #include "base/files/scoped_temp_dir.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/run_loop.h"
12 #include "base/thread_task_runner_handle.h"
13 #include "base/time/time.h"
14 #include "sync/internal_api/attachments/attachment_store_test_template.h"
15 #include "sync/internal_api/attachments/proto/attachment_store.pb.h"
16 #include "testing/gmock/include/gmock/gmock.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/options.h"
20 #include "third_party/leveldatabase/src/include/leveldb/slice.h"
21 #include "third_party/leveldatabase/src/include/leveldb/status.h"
23 namespace syncer {
25 namespace {
27 void AttachmentStoreCreated(AttachmentStore::Result* result_dest,
28 const AttachmentStore::Result& result) {
29 *result_dest = result;
32 } // namespace
34 // Instantiation of common attachment store tests.
35 class OnDiskAttachmentStoreFactory {
36 public:
37 OnDiskAttachmentStoreFactory() {}
38 ~OnDiskAttachmentStoreFactory() {}
40 scoped_refptr<AttachmentStore> CreateAttachmentStore() {
41 EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
42 scoped_refptr<AttachmentStore> store;
43 AttachmentStore::Result result = AttachmentStore::UNSPECIFIED_ERROR;
44 store = AttachmentStore::CreateOnDiskStore(
45 temp_dir_.path(), base::ThreadTaskRunnerHandle::Get(),
46 base::Bind(&AttachmentStoreCreated, &result));
47 base::RunLoop run_loop;
48 run_loop.RunUntilIdle();
49 EXPECT_EQ(AttachmentStore::SUCCESS, result);
50 return store;
53 private:
54 base::ScopedTempDir temp_dir_;
57 INSTANTIATE_TYPED_TEST_CASE_P(OnDisk,
58 AttachmentStoreTest,
59 OnDiskAttachmentStoreFactory);
61 // Tests specific to OnDiskAttachmentStore.
62 class OnDiskAttachmentStoreSpecificTest : public testing::Test {
63 public:
64 base::ScopedTempDir temp_dir_;
65 base::FilePath db_path_;
66 base::MessageLoop message_loop_;
67 scoped_refptr<AttachmentStore> store_;
69 OnDiskAttachmentStoreSpecificTest() {}
71 void SetUp() override {
72 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
73 db_path_ = temp_dir_.path().Append(FILE_PATH_LITERAL("leveldb"));
74 base::CreateDirectory(db_path_);
77 void CopyResult(AttachmentStore::Result* destination_result,
78 const AttachmentStore::Result& source_result) {
79 *destination_result = source_result;
82 void CopyResultAttachments(
83 AttachmentStore::Result* destination_result,
84 AttachmentIdList* destination_failed_attachment_ids,
85 const AttachmentStore::Result& source_result,
86 scoped_ptr<AttachmentMap> source_attachments,
87 scoped_ptr<AttachmentIdList> source_failed_attachment_ids) {
88 CopyResult(destination_result, source_result);
89 *destination_failed_attachment_ids = *source_failed_attachment_ids;
92 void CopyResultMetadata(
93 AttachmentStore::Result* destination_result,
94 scoped_ptr<AttachmentMetadataList>* destination_metadata,
95 const AttachmentStore::Result& source_result,
96 scoped_ptr<AttachmentMetadataList> source_metadata) {
97 CopyResult(destination_result, source_result);
98 *destination_metadata = source_metadata.Pass();
101 scoped_ptr<leveldb::DB> OpenLevelDB() {
102 leveldb::DB* db;
103 leveldb::Options options;
104 options.create_if_missing = true;
105 leveldb::Status s =
106 leveldb::DB::Open(options, db_path_.AsUTF8Unsafe(), &db);
107 EXPECT_TRUE(s.ok());
108 return make_scoped_ptr(db);
111 void UpdateRecord(const std::string& key, const std::string& content) {
112 scoped_ptr<leveldb::DB> db = OpenLevelDB();
113 leveldb::Status s = db->Put(leveldb::WriteOptions(), key, content);
114 EXPECT_TRUE(s.ok());
117 void UpdateStoreMetadataRecord(const std::string& content) {
118 UpdateRecord("database-metadata", content);
121 void UpdateAttachmentMetadataRecord(const AttachmentId& attachment_id,
122 const std::string& content) {
123 std::string metadata_key =
124 OnDiskAttachmentStore::MakeMetadataKeyFromAttachmentId(attachment_id);
125 UpdateRecord(metadata_key, content);
128 std::string ReadStoreMetadataRecord() {
129 scoped_ptr<leveldb::DB> db = OpenLevelDB();
130 std::string content;
131 leveldb::Status s =
132 db->Get(leveldb::ReadOptions(), "database-metadata", &content);
133 EXPECT_TRUE(s.ok());
134 return content;
137 void VerifyAttachmentRecordsPresent(const AttachmentId& attachment_id,
138 bool expect_records_present) {
139 scoped_ptr<leveldb::DB> db = OpenLevelDB();
141 std::string metadata_key =
142 OnDiskAttachmentStore::MakeMetadataKeyFromAttachmentId(attachment_id);
143 std::string data_key =
144 OnDiskAttachmentStore::MakeDataKeyFromAttachmentId(attachment_id);
145 std::string data;
146 leveldb::Status s = db->Get(leveldb::ReadOptions(), data_key, &data);
147 if (expect_records_present)
148 EXPECT_TRUE(s.ok());
149 else
150 EXPECT_TRUE(s.IsNotFound());
151 s = db->Get(leveldb::ReadOptions(), metadata_key, &data);
152 if (expect_records_present)
153 EXPECT_TRUE(s.ok());
154 else
155 EXPECT_TRUE(s.IsNotFound());
158 void RunLoop() {
159 base::RunLoop run_loop;
160 run_loop.RunUntilIdle();
164 // Ensure that store can be closed and reopen while retaining stored
165 // attachments.
166 TEST_F(OnDiskAttachmentStoreSpecificTest, CloseAndReopen) {
167 AttachmentStore::Result result;
169 result = AttachmentStore::UNSPECIFIED_ERROR;
170 store_ = AttachmentStore::CreateOnDiskStore(
171 temp_dir_.path(), base::ThreadTaskRunnerHandle::Get(),
172 base::Bind(&AttachmentStoreCreated, &result));
173 RunLoop();
174 EXPECT_EQ(AttachmentStore::SUCCESS, result);
176 result = AttachmentStore::UNSPECIFIED_ERROR;
177 std::string some_data = "data";
178 Attachment attachment =
179 Attachment::Create(base::RefCountedString::TakeString(&some_data));
180 AttachmentList attachments;
181 attachments.push_back(attachment);
182 store_->Write(attachments,
183 base::Bind(&OnDiskAttachmentStoreSpecificTest::CopyResult,
184 base::Unretained(this),
185 &result));
186 RunLoop();
187 EXPECT_EQ(AttachmentStore::SUCCESS, result);
189 // Close and reopen attachment store.
190 store_ = nullptr;
191 result = AttachmentStore::UNSPECIFIED_ERROR;
192 store_ = AttachmentStore::CreateOnDiskStore(
193 temp_dir_.path(), base::ThreadTaskRunnerHandle::Get(),
194 base::Bind(&AttachmentStoreCreated, &result));
195 RunLoop();
196 EXPECT_EQ(AttachmentStore::SUCCESS, result);
198 result = AttachmentStore::UNSPECIFIED_ERROR;
199 AttachmentIdList attachment_ids;
200 attachment_ids.push_back(attachment.GetId());
201 AttachmentIdList failed_attachment_ids;
202 store_->Read(
203 attachment_ids,
204 base::Bind(&OnDiskAttachmentStoreSpecificTest::CopyResultAttachments,
205 base::Unretained(this), &result, &failed_attachment_ids));
206 RunLoop();
207 EXPECT_EQ(AttachmentStore::SUCCESS, result);
208 EXPECT_TRUE(failed_attachment_ids.empty());
211 // Ensure loading corrupt attachment store fails.
212 TEST_F(OnDiskAttachmentStoreSpecificTest, FailToOpen) {
213 // To simulate corrupt database write empty CURRENT file.
214 std::string current_file_content = "";
215 base::WriteFile(db_path_.Append(FILE_PATH_LITERAL("CURRENT")),
216 current_file_content.c_str(), current_file_content.size());
218 AttachmentStore::Result result = AttachmentStore::SUCCESS;
219 store_ = AttachmentStore::CreateOnDiskStore(
220 temp_dir_.path(), base::ThreadTaskRunnerHandle::Get(),
221 base::Bind(&AttachmentStoreCreated, &result));
222 RunLoop();
223 EXPECT_EQ(AttachmentStore::UNSPECIFIED_ERROR, result);
226 // Ensure that attachment store works correctly when store metadata is missing,
227 // corrupt or has unknown schema version.
228 TEST_F(OnDiskAttachmentStoreSpecificTest, StoreMetadata) {
229 // Create and close empty database.
230 OpenLevelDB();
231 // Open database with AttachmentStore.
232 AttachmentStore::Result result = AttachmentStore::UNSPECIFIED_ERROR;
233 store_ = AttachmentStore::CreateOnDiskStore(
234 temp_dir_.path(), base::ThreadTaskRunnerHandle::Get(),
235 base::Bind(&AttachmentStoreCreated, &result));
236 RunLoop();
237 EXPECT_EQ(AttachmentStore::SUCCESS, result);
238 // Close AttachmentStore so that test can check content.
239 store_ = nullptr;
240 RunLoop();
242 // AttachmentStore should create metadata record.
243 std::string data = ReadStoreMetadataRecord();
244 attachment_store_pb::StoreMetadata metadata;
245 EXPECT_TRUE(metadata.ParseFromString(data));
246 EXPECT_EQ(1, metadata.schema_version());
248 // Set unknown future schema version.
249 metadata.set_schema_version(2);
250 data = metadata.SerializeAsString();
251 UpdateStoreMetadataRecord(data);
253 // AttachmentStore should fail to load.
254 result = AttachmentStore::SUCCESS;
255 store_ = AttachmentStore::CreateOnDiskStore(
256 temp_dir_.path(), base::ThreadTaskRunnerHandle::Get(),
257 base::Bind(&AttachmentStoreCreated, &result));
258 RunLoop();
259 EXPECT_EQ(AttachmentStore::UNSPECIFIED_ERROR, result);
261 // Write garbage into metadata record.
262 UpdateStoreMetadataRecord("abra.cadabra");
264 // AttachmentStore should fail to load.
265 result = AttachmentStore::SUCCESS;
266 store_ = AttachmentStore::CreateOnDiskStore(
267 temp_dir_.path(), base::ThreadTaskRunnerHandle::Get(),
268 base::Bind(&AttachmentStoreCreated, &result));
269 RunLoop();
270 EXPECT_EQ(AttachmentStore::UNSPECIFIED_ERROR, result);
273 // Ensure that attachment store correctly maintains metadata records for
274 // attachments.
275 TEST_F(OnDiskAttachmentStoreSpecificTest, RecordMetadata) {
276 // Create attachment store.
277 AttachmentStore::Result create_result = AttachmentStore::UNSPECIFIED_ERROR;
278 store_ = AttachmentStore::CreateOnDiskStore(
279 temp_dir_.path(), base::ThreadTaskRunnerHandle::Get(),
280 base::Bind(&AttachmentStoreCreated, &create_result));
282 // Write two attachments.
283 AttachmentStore::Result write_result = AttachmentStore::UNSPECIFIED_ERROR;
284 std::string some_data;
285 AttachmentList attachments;
286 some_data = "data1";
287 attachments.push_back(
288 Attachment::Create(base::RefCountedString::TakeString(&some_data)));
289 some_data = "data2";
290 attachments.push_back(
291 Attachment::Create(base::RefCountedString::TakeString(&some_data)));
292 store_->Write(attachments,
293 base::Bind(&OnDiskAttachmentStoreSpecificTest::CopyResult,
294 base::Unretained(this), &write_result));
296 // Delete one of written attachments.
297 AttachmentStore::Result drop_result = AttachmentStore::UNSPECIFIED_ERROR;
298 AttachmentIdList attachment_ids;
299 attachment_ids.push_back(attachments[0].GetId());
300 store_->Drop(attachment_ids,
301 base::Bind(&OnDiskAttachmentStoreSpecificTest::CopyResult,
302 base::Unretained(this), &drop_result));
303 store_ = nullptr;
304 RunLoop();
305 EXPECT_EQ(AttachmentStore::SUCCESS, create_result);
306 EXPECT_EQ(AttachmentStore::SUCCESS, write_result);
307 EXPECT_EQ(AttachmentStore::SUCCESS, drop_result);
309 // Verify that attachment store contains only records for second attachment.
310 VerifyAttachmentRecordsPresent(attachments[0].GetId(), false);
311 VerifyAttachmentRecordsPresent(attachments[1].GetId(), true);
314 // Ensure that attachment store fails to load attachment with mismatched crc.
315 TEST_F(OnDiskAttachmentStoreSpecificTest, MismatchedCrc) {
316 // Create attachment store.
317 AttachmentStore::Result create_result = AttachmentStore::UNSPECIFIED_ERROR;
318 store_ = AttachmentStore::CreateOnDiskStore(
319 temp_dir_.path(), base::ThreadTaskRunnerHandle::Get(),
320 base::Bind(&AttachmentStoreCreated, &create_result));
322 // Write attachment with incorrect crc32c.
323 AttachmentStore::Result write_result = AttachmentStore::UNSPECIFIED_ERROR;
324 const uint32_t intentionally_wrong_crc32c = 0;
325 std::string some_data("data1");
326 Attachment attachment = Attachment::CreateFromParts(
327 AttachmentId::Create(), base::RefCountedString::TakeString(&some_data),
328 intentionally_wrong_crc32c);
329 AttachmentList attachments;
330 attachments.push_back(attachment);
331 store_->Write(attachments,
332 base::Bind(&OnDiskAttachmentStoreSpecificTest::CopyResult,
333 base::Unretained(this), &write_result));
335 // Read attachment.
336 AttachmentStore::Result read_result = AttachmentStore::UNSPECIFIED_ERROR;
337 AttachmentIdList attachment_ids;
338 attachment_ids.push_back(attachment.GetId());
339 AttachmentIdList failed_attachment_ids;
340 store_->Read(
341 attachment_ids,
342 base::Bind(&OnDiskAttachmentStoreSpecificTest::CopyResultAttachments,
343 base::Unretained(this), &read_result, &failed_attachment_ids));
344 RunLoop();
345 EXPECT_EQ(AttachmentStore::SUCCESS, create_result);
346 EXPECT_EQ(AttachmentStore::SUCCESS, write_result);
347 EXPECT_EQ(AttachmentStore::UNSPECIFIED_ERROR, read_result);
348 EXPECT_THAT(failed_attachment_ids, testing::ElementsAre(attachment.GetId()));
351 // Ensure that after store initialization failure ReadWrite/Drop operations fail
352 // with correct error.
353 TEST_F(OnDiskAttachmentStoreSpecificTest, OpsAfterInitializationFailed) {
354 // To simulate corrupt database write empty CURRENT file.
355 std::string current_file_content = "";
356 base::WriteFile(db_path_.Append(FILE_PATH_LITERAL("CURRENT")),
357 current_file_content.c_str(), current_file_content.size());
359 AttachmentStore::Result create_result = AttachmentStore::SUCCESS;
360 store_ = AttachmentStore::CreateOnDiskStore(
361 temp_dir_.path(), base::ThreadTaskRunnerHandle::Get(),
362 base::Bind(&AttachmentStoreCreated, &create_result));
364 // Reading from uninitialized store should result in
365 // STORE_INITIALIZATION_FAILED.
366 AttachmentStore::Result read_result = AttachmentStore::SUCCESS;
367 AttachmentIdList attachment_ids;
368 attachment_ids.push_back(AttachmentId::Create());
369 AttachmentIdList failed_attachment_ids;
370 store_->Read(
371 attachment_ids,
372 base::Bind(&OnDiskAttachmentStoreSpecificTest::CopyResultAttachments,
373 base::Unretained(this), &read_result, &failed_attachment_ids));
375 // Dropping from uninitialized store should result in
376 // STORE_INITIALIZATION_FAILED.
377 AttachmentStore::Result drop_result = AttachmentStore::SUCCESS;
378 store_->Drop(attachment_ids,
379 base::Bind(&OnDiskAttachmentStoreSpecificTest::CopyResult,
380 base::Unretained(this), &drop_result));
382 // Writing to uninitialized store should result in
383 // STORE_INITIALIZATION_FAILED.
384 AttachmentStore::Result write_result = AttachmentStore::SUCCESS;
385 std::string some_data;
386 AttachmentList attachments;
387 some_data = "data1";
388 attachments.push_back(
389 Attachment::Create(base::RefCountedString::TakeString(&some_data)));
390 store_->Write(attachments,
391 base::Bind(&OnDiskAttachmentStoreSpecificTest::CopyResult,
392 base::Unretained(this), &write_result));
394 RunLoop();
395 EXPECT_EQ(AttachmentStore::UNSPECIFIED_ERROR, create_result);
396 EXPECT_EQ(AttachmentStore::STORE_INITIALIZATION_FAILED, read_result);
397 EXPECT_THAT(failed_attachment_ids, testing::ElementsAre(attachment_ids[0]));
398 EXPECT_EQ(AttachmentStore::STORE_INITIALIZATION_FAILED, drop_result);
399 EXPECT_EQ(AttachmentStore::STORE_INITIALIZATION_FAILED, write_result);
402 // Ensure that attachment store handles the case of having an unexpected
403 // record at the end without crashing.
404 TEST_F(OnDiskAttachmentStoreSpecificTest, ReadAllMetadataWithUnexpectedRecord) {
405 // Write a bogus entry at the end of the database.
406 UpdateRecord("zzz", "foobar");
408 // Create attachment store.
409 AttachmentStore::Result create_result = AttachmentStore::UNSPECIFIED_ERROR;
410 store_ = AttachmentStore::CreateOnDiskStore(
411 temp_dir_.path(), base::ThreadTaskRunnerHandle::Get(),
412 base::Bind(&AttachmentStoreCreated, &create_result));
414 // Read all metadata. Should be getting no error and zero entries.
415 AttachmentStore::Result metadata_result = AttachmentStore::UNSPECIFIED_ERROR;
416 scoped_ptr<AttachmentMetadataList> metadata_list;
417 store_->ReadAllMetadata(
418 base::Bind(&OnDiskAttachmentStoreSpecificTest::CopyResultMetadata,
419 base::Unretained(this), &metadata_result, &metadata_list));
420 RunLoop();
421 EXPECT_EQ(AttachmentStore::SUCCESS, create_result);
422 EXPECT_EQ(AttachmentStore::SUCCESS, metadata_result);
423 EXPECT_EQ(0U, metadata_list->size());
424 metadata_list.reset();
426 // Write 3 attachments to the store
427 AttachmentList attachments;
429 for (int i = 0; i < 3; i++) {
430 std::string some_data = "data";
431 Attachment attachment =
432 Attachment::Create(base::RefCountedString::TakeString(&some_data));
433 attachments.push_back(attachment);
435 AttachmentStore::Result write_result = AttachmentStore::UNSPECIFIED_ERROR;
436 store_->Write(attachments,
437 base::Bind(&OnDiskAttachmentStoreSpecificTest::CopyResult,
438 base::Unretained(this), &write_result));
440 // Read all metadata back. We should be getting 3 entries.
441 store_->ReadAllMetadata(
442 base::Bind(&OnDiskAttachmentStoreSpecificTest::CopyResultMetadata,
443 base::Unretained(this), &metadata_result, &metadata_list));
444 RunLoop();
445 EXPECT_EQ(AttachmentStore::SUCCESS, write_result);
446 EXPECT_EQ(AttachmentStore::SUCCESS, metadata_result);
447 EXPECT_EQ(3U, metadata_list->size());
448 // Get Id of the attachment in the middle.
449 AttachmentId id = (*metadata_list.get())[1].GetId();
450 metadata_list.reset();
452 // Close the store.
453 store_ = nullptr;
454 RunLoop();
456 // Modify the middle attachment metadata entry so that it isn't valid anymore.
457 UpdateAttachmentMetadataRecord(id, "foobar");
459 // Reopen the store.
460 create_result = AttachmentStore::UNSPECIFIED_ERROR;
461 metadata_result = AttachmentStore::UNSPECIFIED_ERROR;
462 store_ = AttachmentStore::CreateOnDiskStore(
463 temp_dir_.path(), base::ThreadTaskRunnerHandle::Get(),
464 base::Bind(&AttachmentStoreCreated, &create_result));
466 // Read all metadata back. We should be getting a failure and
467 // only 2 entries now.
468 store_->ReadAllMetadata(
469 base::Bind(&OnDiskAttachmentStoreSpecificTest::CopyResultMetadata,
470 base::Unretained(this), &metadata_result, &metadata_list));
471 RunLoop();
472 EXPECT_EQ(AttachmentStore::SUCCESS, create_result);
473 EXPECT_EQ(AttachmentStore::UNSPECIFIED_ERROR, metadata_result);
474 EXPECT_EQ(2U, metadata_list->size());
477 } // namespace syncer