Upstream version 11.40.271.0
[platform/framework/web/crosswalk.git] / src / sync / internal_api / attachments / on_disk_attachment_store_unittest.cc
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.
4
5 #include "sync/internal_api/public/attachments/on_disk_attachment_store.h"
6
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/gtest/include/gtest/gtest.h"
17 #include "third_party/leveldatabase/src/include/leveldb/db.h"
18 #include "third_party/leveldatabase/src/include/leveldb/options.h"
19 #include "third_party/leveldatabase/src/include/leveldb/slice.h"
20 #include "third_party/leveldatabase/src/include/leveldb/status.h"
21
22 namespace syncer {
23
24 namespace {
25
26 void AttachmentStoreCreated(scoped_refptr<AttachmentStore>* store_dest,
27                             AttachmentStore::Result* result_dest,
28                             const AttachmentStore::Result& result,
29                             const scoped_refptr<AttachmentStore>& store) {
30   *result_dest = result;
31   *store_dest = store;
32 }
33
34 }  // namespace
35
36 // Instantiation of common attachment store tests.
37 class OnDiskAttachmentStoreFactory {
38  public:
39   OnDiskAttachmentStoreFactory() {}
40   ~OnDiskAttachmentStoreFactory() {}
41
42   scoped_refptr<AttachmentStore> CreateAttachmentStore() {
43     EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
44     scoped_refptr<AttachmentStore> store;
45     AttachmentStore::Result result = AttachmentStore::UNSPECIFIED_ERROR;
46     AttachmentStore::CreateOnDiskStore(
47         temp_dir_.path(),
48         base::ThreadTaskRunnerHandle::Get(),
49         base::Bind(&AttachmentStoreCreated, &store, &result));
50     base::RunLoop run_loop;
51     run_loop.RunUntilIdle();
52     EXPECT_EQ(result, AttachmentStore::SUCCESS);
53     return store;
54   }
55
56  private:
57   base::ScopedTempDir temp_dir_;
58 };
59
60 INSTANTIATE_TYPED_TEST_CASE_P(OnDisk,
61                               AttachmentStoreTest,
62                               OnDiskAttachmentStoreFactory);
63
64 // Tests specific to OnDiskAttachmentStore.
65 class OnDiskAttachmentStoreSpecificTest : public testing::Test {
66  public:
67   base::ScopedTempDir temp_dir_;
68   base::MessageLoop message_loop_;
69   scoped_refptr<AttachmentStore> store_;
70
71   OnDiskAttachmentStoreSpecificTest() {}
72
73   void CopyResult(AttachmentStore::Result* destination_result,
74                   const AttachmentStore::Result& source_result) {
75     *destination_result = source_result;
76   }
77
78   void CopyResultAttachments(
79       AttachmentStore::Result* destination_result,
80       const AttachmentStore::Result& source_result,
81       scoped_ptr<AttachmentMap> source_attachments,
82       scoped_ptr<AttachmentIdList> source_failed_attachment_ids) {
83     CopyResult(destination_result, source_result);
84   }
85
86   scoped_ptr<leveldb::DB> OpenLevelDB(const base::FilePath& path) {
87     leveldb::DB* db;
88     leveldb::Options options;
89     options.create_if_missing = true;
90     leveldb::Status s = leveldb::DB::Open(options, path.AsUTF8Unsafe(), &db);
91     EXPECT_TRUE(s.ok());
92     return make_scoped_ptr(db);
93   }
94
95   void UpdateStoreMetadataRecord(const base::FilePath& path,
96                                  const std::string& content) {
97     scoped_ptr<leveldb::DB> db = OpenLevelDB(path);
98     leveldb::Status s =
99         db->Put(leveldb::WriteOptions(), "database-metadata", content);
100     EXPECT_TRUE(s.ok());
101   }
102
103   std::string ReadStoreMetadataRecord(const base::FilePath& path) {
104     scoped_ptr<leveldb::DB> db = OpenLevelDB(path);
105     std::string content;
106     leveldb::Status s =
107         db->Get(leveldb::ReadOptions(), "database-metadata", &content);
108     EXPECT_TRUE(s.ok());
109     return content;
110   }
111
112   void VerifyAttachmentRecordsPresent(const base::FilePath& path,
113                                       const AttachmentId& attachment_id,
114                                       bool expect_records_present) {
115     scoped_ptr<leveldb::DB> db = OpenLevelDB(path);
116
117     std::string metadata_key =
118         OnDiskAttachmentStore::MakeMetadataKeyFromAttachmentId(attachment_id);
119     std::string data_key =
120         OnDiskAttachmentStore::MakeDataKeyFromAttachmentId(attachment_id);
121     std::string data;
122     leveldb::Status s = db->Get(leveldb::ReadOptions(), data_key, &data);
123     if (expect_records_present)
124       EXPECT_TRUE(s.ok());
125     else
126       EXPECT_TRUE(s.IsNotFound());
127     s = db->Get(leveldb::ReadOptions(), metadata_key, &data);
128     if (expect_records_present)
129       EXPECT_TRUE(s.ok());
130     else
131       EXPECT_TRUE(s.IsNotFound());
132   }
133
134   void RunLoop() {
135     base::RunLoop run_loop;
136     run_loop.RunUntilIdle();
137   }
138 };
139
140 // Ensure that store can be closed and reopen while retaining stored
141 // attachments.
142 TEST_F(OnDiskAttachmentStoreSpecificTest, CloseAndReopen) {
143   ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
144   AttachmentStore::Result result;
145
146   result = AttachmentStore::UNSPECIFIED_ERROR;
147   AttachmentStore::CreateOnDiskStore(
148       temp_dir_.path(),
149       base::ThreadTaskRunnerHandle::Get(),
150       base::Bind(&AttachmentStoreCreated, &store_, &result));
151   RunLoop();
152   EXPECT_EQ(result, AttachmentStore::SUCCESS);
153
154   result = AttachmentStore::UNSPECIFIED_ERROR;
155   std::string some_data = "data";
156   Attachment attachment =
157       Attachment::Create(base::RefCountedString::TakeString(&some_data));
158   AttachmentList attachments;
159   attachments.push_back(attachment);
160   store_->Write(attachments,
161                 base::Bind(&OnDiskAttachmentStoreSpecificTest::CopyResult,
162                            base::Unretained(this),
163                            &result));
164   RunLoop();
165   EXPECT_EQ(result, AttachmentStore::SUCCESS);
166
167   // Close attachment store.
168   store_ = nullptr;
169   result = AttachmentStore::UNSPECIFIED_ERROR;
170   AttachmentStore::CreateOnDiskStore(
171       temp_dir_.path(),
172       base::ThreadTaskRunnerHandle::Get(),
173       base::Bind(&AttachmentStoreCreated, &store_, &result));
174   RunLoop();
175   EXPECT_EQ(result, AttachmentStore::SUCCESS);
176
177   result = AttachmentStore::UNSPECIFIED_ERROR;
178   AttachmentIdList attachment_ids;
179   attachment_ids.push_back(attachment.GetId());
180   store_->Read(
181       attachment_ids,
182       base::Bind(&OnDiskAttachmentStoreSpecificTest::CopyResultAttachments,
183                  base::Unretained(this),
184                  &result));
185   RunLoop();
186   EXPECT_EQ(result, AttachmentStore::SUCCESS);
187 }
188
189 // Ensure loading corrupt attachment store fails.
190 TEST_F(OnDiskAttachmentStoreSpecificTest, FailToOpen) {
191   ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
192   base::FilePath db_path =
193       temp_dir_.path().Append(FILE_PATH_LITERAL("leveldb"));
194   base::CreateDirectory(db_path);
195
196   // To simulate corrupt database write empty CURRENT file.
197   std::string current_file_content = "";
198   base::WriteFile(db_path.Append(FILE_PATH_LITERAL("CURRENT")),
199                   current_file_content.c_str(),
200                   current_file_content.size());
201
202   AttachmentStore::Result result = AttachmentStore::SUCCESS;
203   AttachmentStore::CreateOnDiskStore(
204       temp_dir_.path(),
205       base::ThreadTaskRunnerHandle::Get(),
206       base::Bind(&AttachmentStoreCreated, &store_, &result));
207   RunLoop();
208   EXPECT_EQ(result, AttachmentStore::UNSPECIFIED_ERROR);
209   EXPECT_EQ(store_.get(), nullptr);
210 }
211
212 // Ensure that attachment store works correctly when store metadata is missing,
213 // corrupt or has unknown schema version.
214 TEST_F(OnDiskAttachmentStoreSpecificTest, StoreMetadata) {
215   ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
216   base::FilePath db_path =
217       temp_dir_.path().Append(FILE_PATH_LITERAL("leveldb"));
218   base::CreateDirectory(db_path);
219
220   // Create and close empty database.
221   OpenLevelDB(db_path);
222   // Open database with AttachmentStore.
223   AttachmentStore::Result result = AttachmentStore::UNSPECIFIED_ERROR;
224   AttachmentStore::CreateOnDiskStore(
225       temp_dir_.path(),
226       base::ThreadTaskRunnerHandle::Get(),
227       base::Bind(&AttachmentStoreCreated, &store_, &result));
228   RunLoop();
229   EXPECT_EQ(result, AttachmentStore::SUCCESS);
230   // Close AttachmentStore so that test can check content.
231   store_ = nullptr;
232   RunLoop();
233
234   // AttachmentStore should create metadata record.
235   std::string data = ReadStoreMetadataRecord(db_path);
236   attachment_store_pb::StoreMetadata metadata;
237   EXPECT_TRUE(metadata.ParseFromString(data));
238   EXPECT_EQ(metadata.schema_version(), 1);
239
240   // Set unknown future schema version.
241   metadata.set_schema_version(2);
242   data = metadata.SerializeAsString();
243   UpdateStoreMetadataRecord(db_path, data);
244
245   // AttachmentStore should fail to load.
246   result = AttachmentStore::SUCCESS;
247   AttachmentStore::CreateOnDiskStore(
248       temp_dir_.path(),
249       base::ThreadTaskRunnerHandle::Get(),
250       base::Bind(&AttachmentStoreCreated, &store_, &result));
251   RunLoop();
252   EXPECT_EQ(result, AttachmentStore::UNSPECIFIED_ERROR);
253   EXPECT_EQ(store_.get(), nullptr);
254
255   // Write garbage into metadata record.
256   UpdateStoreMetadataRecord(db_path, "abra.cadabra");
257
258   // AttachmentStore should fail to load.
259   result = AttachmentStore::SUCCESS;
260   AttachmentStore::CreateOnDiskStore(
261       temp_dir_.path(),
262       base::ThreadTaskRunnerHandle::Get(),
263       base::Bind(&AttachmentStoreCreated, &store_, &result));
264   RunLoop();
265   EXPECT_EQ(result, AttachmentStore::UNSPECIFIED_ERROR);
266   EXPECT_EQ(store_.get(), nullptr);
267 }
268
269 TEST_F(OnDiskAttachmentStoreSpecificTest, RecordMetadata) {
270   ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
271   base::FilePath db_path =
272       temp_dir_.path().Append(FILE_PATH_LITERAL("leveldb"));
273
274   // Create attachment store.
275   AttachmentStore::Result result = AttachmentStore::UNSPECIFIED_ERROR;
276   AttachmentStore::CreateOnDiskStore(
277       temp_dir_.path(),
278       base::ThreadTaskRunnerHandle::Get(),
279       base::Bind(&AttachmentStoreCreated, &store_, &result));
280   RunLoop();
281   EXPECT_EQ(result, AttachmentStore::SUCCESS);
282
283   // Write two attachments.
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),
295                            &result));
296   RunLoop();
297   EXPECT_EQ(result, AttachmentStore::SUCCESS);
298
299   // Delete one of written attachments.
300   AttachmentIdList attachment_ids;
301   attachment_ids.push_back(attachments[0].GetId());
302   store_->Drop(attachment_ids,
303                base::Bind(&OnDiskAttachmentStoreSpecificTest::CopyResult,
304                           base::Unretained(this),
305                           &result));
306   RunLoop();
307   EXPECT_EQ(result, AttachmentStore::SUCCESS);
308   store_ = nullptr;
309   RunLoop();
310
311   // Verify that attachment store contains only records for second attachment.
312   VerifyAttachmentRecordsPresent(db_path, attachments[0].GetId(), false);
313   VerifyAttachmentRecordsPresent(db_path, attachments[1].GetId(), true);
314 }
315
316 }  // namespace syncer