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 #ifndef SYNC_INTERNAL_API_ATTACHMENTS_ATTACHMENT_STORE_TEST_TEMPLATE_H_
6 #define SYNC_INTERNAL_API_ATTACHMENTS_ATTACHMENT_STORE_TEST_TEMPLATE_H_
8 #include "sync/api/attachments/attachment_store.h"
10 #include "base/bind.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/memory/ref_counted_memory.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/thread_task_runner_handle.h"
16 #include "sync/api/attachments/attachment.h"
17 #include "sync/internal_api/public/attachments/attachment_util.h"
18 #include "sync/protocol/sync.pb.h"
19 #include "testing/gmock/include/gmock/gmock-matchers.h"
20 #include "testing/gtest/include/gtest/gtest.h"
22 // AttachmentStoreTest defines tests for AttachmentStore. To instantiate these
23 // tests for a particular implementation you need to:
24 // - Include this file in test.
25 // - Create factory class for attachment store that implements factory method.
26 // - add INSTANTIATE_TYPED_TEST_CASE_P statement.
27 // Here is how to do it for MyAttachmentStore:
29 // class MyAttachmentStoreFactory {
31 // scoped_refptr<AttachmentStore> CreateAttachmentStore() {
32 // return new MyAttachmentStore();
36 // INSTANTIATE_TYPED_TEST_CASE_P(My,
37 // AttachmentStoreTest,
38 // MyAttachmentStoreFactory);
42 const char kTestData1
[] = "test data 1";
43 const char kTestData2
[] = "test data 2";
45 template <typename AttachmentStoreFactory
>
46 class AttachmentStoreTest
: public testing::Test
{
48 AttachmentStoreFactory attachment_store_factory
;
49 base::MessageLoop message_loop
;
50 scoped_refptr
<AttachmentStore
> store
;
51 AttachmentStore::Result result
;
52 scoped_ptr
<AttachmentMap
> attachments
;
53 scoped_ptr
<AttachmentIdList
> failed_attachment_ids
;
54 scoped_ptr
<AttachmentMetadataList
> attachment_metadata
;
56 AttachmentStore::ReadCallback read_callback
;
57 AttachmentStore::WriteCallback write_callback
;
58 AttachmentStore::DropCallback drop_callback
;
59 AttachmentStore::ReadMetadataCallback read_metadata_callback
;
61 scoped_refptr
<base::RefCountedString
> some_data1
;
62 scoped_refptr
<base::RefCountedString
> some_data2
;
64 AttachmentStoreTest() {}
66 void SetUp() override
{
67 store
= attachment_store_factory
.CreateAttachmentStore();
70 read_callback
= base::Bind(&AttachmentStoreTest::CopyResultAttachments
,
71 base::Unretained(this),
74 &failed_attachment_ids
);
75 write_callback
= base::Bind(
76 &AttachmentStoreTest::CopyResult
, base::Unretained(this), &result
);
77 drop_callback
= write_callback
;
78 read_metadata_callback
=
79 base::Bind(&AttachmentStoreTest::CopyResultMetadata
,
80 base::Unretained(this), &result
, &attachment_metadata
);
82 some_data1
= new base::RefCountedString
;
83 some_data1
->data() = kTestData1
;
85 some_data2
= new base::RefCountedString
;
86 some_data2
->data() = kTestData2
;
89 void ClearAndPumpLoop() {
91 message_loop
.RunUntilIdle();
96 result
= AttachmentStore::UNSPECIFIED_ERROR
;
98 failed_attachment_ids
.reset();
99 attachment_metadata
.reset();
102 void CopyResult(AttachmentStore::Result
* destination_result
,
103 const AttachmentStore::Result
& source_result
) {
104 *destination_result
= source_result
;
107 void CopyResultAttachments(
108 AttachmentStore::Result
* destination_result
,
109 scoped_ptr
<AttachmentMap
>* destination_attachments
,
110 scoped_ptr
<AttachmentIdList
>* destination_failed_attachment_ids
,
111 const AttachmentStore::Result
& source_result
,
112 scoped_ptr
<AttachmentMap
> source_attachments
,
113 scoped_ptr
<AttachmentIdList
> source_failed_attachment_ids
) {
114 CopyResult(destination_result
, source_result
);
115 *destination_attachments
= source_attachments
.Pass();
116 *destination_failed_attachment_ids
= source_failed_attachment_ids
.Pass();
119 void CopyResultMetadata(
120 AttachmentStore::Result
* destination_result
,
121 scoped_ptr
<AttachmentMetadataList
>* destination_metadata
,
122 const AttachmentStore::Result
& source_result
,
123 scoped_ptr
<AttachmentMetadataList
> source_metadata
) {
124 CopyResult(destination_result
, source_result
);
125 *destination_metadata
= source_metadata
.Pass();
129 TYPED_TEST_CASE_P(AttachmentStoreTest
);
131 // Verify that we do not overwrite existing attachments and that we do not treat
133 TYPED_TEST_P(AttachmentStoreTest
, Write_NoOverwriteNoError
) {
134 // Create two attachments with the same id but different data.
135 Attachment attachment1
= Attachment::Create(this->some_data1
);
136 uint32_t crc32c
= ComputeCrc32c(this->some_data2
);
137 Attachment attachment2
= Attachment::CreateFromParts(
138 attachment1
.GetId(), this->some_data2
, crc32c
);
140 // Write the first one.
141 AttachmentList some_attachments
;
142 some_attachments
.push_back(attachment1
);
143 this->store
->Write(some_attachments
, this->write_callback
);
144 this->ClearAndPumpLoop();
145 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
147 // Write the second one.
148 some_attachments
.clear();
149 some_attachments
.push_back(attachment2
);
150 this->store
->Write(some_attachments
, this->write_callback
);
151 this->ClearAndPumpLoop();
152 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
154 // Read it back and see that it was not overwritten.
155 AttachmentIdList some_attachment_ids
;
156 some_attachment_ids
.push_back(attachment1
.GetId());
157 this->store
->Read(some_attachment_ids
, this->read_callback
);
158 this->ClearAndPumpLoop();
159 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
160 EXPECT_EQ(1U, this->attachments
->size());
161 EXPECT_EQ(0U, this->failed_attachment_ids
->size());
162 AttachmentMap::const_iterator a1
=
163 this->attachments
->find(attachment1
.GetId());
164 EXPECT_TRUE(a1
!= this->attachments
->end());
165 EXPECT_TRUE(attachment1
.GetData()->Equals(a1
->second
.GetData()));
168 // Verify that we can write some attachments and read them back.
169 TYPED_TEST_P(AttachmentStoreTest
, Write_RoundTrip
) {
170 Attachment attachment1
= Attachment::Create(this->some_data1
);
171 Attachment attachment2
= Attachment::Create(this->some_data2
);
172 AttachmentList some_attachments
;
173 some_attachments
.push_back(attachment1
);
174 some_attachments
.push_back(attachment2
);
176 this->store
->Write(some_attachments
, this->write_callback
);
177 this->ClearAndPumpLoop();
178 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
180 AttachmentIdList some_attachment_ids
;
181 some_attachment_ids
.push_back(attachment1
.GetId());
182 some_attachment_ids
.push_back(attachment2
.GetId());
183 this->store
->Read(some_attachment_ids
, this->read_callback
);
184 this->ClearAndPumpLoop();
185 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
186 EXPECT_EQ(2U, this->attachments
->size());
187 EXPECT_EQ(0U, this->failed_attachment_ids
->size());
189 AttachmentMap::const_iterator a1
=
190 this->attachments
->find(attachment1
.GetId());
191 EXPECT_TRUE(a1
!= this->attachments
->end());
192 EXPECT_TRUE(attachment1
.GetData()->Equals(a1
->second
.GetData()));
194 AttachmentMap::const_iterator a2
=
195 this->attachments
->find(attachment2
.GetId());
196 EXPECT_TRUE(a2
!= this->attachments
->end());
197 EXPECT_TRUE(attachment2
.GetData()->Equals(a2
->second
.GetData()));
200 // Try to read two attachments when only one exists.
201 TYPED_TEST_P(AttachmentStoreTest
, Read_OneNotFound
) {
202 Attachment attachment1
= Attachment::Create(this->some_data1
);
203 Attachment attachment2
= Attachment::Create(this->some_data2
);
205 AttachmentList some_attachments
;
206 // Write attachment1 only.
207 some_attachments
.push_back(attachment1
);
208 this->store
->Write(some_attachments
, this->write_callback
);
209 this->ClearAndPumpLoop();
210 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
212 // Try to read both attachment1 and attachment2.
213 AttachmentIdList ids
;
214 ids
.push_back(attachment1
.GetId());
215 ids
.push_back(attachment2
.GetId());
216 this->store
->Read(ids
, this->read_callback
);
217 this->ClearAndPumpLoop();
219 // See that only attachment1 was read.
220 EXPECT_EQ(AttachmentStore::UNSPECIFIED_ERROR
, this->result
);
221 EXPECT_EQ(1U, this->attachments
->size());
222 EXPECT_EQ(1U, this->failed_attachment_ids
->size());
225 // Try to drop two attachments when only one exists. Verify that no error occurs
226 // and that the existing attachment was dropped.
227 TYPED_TEST_P(AttachmentStoreTest
, Drop_DropTwoButOnlyOneExists
) {
228 // First, create two attachments.
229 Attachment attachment1
= Attachment::Create(this->some_data1
);
230 Attachment attachment2
= Attachment::Create(this->some_data2
);
231 AttachmentList some_attachments
;
232 some_attachments
.push_back(attachment1
);
233 some_attachments
.push_back(attachment2
);
234 this->store
->Write(some_attachments
, this->write_callback
);
235 this->ClearAndPumpLoop();
236 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
238 // Drop attachment1 only.
239 AttachmentIdList ids
;
240 ids
.push_back(attachment1
.GetId());
241 this->store
->Drop(ids
, this->drop_callback
);
242 this->ClearAndPumpLoop();
243 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
245 // See that attachment1 is gone.
246 this->store
->Read(ids
, this->read_callback
);
247 this->ClearAndPumpLoop();
248 EXPECT_EQ(AttachmentStore::UNSPECIFIED_ERROR
, this->result
);
249 EXPECT_EQ(0U, this->attachments
->size());
250 EXPECT_EQ(1U, this->failed_attachment_ids
->size());
251 EXPECT_EQ(attachment1
.GetId(), (*this->failed_attachment_ids
)[0]);
253 // Drop both attachment1 and attachment2.
255 ids
.push_back(attachment1
.GetId());
256 ids
.push_back(attachment2
.GetId());
257 this->store
->Drop(ids
, this->drop_callback
);
258 this->ClearAndPumpLoop();
259 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
261 // See that attachment2 is now gone.
263 ids
.push_back(attachment2
.GetId());
264 this->store
->Read(ids
, this->read_callback
);
265 this->ClearAndPumpLoop();
266 EXPECT_EQ(AttachmentStore::UNSPECIFIED_ERROR
, this->result
);
267 EXPECT_EQ(0U, this->attachments
->size());
268 EXPECT_EQ(1U, this->failed_attachment_ids
->size());
269 EXPECT_EQ(attachment2
.GetId(), (*this->failed_attachment_ids
)[0]);
272 // Verify that attempting to drop an attachment that does not exist is not an
274 TYPED_TEST_P(AttachmentStoreTest
, Drop_DoesNotExist
) {
275 Attachment attachment1
= Attachment::Create(this->some_data1
);
276 AttachmentList some_attachments
;
277 some_attachments
.push_back(attachment1
);
278 this->store
->Write(some_attachments
, this->write_callback
);
279 this->ClearAndPumpLoop();
280 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
282 // Drop the attachment.
283 AttachmentIdList ids
;
284 ids
.push_back(attachment1
.GetId());
285 this->store
->Drop(ids
, this->drop_callback
);
286 this->ClearAndPumpLoop();
287 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
289 // See that it's gone.
290 this->store
->Read(ids
, this->read_callback
);
291 this->ClearAndPumpLoop();
292 EXPECT_EQ(AttachmentStore::UNSPECIFIED_ERROR
, this->result
);
293 EXPECT_EQ(0U, this->attachments
->size());
294 EXPECT_EQ(1U, this->failed_attachment_ids
->size());
295 EXPECT_EQ(attachment1
.GetId(), (*this->failed_attachment_ids
)[0]);
297 // Drop again, see that no error occurs.
299 ids
.push_back(attachment1
.GetId());
300 this->store
->Drop(ids
, this->drop_callback
);
301 this->ClearAndPumpLoop();
302 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
305 // Verify getting metadata for specific attachments.
306 TYPED_TEST_P(AttachmentStoreTest
, ReadMetadata
) {
307 Attachment attachment1
= Attachment::Create(this->some_data1
);
308 Attachment attachment2
= Attachment::Create(this->some_data2
);
310 AttachmentList some_attachments
;
311 // Write attachment1 only.
312 some_attachments
.push_back(attachment1
);
313 this->store
->Write(some_attachments
, this->write_callback
);
314 this->ClearAndPumpLoop();
315 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
317 // Try to read metadata for both attachment1 and attachment2.
318 AttachmentIdList ids
;
319 ids
.push_back(attachment1
.GetId());
320 ids
.push_back(attachment2
.GetId());
321 this->store
->ReadMetadata(ids
, this->read_metadata_callback
);
322 this->ClearAndPumpLoop();
324 // See that only one entry was read.
325 EXPECT_EQ(AttachmentStore::UNSPECIFIED_ERROR
, this->result
);
326 EXPECT_EQ(1U, this->attachment_metadata
->size());
328 // Now write attachment2.
329 some_attachments
[0] = attachment2
;
330 this->store
->Write(some_attachments
, this->write_callback
);
331 this->ClearAndPumpLoop();
332 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
334 // Try to read metadata for both attachment1 and attachment2 again.
335 this->store
->ReadMetadata(ids
, this->read_metadata_callback
);
336 this->ClearAndPumpLoop();
337 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
338 EXPECT_EQ(2U, this->attachment_metadata
->size());
340 // Verify that we've got both entries back in the right order.
341 AttachmentMetadataList::const_iterator iter
=
342 this->attachment_metadata
->begin();
343 EXPECT_EQ(attachment1
.GetId(), iter
->GetId());
345 EXPECT_EQ(attachment2
.GetId(), iter
->GetId());
348 // Verify getting metadata for all attachments.
349 TYPED_TEST_P(AttachmentStoreTest
, ReadAllMetadata
) {
350 // Try to read all metadata from an empty store.
351 this->store
->ReadAllMetadata(this->read_metadata_callback
);
352 this->ClearAndPumpLoop();
353 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
354 EXPECT_EQ(0U, this->attachment_metadata
->size());
356 // Create and write two attachments.
357 Attachment attachment1
= Attachment::Create(this->some_data1
);
358 Attachment attachment2
= Attachment::Create(this->some_data2
);
360 AttachmentList some_attachments
;
361 some_attachments
.push_back(attachment1
);
362 some_attachments
.push_back(attachment2
);
363 this->store
->Write(some_attachments
, this->write_callback
);
364 this->ClearAndPumpLoop();
365 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
367 // Read all metadata again.
368 this->store
->ReadAllMetadata(this->read_metadata_callback
);
369 this->ClearAndPumpLoop();
370 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
371 EXPECT_EQ(2U, this->attachment_metadata
->size());
373 // Verify that we get all attachments back (the order is undefined).
375 ids
.insert(attachment1
.GetId());
376 ids
.insert(attachment2
.GetId());
378 AttachmentMetadataList::const_iterator iter
=
379 this->attachment_metadata
->begin();
380 const AttachmentMetadataList::const_iterator end
=
381 this->attachment_metadata
->end();
382 for (; iter
!= end
; ++iter
) {
383 EXPECT_THAT(ids
, testing::Contains(iter
->GetId()));
384 ids
.erase(iter
->GetId());
386 EXPECT_TRUE(ids
.empty());
389 REGISTER_TYPED_TEST_CASE_P(AttachmentStoreTest
,
390 Write_NoOverwriteNoError
,
393 Drop_DropTwoButOnlyOneExists
,
398 } // namespace syncer
400 #endif // SYNC_INTERNAL_API_ATTACHMENTS_ATTACHMENT_STORE_TEST_TEMPLATE_H_