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 scoped_ptr
<AttachmentStoreForSync
> store_for_sync
;
52 AttachmentStore::Result result
;
53 scoped_ptr
<AttachmentMap
> attachments
;
54 scoped_ptr
<AttachmentIdList
> failed_attachment_ids
;
55 scoped_ptr
<AttachmentMetadataList
> attachment_metadata
;
57 AttachmentStore::ReadCallback read_callback
;
58 AttachmentStore::WriteCallback write_callback
;
59 AttachmentStore::DropCallback drop_callback
;
60 AttachmentStore::ReadMetadataCallback read_metadata_callback
;
62 scoped_refptr
<base::RefCountedString
> some_data1
;
63 scoped_refptr
<base::RefCountedString
> some_data2
;
65 AttachmentStoreTest() {}
67 void SetUp() override
{
68 store
= attachment_store_factory
.CreateAttachmentStore();
69 store_for_sync
= store
->CreateAttachmentStoreForSync();
72 read_callback
= base::Bind(&AttachmentStoreTest::CopyResultAttachments
,
73 base::Unretained(this),
76 &failed_attachment_ids
);
77 write_callback
= base::Bind(
78 &AttachmentStoreTest::CopyResult
, base::Unretained(this), &result
);
79 drop_callback
= write_callback
;
80 read_metadata_callback
=
81 base::Bind(&AttachmentStoreTest::CopyResultMetadata
,
82 base::Unretained(this), &result
, &attachment_metadata
);
84 some_data1
= new base::RefCountedString
;
85 some_data1
->data() = kTestData1
;
87 some_data2
= new base::RefCountedString
;
88 some_data2
->data() = kTestData2
;
91 void ClearAndPumpLoop() {
93 base::RunLoop().RunUntilIdle();
98 result
= AttachmentStore::UNSPECIFIED_ERROR
;
100 failed_attachment_ids
.reset();
101 attachment_metadata
.reset();
104 void CopyResult(AttachmentStore::Result
* destination_result
,
105 const AttachmentStore::Result
& source_result
) {
106 *destination_result
= source_result
;
109 void CopyResultAttachments(
110 AttachmentStore::Result
* destination_result
,
111 scoped_ptr
<AttachmentMap
>* destination_attachments
,
112 scoped_ptr
<AttachmentIdList
>* destination_failed_attachment_ids
,
113 const AttachmentStore::Result
& source_result
,
114 scoped_ptr
<AttachmentMap
> source_attachments
,
115 scoped_ptr
<AttachmentIdList
> source_failed_attachment_ids
) {
116 CopyResult(destination_result
, source_result
);
117 *destination_attachments
= source_attachments
.Pass();
118 *destination_failed_attachment_ids
= source_failed_attachment_ids
.Pass();
121 void CopyResultMetadata(
122 AttachmentStore::Result
* destination_result
,
123 scoped_ptr
<AttachmentMetadataList
>* destination_metadata
,
124 const AttachmentStore::Result
& source_result
,
125 scoped_ptr
<AttachmentMetadataList
> source_metadata
) {
126 CopyResult(destination_result
, source_result
);
127 *destination_metadata
= source_metadata
.Pass();
131 TYPED_TEST_CASE_P(AttachmentStoreTest
);
133 // Verify that CreateAttachmentStoreForSync() creates valid object.
134 TYPED_TEST_P(AttachmentStoreTest
, CreateAttachmentStoreForSync
) {
135 scoped_ptr
<AttachmentStoreForSync
> attachment_store_for_sync
=
136 this->store
->CreateAttachmentStoreForSync();
137 EXPECT_NE(nullptr, attachment_store_for_sync
);
140 // Verify that we do not overwrite existing attachments and that we do not treat
142 TYPED_TEST_P(AttachmentStoreTest
, Write_NoOverwriteNoError
) {
143 // Create two attachments with the same id but different data.
144 Attachment attachment1
= Attachment::Create(this->some_data1
);
145 Attachment attachment2
=
146 Attachment::CreateFromParts(attachment1
.GetId(), this->some_data2
);
148 // Write the first one.
149 AttachmentList some_attachments
;
150 some_attachments
.push_back(attachment1
);
151 this->store
->Write(some_attachments
, this->write_callback
);
152 this->ClearAndPumpLoop();
153 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
155 // Write the second one.
156 some_attachments
.clear();
157 some_attachments
.push_back(attachment2
);
158 this->store
->Write(some_attachments
, this->write_callback
);
159 this->ClearAndPumpLoop();
160 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
162 // Read it back and see that it was not overwritten.
163 AttachmentIdList some_attachment_ids
;
164 some_attachment_ids
.push_back(attachment1
.GetId());
165 this->store
->Read(some_attachment_ids
, this->read_callback
);
166 this->ClearAndPumpLoop();
167 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
168 EXPECT_EQ(1U, this->attachments
->size());
169 EXPECT_EQ(0U, this->failed_attachment_ids
->size());
170 AttachmentMap::const_iterator a1
=
171 this->attachments
->find(attachment1
.GetId());
172 EXPECT_TRUE(a1
!= this->attachments
->end());
173 EXPECT_TRUE(attachment1
.GetData()->Equals(a1
->second
.GetData()));
176 // Verify that we can write some attachments and read them back.
177 TYPED_TEST_P(AttachmentStoreTest
, Write_RoundTrip
) {
178 Attachment attachment1
= Attachment::Create(this->some_data1
);
179 Attachment attachment2
= Attachment::Create(this->some_data2
);
180 AttachmentList some_attachments
;
181 some_attachments
.push_back(attachment1
);
182 some_attachments
.push_back(attachment2
);
184 this->store
->Write(some_attachments
, this->write_callback
);
185 this->ClearAndPumpLoop();
186 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
188 AttachmentIdList some_attachment_ids
;
189 some_attachment_ids
.push_back(attachment1
.GetId());
190 some_attachment_ids
.push_back(attachment2
.GetId());
191 this->store
->Read(some_attachment_ids
, this->read_callback
);
192 this->ClearAndPumpLoop();
193 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
194 EXPECT_EQ(2U, this->attachments
->size());
195 EXPECT_EQ(0U, this->failed_attachment_ids
->size());
197 AttachmentMap::const_iterator a1
=
198 this->attachments
->find(attachment1
.GetId());
199 EXPECT_TRUE(a1
!= this->attachments
->end());
200 EXPECT_TRUE(attachment1
.GetData()->Equals(a1
->second
.GetData()));
202 AttachmentMap::const_iterator a2
=
203 this->attachments
->find(attachment2
.GetId());
204 EXPECT_TRUE(a2
!= this->attachments
->end());
205 EXPECT_TRUE(attachment2
.GetData()->Equals(a2
->second
.GetData()));
208 // Try to read two attachments when only one exists.
209 TYPED_TEST_P(AttachmentStoreTest
, Read_OneNotFound
) {
210 Attachment attachment1
= Attachment::Create(this->some_data1
);
211 Attachment attachment2
= Attachment::Create(this->some_data2
);
213 AttachmentList some_attachments
;
214 // Write attachment1 only.
215 some_attachments
.push_back(attachment1
);
216 this->store
->Write(some_attachments
, this->write_callback
);
217 this->ClearAndPumpLoop();
218 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
220 // Try to read both attachment1 and attachment2.
221 AttachmentIdList ids
;
222 ids
.push_back(attachment1
.GetId());
223 ids
.push_back(attachment2
.GetId());
224 this->store
->Read(ids
, this->read_callback
);
225 this->ClearAndPumpLoop();
227 // See that only attachment1 was read.
228 EXPECT_EQ(AttachmentStore::UNSPECIFIED_ERROR
, this->result
);
229 EXPECT_EQ(1U, this->attachments
->size());
230 EXPECT_EQ(1U, this->failed_attachment_ids
->size());
233 // Try to drop two attachments when only one exists. Verify that no error occurs
234 // and that the existing attachment was dropped.
235 TYPED_TEST_P(AttachmentStoreTest
, Drop_DropTwoButOnlyOneExists
) {
236 // First, create two attachments.
237 Attachment attachment1
= Attachment::Create(this->some_data1
);
238 Attachment attachment2
= Attachment::Create(this->some_data2
);
239 AttachmentList some_attachments
;
240 some_attachments
.push_back(attachment1
);
241 some_attachments
.push_back(attachment2
);
242 this->store
->Write(some_attachments
, this->write_callback
);
243 this->ClearAndPumpLoop();
244 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
246 // Drop attachment1 only.
247 AttachmentIdList ids
;
248 ids
.push_back(attachment1
.GetId());
249 this->store
->Drop(ids
, this->drop_callback
);
250 this->ClearAndPumpLoop();
251 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
253 // See that attachment1 is gone.
254 this->store
->Read(ids
, this->read_callback
);
255 this->ClearAndPumpLoop();
256 EXPECT_EQ(AttachmentStore::UNSPECIFIED_ERROR
, this->result
);
257 EXPECT_EQ(0U, this->attachments
->size());
258 EXPECT_EQ(1U, this->failed_attachment_ids
->size());
259 EXPECT_EQ(attachment1
.GetId(), (*this->failed_attachment_ids
)[0]);
261 // Drop both attachment1 and attachment2.
263 ids
.push_back(attachment1
.GetId());
264 ids
.push_back(attachment2
.GetId());
265 this->store
->Drop(ids
, this->drop_callback
);
266 this->ClearAndPumpLoop();
267 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
269 // See that attachment2 is now gone.
271 ids
.push_back(attachment2
.GetId());
272 this->store
->Read(ids
, this->read_callback
);
273 this->ClearAndPumpLoop();
274 EXPECT_EQ(AttachmentStore::UNSPECIFIED_ERROR
, this->result
);
275 EXPECT_EQ(0U, this->attachments
->size());
276 EXPECT_EQ(1U, this->failed_attachment_ids
->size());
277 EXPECT_EQ(attachment2
.GetId(), (*this->failed_attachment_ids
)[0]);
280 // Verify that attempting to drop an attachment that does not exist is not an
282 TYPED_TEST_P(AttachmentStoreTest
, Drop_DoesNotExist
) {
283 Attachment attachment1
= Attachment::Create(this->some_data1
);
284 AttachmentList some_attachments
;
285 some_attachments
.push_back(attachment1
);
286 this->store
->Write(some_attachments
, this->write_callback
);
287 this->ClearAndPumpLoop();
288 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
290 // Drop the attachment.
291 AttachmentIdList ids
;
292 ids
.push_back(attachment1
.GetId());
293 this->store
->Drop(ids
, this->drop_callback
);
294 this->ClearAndPumpLoop();
295 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
297 // See that it's gone.
298 this->store
->Read(ids
, this->read_callback
);
299 this->ClearAndPumpLoop();
300 EXPECT_EQ(AttachmentStore::UNSPECIFIED_ERROR
, this->result
);
301 EXPECT_EQ(0U, this->attachments
->size());
302 EXPECT_EQ(1U, this->failed_attachment_ids
->size());
303 EXPECT_EQ(attachment1
.GetId(), (*this->failed_attachment_ids
)[0]);
305 // Drop again, see that no error occurs.
307 ids
.push_back(attachment1
.GetId());
308 this->store
->Drop(ids
, this->drop_callback
);
309 this->ClearAndPumpLoop();
310 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
313 // Verify getting metadata for specific attachments.
314 TYPED_TEST_P(AttachmentStoreTest
, ReadMetadata
) {
315 Attachment attachment1
= Attachment::Create(this->some_data1
);
316 Attachment attachment2
= Attachment::Create(this->some_data2
);
318 AttachmentList some_attachments
;
319 // Write attachment1 only.
320 some_attachments
.push_back(attachment1
);
321 this->store
->Write(some_attachments
, this->write_callback
);
322 this->ClearAndPumpLoop();
323 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
325 // Try to read metadata for both attachment1 and attachment2.
326 AttachmentIdList ids
;
327 ids
.push_back(attachment1
.GetId());
328 ids
.push_back(attachment2
.GetId());
329 this->store
->ReadMetadata(ids
, this->read_metadata_callback
);
330 this->ClearAndPumpLoop();
332 // See that only one entry was read.
333 EXPECT_EQ(AttachmentStore::UNSPECIFIED_ERROR
, this->result
);
334 EXPECT_EQ(1U, this->attachment_metadata
->size());
336 // Now write attachment2.
337 some_attachments
[0] = attachment2
;
338 this->store
->Write(some_attachments
, this->write_callback
);
339 this->ClearAndPumpLoop();
340 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
342 // Try to read metadata for both attachment1 and attachment2 again.
343 this->store
->ReadMetadata(ids
, this->read_metadata_callback
);
344 this->ClearAndPumpLoop();
345 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
346 EXPECT_EQ(2U, this->attachment_metadata
->size());
348 // Verify that we've got both entries back in the right order.
349 AttachmentMetadataList::const_iterator iter
=
350 this->attachment_metadata
->begin();
351 EXPECT_EQ(attachment1
.GetId(), iter
->GetId());
353 EXPECT_EQ(attachment2
.GetId(), iter
->GetId());
356 // Verify that ReadAllMetadata/ReadSyncMetadata returns metadata for correct
357 // set of attachments.
358 TYPED_TEST_P(AttachmentStoreTest
, ReadAllMetadata
) {
359 // Try to read all metadata from an empty store.
360 this->store
->ReadAllMetadata(this->read_metadata_callback
);
361 this->ClearAndPumpLoop();
362 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
363 EXPECT_EQ(0U, this->attachment_metadata
->size());
365 // Create and write attachments with different set of references.
366 Attachment attachment_mt
= Attachment::Create(this->some_data1
);
367 Attachment attachment_sync
= Attachment::Create(this->some_data1
);
368 Attachment attachment_both
= Attachment::Create(this->some_data1
);
370 AttachmentList attachments
;
371 attachments
.push_back(attachment_mt
);
372 attachments
.push_back(attachment_sync
);
373 attachments
.push_back(attachment_both
);
374 this->store
->Write(attachments
, this->write_callback
);
375 this->ClearAndPumpLoop();
376 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
378 AttachmentIdList ids
;
379 ids
.push_back(attachment_sync
.GetId());
380 ids
.push_back(attachment_both
.GetId());
381 this->store_for_sync
->SetSyncReference(ids
);
384 ids
.push_back(attachment_sync
.GetId());
385 this->store
->Drop(ids
, this->drop_callback
);
386 this->ClearAndPumpLoop();
388 // Calling ReadMetadata for above three attachments should return all of them.
390 ids
.push_back(attachment_sync
.GetId());
391 ids
.push_back(attachment_sync
.GetId());
392 ids
.push_back(attachment_both
.GetId());
393 this->store
->ReadMetadata(ids
, this->read_metadata_callback
);
394 this->ClearAndPumpLoop();
395 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
396 EXPECT_EQ(3U, this->attachment_metadata
->size());
398 // Call to ReadAllMetadata() should only return attachments with model type
400 this->store
->ReadAllMetadata(this->read_metadata_callback
);
401 this->ClearAndPumpLoop();
402 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
403 EXPECT_EQ(2U, this->attachment_metadata
->size());
405 // Verify that we get all attachments back (the order is undefined).
406 AttachmentIdSet id_set
;
407 id_set
.insert(attachment_mt
.GetId());
408 id_set
.insert(attachment_both
.GetId());
410 testing::Contains((*this->attachment_metadata
)[0].GetId()));
412 testing::Contains((*this->attachment_metadata
)[1].GetId()));
414 // Call to ReadSyncMetadata() should only return attachments with sync
416 this->store_for_sync
->ReadSyncMetadata(this->read_metadata_callback
);
417 this->ClearAndPumpLoop();
418 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
419 EXPECT_EQ(2U, this->attachment_metadata
->size());
422 id_set
.insert(attachment_sync
.GetId());
423 id_set
.insert(attachment_both
.GetId());
425 testing::Contains((*this->attachment_metadata
)[0].GetId()));
427 testing::Contains((*this->attachment_metadata
)[1].GetId()));
430 // Verify that setting/droping references gets reflected in ReadAllMetadata and
431 // that attachment is only deleted after last reference is droped.
432 TYPED_TEST_P(AttachmentStoreTest
, SetSyncReference_DropSyncReference
) {
433 Attachment attachment
= Attachment::Create(this->some_data1
);
434 AttachmentList attachments
;
435 attachments
.push_back(attachment
);
436 AttachmentIdList ids
;
437 ids
.push_back(attachment
.GetId());
439 // When writing attachment to store only model type reference should be set.
440 this->store
->Write(attachments
, this->write_callback
);
442 this->store
->ReadAllMetadata(this->read_metadata_callback
);
443 this->ClearAndPumpLoop();
444 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
445 EXPECT_EQ(1U, this->attachment_metadata
->size());
446 EXPECT_EQ(attachment
.GetId(), this->attachment_metadata
->begin()->GetId());
448 this->store_for_sync
->ReadSyncMetadata(this->read_metadata_callback
);
449 this->ClearAndPumpLoop();
450 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
451 EXPECT_EQ(0U, this->attachment_metadata
->size());
453 // After call to SetSyncReference() ReadSyncMetadata should start returning
455 this->store_for_sync
->SetSyncReference(ids
);
457 this->store_for_sync
->ReadSyncMetadata(this->read_metadata_callback
);
458 this->ClearAndPumpLoop();
459 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
460 EXPECT_EQ(1U, this->attachment_metadata
->size());
462 // Call SetSyncReference() to verify it is idempotent.
463 this->store_for_sync
->SetSyncReference(ids
);
464 this->ClearAndPumpLoop();
466 // Droping attachment should remove model type reference, but there is still
468 this->store
->Drop(ids
, this->drop_callback
);
469 this->ClearAndPumpLoop();
470 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
472 this->store
->ReadAllMetadata(this->read_metadata_callback
);
473 this->ClearAndPumpLoop();
474 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
475 EXPECT_EQ(0U, this->attachment_metadata
->size());
477 this->store_for_sync
->ReadSyncMetadata(this->read_metadata_callback
);
478 this->ClearAndPumpLoop();
479 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
480 EXPECT_EQ(1U, this->attachment_metadata
->size());
482 // ReadMetadata should still return this attachment even though it does not
483 // have model type reference.
484 this->store
->ReadMetadata(ids
, this->read_metadata_callback
);
485 this->ClearAndPumpLoop();
486 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
487 EXPECT_EQ(1U, this->attachment_metadata
->size());
489 // Call Drop() again to ensure it doesn't fail.
490 this->store
->Drop(ids
, this->drop_callback
);
491 this->ClearAndPumpLoop();
492 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
494 // After droping sync reference attachment should be deleted from store.
495 // ReadMetadata should return UNSPECIFIED_ERROR.
496 this->store_for_sync
->DropSyncReference(ids
);
498 this->store_for_sync
->ReadSyncMetadata(this->read_metadata_callback
);
499 this->ClearAndPumpLoop();
500 EXPECT_EQ(AttachmentStore::SUCCESS
, this->result
);
501 EXPECT_EQ(0U, this->attachment_metadata
->size());
503 this->store
->ReadMetadata(ids
, this->read_metadata_callback
);
504 this->ClearAndPumpLoop();
505 EXPECT_EQ(AttachmentStore::UNSPECIFIED_ERROR
, this->result
);
506 EXPECT_EQ(0U, this->attachment_metadata
->size());
509 REGISTER_TYPED_TEST_CASE_P(AttachmentStoreTest
,
510 CreateAttachmentStoreForSync
,
511 Write_NoOverwriteNoError
,
514 Drop_DropTwoButOnlyOneExists
,
518 SetSyncReference_DropSyncReference
);
520 } // namespace syncer
522 #endif // SYNC_INTERNAL_API_ATTACHMENTS_ATTACHMENT_STORE_TEST_TEMPLATE_H_