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/run_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_ptr
<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 base::RunLoop().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 CreateAttachmentStoreForSync() creates valid object.
132 TYPED_TEST_P(AttachmentStoreTest
, CreateAttachmentStoreForSync
) {
133 scoped_ptr
<AttachmentStoreForSync
> attachment_store_for_sync
=
134 this->store
->CreateAttachmentStoreForSync();
135 EXPECT_NE(nullptr, attachment_store_for_sync
);
138 // Verify that we do not overwrite existing attachments and that we do not treat
140 TYPED_TEST_P(AttachmentStoreTest
, Write_NoOverwriteNoError
) {
141 // Create two attachments with the same id but different data.
142 Attachment attachment1
= Attachment::Create(this->some_data1
);
143 Attachment attachment2
=
144 Attachment::CreateFromParts(attachment1
.GetId(), this->some_data2
);
146 // Write the first one.
147 AttachmentList some_attachments
;
148 some_attachments
.push_back(attachment1
);
149 this->store
->Write(some_attachments
, this->write_callback
);
150 this->ClearAndPumpLoop();
151 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
153 // Write the second one.
154 some_attachments
.clear();
155 some_attachments
.push_back(attachment2
);
156 this->store
->Write(some_attachments
, this->write_callback
);
157 this->ClearAndPumpLoop();
158 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
160 // Read it back and see that it was not overwritten.
161 AttachmentIdList some_attachment_ids
;
162 some_attachment_ids
.push_back(attachment1
.GetId());
163 this->store
->Read(some_attachment_ids
, this->read_callback
);
164 this->ClearAndPumpLoop();
165 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
166 EXPECT_EQ(1U, this->attachments
->size());
167 EXPECT_EQ(0U, this->failed_attachment_ids
->size());
168 AttachmentMap::const_iterator a1
=
169 this->attachments
->find(attachment1
.GetId());
170 EXPECT_TRUE(a1
!= this->attachments
->end());
171 EXPECT_TRUE(attachment1
.GetData()->Equals(a1
->second
.GetData()));
174 // Verify that we can write some attachments and read them back.
175 TYPED_TEST_P(AttachmentStoreTest
, Write_RoundTrip
) {
176 Attachment attachment1
= Attachment::Create(this->some_data1
);
177 Attachment attachment2
= Attachment::Create(this->some_data2
);
178 AttachmentList some_attachments
;
179 some_attachments
.push_back(attachment1
);
180 some_attachments
.push_back(attachment2
);
182 this->store
->Write(some_attachments
, this->write_callback
);
183 this->ClearAndPumpLoop();
184 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
186 AttachmentIdList some_attachment_ids
;
187 some_attachment_ids
.push_back(attachment1
.GetId());
188 some_attachment_ids
.push_back(attachment2
.GetId());
189 this->store
->Read(some_attachment_ids
, this->read_callback
);
190 this->ClearAndPumpLoop();
191 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
192 EXPECT_EQ(2U, this->attachments
->size());
193 EXPECT_EQ(0U, this->failed_attachment_ids
->size());
195 AttachmentMap::const_iterator a1
=
196 this->attachments
->find(attachment1
.GetId());
197 EXPECT_TRUE(a1
!= this->attachments
->end());
198 EXPECT_TRUE(attachment1
.GetData()->Equals(a1
->second
.GetData()));
200 AttachmentMap::const_iterator a2
=
201 this->attachments
->find(attachment2
.GetId());
202 EXPECT_TRUE(a2
!= this->attachments
->end());
203 EXPECT_TRUE(attachment2
.GetData()->Equals(a2
->second
.GetData()));
206 // Try to read two attachments when only one exists.
207 TYPED_TEST_P(AttachmentStoreTest
, Read_OneNotFound
) {
208 Attachment attachment1
= Attachment::Create(this->some_data1
);
209 Attachment attachment2
= Attachment::Create(this->some_data2
);
211 AttachmentList some_attachments
;
212 // Write attachment1 only.
213 some_attachments
.push_back(attachment1
);
214 this->store
->Write(some_attachments
, this->write_callback
);
215 this->ClearAndPumpLoop();
216 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
218 // Try to read both attachment1 and attachment2.
219 AttachmentIdList ids
;
220 ids
.push_back(attachment1
.GetId());
221 ids
.push_back(attachment2
.GetId());
222 this->store
->Read(ids
, this->read_callback
);
223 this->ClearAndPumpLoop();
225 // See that only attachment1 was read.
226 EXPECT_EQ(AttachmentStore::UNSPECIFIED_ERROR
, this->result
);
227 EXPECT_EQ(1U, this->attachments
->size());
228 EXPECT_EQ(1U, this->failed_attachment_ids
->size());
231 // Try to drop two attachments when only one exists. Verify that no error occurs
232 // and that the existing attachment was dropped.
233 TYPED_TEST_P(AttachmentStoreTest
, Drop_DropTwoButOnlyOneExists
) {
234 // First, create two attachments.
235 Attachment attachment1
= Attachment::Create(this->some_data1
);
236 Attachment attachment2
= Attachment::Create(this->some_data2
);
237 AttachmentList some_attachments
;
238 some_attachments
.push_back(attachment1
);
239 some_attachments
.push_back(attachment2
);
240 this->store
->Write(some_attachments
, this->write_callback
);
241 this->ClearAndPumpLoop();
242 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
244 // Drop attachment1 only.
245 AttachmentIdList ids
;
246 ids
.push_back(attachment1
.GetId());
247 this->store
->Drop(ids
, this->drop_callback
);
248 this->ClearAndPumpLoop();
249 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
251 // See that attachment1 is gone.
252 this->store
->Read(ids
, this->read_callback
);
253 this->ClearAndPumpLoop();
254 EXPECT_EQ(AttachmentStore::UNSPECIFIED_ERROR
, this->result
);
255 EXPECT_EQ(0U, this->attachments
->size());
256 EXPECT_EQ(1U, this->failed_attachment_ids
->size());
257 EXPECT_EQ(attachment1
.GetId(), (*this->failed_attachment_ids
)[0]);
259 // Drop both attachment1 and attachment2.
261 ids
.push_back(attachment1
.GetId());
262 ids
.push_back(attachment2
.GetId());
263 this->store
->Drop(ids
, this->drop_callback
);
264 this->ClearAndPumpLoop();
265 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
267 // See that attachment2 is now gone.
269 ids
.push_back(attachment2
.GetId());
270 this->store
->Read(ids
, this->read_callback
);
271 this->ClearAndPumpLoop();
272 EXPECT_EQ(AttachmentStore::UNSPECIFIED_ERROR
, this->result
);
273 EXPECT_EQ(0U, this->attachments
->size());
274 EXPECT_EQ(1U, this->failed_attachment_ids
->size());
275 EXPECT_EQ(attachment2
.GetId(), (*this->failed_attachment_ids
)[0]);
278 // Verify that attempting to drop an attachment that does not exist is not an
280 TYPED_TEST_P(AttachmentStoreTest
, Drop_DoesNotExist
) {
281 Attachment attachment1
= Attachment::Create(this->some_data1
);
282 AttachmentList some_attachments
;
283 some_attachments
.push_back(attachment1
);
284 this->store
->Write(some_attachments
, this->write_callback
);
285 this->ClearAndPumpLoop();
286 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
288 // Drop the attachment.
289 AttachmentIdList ids
;
290 ids
.push_back(attachment1
.GetId());
291 this->store
->Drop(ids
, this->drop_callback
);
292 this->ClearAndPumpLoop();
293 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
295 // See that it's gone.
296 this->store
->Read(ids
, this->read_callback
);
297 this->ClearAndPumpLoop();
298 EXPECT_EQ(AttachmentStore::UNSPECIFIED_ERROR
, this->result
);
299 EXPECT_EQ(0U, this->attachments
->size());
300 EXPECT_EQ(1U, this->failed_attachment_ids
->size());
301 EXPECT_EQ(attachment1
.GetId(), (*this->failed_attachment_ids
)[0]);
303 // Drop again, see that no error occurs.
305 ids
.push_back(attachment1
.GetId());
306 this->store
->Drop(ids
, this->drop_callback
);
307 this->ClearAndPumpLoop();
308 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
311 // Verify getting metadata for specific attachments.
312 TYPED_TEST_P(AttachmentStoreTest
, ReadMetadata
) {
313 Attachment attachment1
= Attachment::Create(this->some_data1
);
314 Attachment attachment2
= Attachment::Create(this->some_data2
);
316 AttachmentList some_attachments
;
317 // Write attachment1 only.
318 some_attachments
.push_back(attachment1
);
319 this->store
->Write(some_attachments
, this->write_callback
);
320 this->ClearAndPumpLoop();
321 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
323 // Try to read metadata for both attachment1 and attachment2.
324 AttachmentIdList ids
;
325 ids
.push_back(attachment1
.GetId());
326 ids
.push_back(attachment2
.GetId());
327 this->store
->ReadMetadata(ids
, this->read_metadata_callback
);
328 this->ClearAndPumpLoop();
330 // See that only one entry was read.
331 EXPECT_EQ(AttachmentStore::UNSPECIFIED_ERROR
, this->result
);
332 EXPECT_EQ(1U, this->attachment_metadata
->size());
334 // Now write attachment2.
335 some_attachments
[0] = attachment2
;
336 this->store
->Write(some_attachments
, this->write_callback
);
337 this->ClearAndPumpLoop();
338 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
340 // Try to read metadata for both attachment1 and attachment2 again.
341 this->store
->ReadMetadata(ids
, this->read_metadata_callback
);
342 this->ClearAndPumpLoop();
343 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
344 EXPECT_EQ(2U, this->attachment_metadata
->size());
346 // Verify that we've got both entries back in the right order.
347 AttachmentMetadataList::const_iterator iter
=
348 this->attachment_metadata
->begin();
349 EXPECT_EQ(attachment1
.GetId(), iter
->GetId());
351 EXPECT_EQ(attachment2
.GetId(), iter
->GetId());
354 // Verify getting metadata for all attachments.
355 TYPED_TEST_P(AttachmentStoreTest
, ReadAllMetadata
) {
356 // Try to read all metadata from an empty store.
357 this->store
->ReadAllMetadata(this->read_metadata_callback
);
358 this->ClearAndPumpLoop();
359 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
360 EXPECT_EQ(0U, this->attachment_metadata
->size());
362 // Create and write two attachments.
363 Attachment attachment1
= Attachment::Create(this->some_data1
);
364 Attachment attachment2
= Attachment::Create(this->some_data2
);
366 AttachmentList some_attachments
;
367 some_attachments
.push_back(attachment1
);
368 some_attachments
.push_back(attachment2
);
369 this->store
->Write(some_attachments
, this->write_callback
);
370 this->ClearAndPumpLoop();
371 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
373 // Read all metadata again.
374 this->store
->ReadAllMetadata(this->read_metadata_callback
);
375 this->ClearAndPumpLoop();
376 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
377 EXPECT_EQ(2U, this->attachment_metadata
->size());
379 // Verify that we get all attachments back (the order is undefined).
381 ids
.insert(attachment1
.GetId());
382 ids
.insert(attachment2
.GetId());
384 AttachmentMetadataList::const_iterator iter
=
385 this->attachment_metadata
->begin();
386 const AttachmentMetadataList::const_iterator end
=
387 this->attachment_metadata
->end();
388 for (; iter
!= end
; ++iter
) {
389 EXPECT_THAT(ids
, testing::Contains(iter
->GetId()));
390 ids
.erase(iter
->GetId());
392 EXPECT_TRUE(ids
.empty());
395 REGISTER_TYPED_TEST_CASE_P(AttachmentStoreTest
,
396 CreateAttachmentStoreForSync
,
397 Write_NoOverwriteNoError
,
400 Drop_DropTwoButOnlyOneExists
,
405 } // namespace syncer
407 #endif // SYNC_INTERNAL_API_ATTACHMENTS_ATTACHMENT_STORE_TEST_TEMPLATE_H_