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/attachment_service_impl.h"
8 #include "base/memory/weak_ptr.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/run_loop.h"
11 #include "sync/internal_api/public/attachments/fake_attachment_downloader.h"
12 #include "sync/internal_api/public/attachments/fake_attachment_uploader.h"
13 #include "testing/gtest/include/gtest/gtest.h"
17 class MockAttachmentStore
: public AttachmentStore
,
18 public base::SupportsWeakPtr
<MockAttachmentStore
> {
20 MockAttachmentStore() {}
22 virtual void Read(const AttachmentIdList
& ids
,
23 const ReadCallback
& callback
) OVERRIDE
{
24 read_ids
.push_back(ids
);
25 read_callbacks
.push_back(callback
);
28 virtual void Write(const AttachmentList
& attachments
,
29 const WriteCallback
& callback
) OVERRIDE
{
30 write_attachments
.push_back(attachments
);
31 write_callbacks
.push_back(callback
);
34 virtual void Drop(const AttachmentIdList
& ids
,
35 const DropCallback
& callback
) OVERRIDE
{
39 // Respond to Read request. Attachments found in local_attachments should be
40 // returned, everything else should be reported unavailable.
41 void RespondToRead(const AttachmentIdSet
& local_attachments
) {
42 scoped_refptr
<base::RefCountedString
> data
= new base::RefCountedString();
43 ReadCallback callback
= read_callbacks
.back();
44 AttachmentIdList ids
= read_ids
.back();
45 read_callbacks
.pop_back();
48 scoped_ptr
<AttachmentMap
> attachments(new AttachmentMap());
49 scoped_ptr
<AttachmentIdList
> unavailable_attachments(
50 new AttachmentIdList());
51 for (AttachmentIdList::const_iterator iter
= ids
.begin(); iter
!= ids
.end();
53 if (local_attachments
.find(*iter
) != local_attachments
.end()) {
54 Attachment attachment
= Attachment::CreateWithId(*iter
, data
);
55 attachments
->insert(std::make_pair(*iter
, attachment
));
57 unavailable_attachments
->push_back(*iter
);
61 unavailable_attachments
->empty() ? SUCCESS
: UNSPECIFIED_ERROR
;
63 base::MessageLoop::current()->PostTask(
67 base::Passed(&attachments
),
68 base::Passed(&unavailable_attachments
)));
71 // Respond to Write request with |result|.
72 void RespondToWrite(const Result
& result
) {
73 WriteCallback callback
= write_callbacks
.back();
74 AttachmentList attachments
= write_attachments
.back();
75 write_callbacks
.pop_back();
76 write_attachments
.pop_back();
77 base::MessageLoop::current()->PostTask(FROM_HERE
,
78 base::Bind(callback
, result
));
81 std::vector
<AttachmentIdList
> read_ids
;
82 std::vector
<ReadCallback
> read_callbacks
;
83 std::vector
<AttachmentList
> write_attachments
;
84 std::vector
<WriteCallback
> write_callbacks
;
86 DISALLOW_COPY_AND_ASSIGN(MockAttachmentStore
);
89 class MockAttachmentDownloader
90 : public AttachmentDownloader
,
91 public base::SupportsWeakPtr
<MockAttachmentDownloader
> {
93 MockAttachmentDownloader() {}
95 virtual void DownloadAttachment(const AttachmentId
& id
,
96 const DownloadCallback
& callback
) OVERRIDE
{
97 ASSERT_TRUE(download_requests
.find(id
) == download_requests
.end());
98 download_requests
.insert(std::make_pair(id
, callback
));
101 // Multiple requests to download will be active at the same time.
102 // RespondToDownload should respond to only one of them.
103 void RespondToDownload(const AttachmentId
& id
, const DownloadResult
& result
) {
104 ASSERT_TRUE(download_requests
.find(id
) != download_requests
.end());
105 scoped_ptr
<Attachment
> attachment
;
106 if (result
== DOWNLOAD_SUCCESS
) {
107 scoped_refptr
<base::RefCountedString
> data
= new base::RefCountedString();
108 attachment
.reset(new Attachment(Attachment::CreateWithId(id
, data
)));
110 base::MessageLoop::current()->PostTask(
112 base::Bind(download_requests
[id
], result
, base::Passed(&attachment
)));
114 download_requests
.erase(id
);
117 std::map
<AttachmentId
, DownloadCallback
> download_requests
;
119 DISALLOW_COPY_AND_ASSIGN(MockAttachmentDownloader
);
122 class MockAttachmentUploader
123 : public AttachmentUploader
,
124 public base::SupportsWeakPtr
<MockAttachmentUploader
> {
126 MockAttachmentUploader() {}
128 // AttachmentUploader implementation.
129 virtual void UploadAttachment(const Attachment
& attachment
,
130 const UploadCallback
& callback
) OVERRIDE
{
131 const AttachmentId id
= attachment
.GetId();
132 ASSERT_TRUE(upload_requests
.find(id
) == upload_requests
.end());
133 upload_requests
.insert(std::make_pair(id
, callback
));
136 void RespondToUpload(const AttachmentId
& id
, const UploadResult
& result
) {
137 ASSERT_TRUE(upload_requests
.find(id
) != upload_requests
.end());
138 base::MessageLoop::current()->PostTask(
139 FROM_HERE
, base::Bind(upload_requests
[id
], result
, id
));
140 upload_requests
.erase(id
);
143 std::map
<AttachmentId
, UploadCallback
> upload_requests
;
145 DISALLOW_COPY_AND_ASSIGN(MockAttachmentUploader
);
148 class AttachmentServiceImplTest
: public testing::Test
,
149 public AttachmentService::Delegate
{
151 AttachmentServiceImplTest() {}
153 virtual void SetUp() OVERRIDE
{
154 InitializeAttachmentService(make_scoped_ptr(new MockAttachmentUploader()),
155 make_scoped_ptr(new MockAttachmentDownloader()),
159 virtual void TearDown() OVERRIDE
{
160 attachment_service_
.reset();
161 ASSERT_FALSE(attachment_store_
);
162 ASSERT_FALSE(attachment_uploader_
);
163 ASSERT_FALSE(attachment_downloader_
);
166 // AttachmentService::Delegate implementation.
167 virtual void OnAttachmentUploaded(
168 const AttachmentId
& attachment_id
) OVERRIDE
{
169 on_attachment_uploaded_list_
.push_back(attachment_id
);
172 void InitializeAttachmentService(
173 scoped_ptr
<MockAttachmentUploader
> uploader
,
174 scoped_ptr
<MockAttachmentDownloader
> downloader
,
175 AttachmentService::Delegate
* delegate
) {
176 scoped_ptr
<MockAttachmentStore
> attachment_store(new MockAttachmentStore());
177 attachment_store_
= attachment_store
->AsWeakPtr();
179 if (uploader
.get()) {
180 attachment_uploader_
= uploader
->AsWeakPtr();
182 if (downloader
.get()) {
183 attachment_downloader_
= downloader
->AsWeakPtr();
185 attachment_service_
.reset(
186 new AttachmentServiceImpl(attachment_store
.PassAs
<AttachmentStore
>(),
187 uploader
.PassAs
<AttachmentUploader
>(),
188 downloader
.PassAs
<AttachmentDownloader
>(),
192 AttachmentService
* attachment_service() { return attachment_service_
.get(); }
194 AttachmentService::GetOrDownloadCallback
download_callback() {
195 return base::Bind(&AttachmentServiceImplTest::DownloadDone
,
196 base::Unretained(this));
199 AttachmentService::StoreCallback
store_callback() {
200 return base::Bind(&AttachmentServiceImplTest::StoreDone
,
201 base::Unretained(this));
204 void DownloadDone(const AttachmentService::GetOrDownloadResult
& result
,
205 scoped_ptr
<AttachmentMap
> attachments
) {
206 download_results_
.push_back(result
);
207 last_download_attachments_
= attachments
.Pass();
210 void StoreDone(const AttachmentService::StoreResult
& result
) {
211 store_results_
.push_back(result
);
215 base::RunLoop run_loop
;
216 run_loop
.RunUntilIdle();
219 const std::vector
<AttachmentService::GetOrDownloadResult
>&
220 download_results() const {
221 return download_results_
;
224 const AttachmentMap
& last_download_attachments() const {
225 return *last_download_attachments_
.get();
228 const std::vector
<AttachmentService::StoreResult
>& store_results() const {
229 return store_results_
;
232 MockAttachmentStore
* store() { return attachment_store_
.get(); }
234 MockAttachmentDownloader
* downloader() {
235 return attachment_downloader_
.get();
238 MockAttachmentUploader
* uploader() {
239 return attachment_uploader_
.get();
242 const std::vector
<AttachmentId
>& on_attachment_uploaded_list() const {
243 return on_attachment_uploaded_list_
;
247 base::MessageLoop message_loop_
;
248 base::WeakPtr
<MockAttachmentStore
> attachment_store_
;
249 base::WeakPtr
<MockAttachmentDownloader
> attachment_downloader_
;
250 base::WeakPtr
<MockAttachmentUploader
> attachment_uploader_
;
251 scoped_ptr
<AttachmentService
> attachment_service_
;
253 std::vector
<AttachmentService::GetOrDownloadResult
> download_results_
;
254 scoped_ptr
<AttachmentMap
> last_download_attachments_
;
255 std::vector
<AttachmentId
> on_attachment_uploaded_list_
;
257 std::vector
<AttachmentService::StoreResult
> store_results_
;
260 TEST_F(AttachmentServiceImplTest
, GetOrDownload_EmptyAttachmentList
) {
261 AttachmentIdList attachment_ids
;
262 attachment_service()->GetOrDownloadAttachments(attachment_ids
,
263 download_callback());
264 store()->RespondToRead(AttachmentIdSet());
267 EXPECT_EQ(1U, download_results().size());
268 EXPECT_EQ(0U, last_download_attachments().size());
271 TEST_F(AttachmentServiceImplTest
, GetOrDownload_Local
) {
272 AttachmentIdList attachment_ids
;
273 attachment_ids
.push_back(AttachmentId::Create());
274 attachment_service()->GetOrDownloadAttachments(attachment_ids
,
275 download_callback());
276 AttachmentIdSet local_attachments
;
277 local_attachments
.insert(attachment_ids
[0]);
278 store()->RespondToRead(local_attachments
);
281 EXPECT_EQ(1U, download_results().size());
282 EXPECT_EQ(1U, last_download_attachments().size());
283 EXPECT_TRUE(last_download_attachments().find(attachment_ids
[0]) !=
284 last_download_attachments().end());
287 TEST_F(AttachmentServiceImplTest
, GetOrDownload_LocalRemoteUnavailable
) {
288 // Create attachment list with 3 ids.
289 AttachmentIdList attachment_ids
;
290 attachment_ids
.push_back(AttachmentId::Create());
291 attachment_ids
.push_back(AttachmentId::Create());
292 attachment_ids
.push_back(AttachmentId::Create());
293 // Call attachment service.
294 attachment_service()->GetOrDownloadAttachments(attachment_ids
,
295 download_callback());
296 // Ensure AttachmentStore is called.
297 EXPECT_FALSE(store()->read_ids
.empty());
299 // make AttachmentStore return only attachment 0.
300 AttachmentIdSet local_attachments
;
301 local_attachments
.insert(attachment_ids
[0]);
302 store()->RespondToRead(local_attachments
);
304 // Ensure Downloader called with right attachment ids
305 EXPECT_EQ(2U, downloader()->download_requests
.size());
307 // Make downloader return attachment 1.
308 downloader()->RespondToDownload(attachment_ids
[1],
309 AttachmentDownloader::DOWNLOAD_SUCCESS
);
311 // Ensure consumer callback is not called.
312 EXPECT_TRUE(download_results().empty());
314 // Make downloader fail attachment 2.
315 downloader()->RespondToDownload(
316 attachment_ids
[2], AttachmentDownloader::DOWNLOAD_UNSPECIFIED_ERROR
);
318 // Ensure callback is called
319 EXPECT_FALSE(download_results().empty());
320 // There should be only two attachments returned, 0 and 1.
321 EXPECT_EQ(2U, last_download_attachments().size());
322 EXPECT_TRUE(last_download_attachments().find(attachment_ids
[0]) !=
323 last_download_attachments().end());
324 EXPECT_TRUE(last_download_attachments().find(attachment_ids
[1]) !=
325 last_download_attachments().end());
326 EXPECT_TRUE(last_download_attachments().find(attachment_ids
[2]) ==
327 last_download_attachments().end());
330 TEST_F(AttachmentServiceImplTest
, GetOrDownload_NoDownloader
) {
332 InitializeAttachmentService(
333 make_scoped_ptr
<MockAttachmentUploader
>(new MockAttachmentUploader()),
334 make_scoped_ptr
<MockAttachmentDownloader
>(NULL
),
337 AttachmentIdList attachment_ids
;
338 attachment_ids
.push_back(AttachmentId::Create());
339 attachment_service()->GetOrDownloadAttachments(attachment_ids
,
340 download_callback());
341 EXPECT_FALSE(store()->read_ids
.empty());
343 AttachmentIdSet local_attachments
;
344 store()->RespondToRead(local_attachments
);
346 ASSERT_EQ(1U, download_results().size());
347 EXPECT_EQ(AttachmentService::GET_UNSPECIFIED_ERROR
, download_results()[0]);
348 EXPECT_TRUE(last_download_attachments().empty());
351 TEST_F(AttachmentServiceImplTest
, StoreAttachments_Success
) {
352 scoped_refptr
<base::RefCountedString
> data
= new base::RefCountedString();
353 Attachment
attachment(Attachment::Create(data
));
354 AttachmentList attachments
;
355 attachments
.push_back(attachment
);
356 attachment_service()->StoreAttachments(attachments
, store_callback());
357 EXPECT_EQ(1U, store()->write_attachments
.size());
358 EXPECT_EQ(1U, uploader()->upload_requests
.size());
360 store()->RespondToWrite(AttachmentStore::SUCCESS
);
361 uploader()->RespondToUpload(attachment
.GetId(),
362 AttachmentUploader::UPLOAD_SUCCESS
);
364 ASSERT_EQ(1U, store_results().size());
365 EXPECT_EQ(AttachmentService::STORE_SUCCESS
, store_results()[0]);
366 ASSERT_EQ(1U, on_attachment_uploaded_list().size());
367 EXPECT_EQ(attachment
.GetId(), on_attachment_uploaded_list()[0]);
370 TEST_F(AttachmentServiceImplTest
,
371 StoreAttachments_StoreFailsWithUnspecifiedError
) {
372 scoped_refptr
<base::RefCountedString
> data
= new base::RefCountedString();
373 Attachment
attachment(Attachment::Create(data
));
374 AttachmentList attachments
;
375 attachments
.push_back(attachment
);
376 attachment_service()->StoreAttachments(attachments
, store_callback());
377 EXPECT_EQ(1U, store()->write_attachments
.size());
378 EXPECT_EQ(1U, uploader()->upload_requests
.size());
380 store()->RespondToWrite(AttachmentStore::UNSPECIFIED_ERROR
);
381 uploader()->RespondToUpload(attachment
.GetId(),
382 AttachmentUploader::UPLOAD_SUCCESS
);
384 ASSERT_EQ(1U, store_results().size());
385 EXPECT_EQ(AttachmentService::STORE_UNSPECIFIED_ERROR
, store_results()[0]);
386 ASSERT_EQ(1U, on_attachment_uploaded_list().size());
387 EXPECT_EQ(attachment
.GetId(), on_attachment_uploaded_list()[0]);
390 TEST_F(AttachmentServiceImplTest
,
391 StoreAttachments_UploadFailsWithUnspecifiedError
) {
392 scoped_refptr
<base::RefCountedString
> data
= new base::RefCountedString();
393 Attachment
attachment(Attachment::Create(data
));
394 AttachmentList attachments
;
395 attachments
.push_back(attachment
);
396 attachment_service()->StoreAttachments(attachments
, store_callback());
397 EXPECT_EQ(1U, store()->write_attachments
.size());
398 EXPECT_EQ(1U, uploader()->upload_requests
.size());
400 store()->RespondToWrite(AttachmentStore::SUCCESS
);
401 uploader()->RespondToUpload(attachment
.GetId(),
402 AttachmentUploader::UPLOAD_UNSPECIFIED_ERROR
);
404 ASSERT_EQ(1U, store_results().size());
405 // Even though the upload failed, the Store operation is successful.
406 EXPECT_EQ(AttachmentService::STORE_SUCCESS
, store_results()[0]);
407 EXPECT_TRUE(on_attachment_uploaded_list().empty());
410 TEST_F(AttachmentServiceImplTest
, StoreAttachments_NoDelegate
) {
411 InitializeAttachmentService(make_scoped_ptr(new MockAttachmentUploader()),
412 make_scoped_ptr(new MockAttachmentDownloader()),
413 NULL
); // No delegate.
415 scoped_refptr
<base::RefCountedString
> data
= new base::RefCountedString();
416 Attachment
attachment(Attachment::Create(data
));
417 AttachmentList attachments
;
418 attachments
.push_back(attachment
);
419 attachment_service()->StoreAttachments(attachments
, store_callback());
420 EXPECT_EQ(1U, store()->write_attachments
.size());
421 EXPECT_EQ(1U, uploader()->upload_requests
.size());
423 store()->RespondToWrite(AttachmentStore::SUCCESS
);
424 uploader()->RespondToUpload(attachment
.GetId(),
425 AttachmentUploader::UPLOAD_SUCCESS
);
427 ASSERT_EQ(1U, store_results().size());
428 EXPECT_EQ(AttachmentService::STORE_SUCCESS
, store_results()[0]);
429 EXPECT_TRUE(on_attachment_uploaded_list().empty());
432 TEST_F(AttachmentServiceImplTest
, StoreAttachments_NoUploader
) {
434 InitializeAttachmentService(make_scoped_ptr
<MockAttachmentUploader
>(NULL
),
435 make_scoped_ptr(new MockAttachmentDownloader()),
438 scoped_refptr
<base::RefCountedString
> data
= new base::RefCountedString();
439 Attachment
attachment(Attachment::Create(data
));
440 AttachmentList attachments
;
441 attachments
.push_back(attachment
);
442 attachment_service()->StoreAttachments(attachments
, store_callback());
443 EXPECT_EQ(1U, store()->write_attachments
.size());
445 store()->RespondToWrite(AttachmentStore::SUCCESS
);
447 ASSERT_EQ(1U, store_results().size());
448 EXPECT_EQ(AttachmentService::STORE_SUCCESS
, store_results()[0]);
449 EXPECT_TRUE(on_attachment_uploaded_list().empty());
452 } // namespace syncer