OLD | NEW |
| (Empty) |
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/api/attachments/attachment_service_impl.h" | |
6 | |
7 #include "base/bind.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" | |
14 | |
15 namespace syncer { | |
16 | |
17 class MockAttachmentStore : public AttachmentStore, | |
18 public base::SupportsWeakPtr<MockAttachmentStore> { | |
19 public: | |
20 MockAttachmentStore() {} | |
21 | |
22 virtual void Read(const AttachmentIdList& ids, | |
23 const ReadCallback& callback) OVERRIDE { | |
24 read_ids.push_back(ids); | |
25 read_callbacks.push_back(callback); | |
26 } | |
27 | |
28 virtual void Write(const AttachmentList& attachments, | |
29 const WriteCallback& callback) OVERRIDE { | |
30 write_attachments.push_back(attachments); | |
31 write_callbacks.push_back(callback); | |
32 } | |
33 | |
34 virtual void Drop(const AttachmentIdList& ids, | |
35 const DropCallback& callback) OVERRIDE { | |
36 NOTREACHED(); | |
37 } | |
38 | |
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(); | |
46 read_ids.pop_back(); | |
47 | |
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(); | |
52 ++iter) { | |
53 if (local_attachments.find(*iter) != local_attachments.end()) { | |
54 Attachment attachment = Attachment::CreateWithId(*iter, data); | |
55 attachments->insert(std::make_pair(*iter, attachment)); | |
56 } else { | |
57 unavailable_attachments->push_back(*iter); | |
58 } | |
59 } | |
60 Result result = | |
61 unavailable_attachments->empty() ? SUCCESS : UNSPECIFIED_ERROR; | |
62 | |
63 base::MessageLoop::current()->PostTask( | |
64 FROM_HERE, | |
65 base::Bind(callback, | |
66 result, | |
67 base::Passed(&attachments), | |
68 base::Passed(&unavailable_attachments))); | |
69 } | |
70 | |
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)); | |
79 } | |
80 | |
81 std::vector<AttachmentIdList> read_ids; | |
82 std::vector<ReadCallback> read_callbacks; | |
83 std::vector<AttachmentList> write_attachments; | |
84 std::vector<WriteCallback> write_callbacks; | |
85 | |
86 DISALLOW_COPY_AND_ASSIGN(MockAttachmentStore); | |
87 }; | |
88 | |
89 class MockAttachmentDownloader | |
90 : public AttachmentDownloader, | |
91 public base::SupportsWeakPtr<MockAttachmentDownloader> { | |
92 public: | |
93 MockAttachmentDownloader() {} | |
94 | |
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)); | |
99 } | |
100 | |
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))); | |
109 } | |
110 base::MessageLoop::current()->PostTask( | |
111 FROM_HERE, | |
112 base::Bind(download_requests[id], result, base::Passed(&attachment))); | |
113 | |
114 download_requests.erase(id); | |
115 } | |
116 | |
117 std::map<AttachmentId, DownloadCallback> download_requests; | |
118 | |
119 DISALLOW_COPY_AND_ASSIGN(MockAttachmentDownloader); | |
120 }; | |
121 | |
122 class MockAttachmentUploader | |
123 : public AttachmentUploader, | |
124 public base::SupportsWeakPtr<MockAttachmentUploader> { | |
125 public: | |
126 MockAttachmentUploader() {} | |
127 | |
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)); | |
134 } | |
135 | |
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); | |
141 } | |
142 | |
143 std::map<AttachmentId, UploadCallback> upload_requests; | |
144 | |
145 DISALLOW_COPY_AND_ASSIGN(MockAttachmentUploader); | |
146 }; | |
147 | |
148 class AttachmentServiceImplTest : public testing::Test, | |
149 public AttachmentService::Delegate { | |
150 protected: | |
151 AttachmentServiceImplTest() {} | |
152 | |
153 virtual void SetUp() OVERRIDE { | |
154 InitializeAttachmentService(make_scoped_ptr(new MockAttachmentUploader()), | |
155 make_scoped_ptr(new MockAttachmentDownloader()), | |
156 this); | |
157 } | |
158 | |
159 virtual void TearDown() OVERRIDE { | |
160 attachment_service_.reset(); | |
161 ASSERT_FALSE(attachment_store_); | |
162 ASSERT_FALSE(attachment_uploader_); | |
163 ASSERT_FALSE(attachment_downloader_); | |
164 } | |
165 | |
166 // AttachmentService::Delegate implementation. | |
167 virtual void OnAttachmentUploaded( | |
168 const AttachmentId& attachment_id) OVERRIDE { | |
169 on_attachment_uploaded_list_.push_back(attachment_id); | |
170 } | |
171 | |
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(); | |
178 | |
179 if (uploader.get()) { | |
180 attachment_uploader_ = uploader->AsWeakPtr(); | |
181 } | |
182 if (downloader.get()) { | |
183 attachment_downloader_ = downloader->AsWeakPtr(); | |
184 } | |
185 attachment_service_.reset( | |
186 new AttachmentServiceImpl(attachment_store.PassAs<AttachmentStore>(), | |
187 uploader.PassAs<AttachmentUploader>(), | |
188 downloader.PassAs<AttachmentDownloader>(), | |
189 delegate)); | |
190 } | |
191 | |
192 AttachmentService* attachment_service() { return attachment_service_.get(); } | |
193 | |
194 AttachmentService::GetOrDownloadCallback download_callback() { | |
195 return base::Bind(&AttachmentServiceImplTest::DownloadDone, | |
196 base::Unretained(this)); | |
197 } | |
198 | |
199 AttachmentService::StoreCallback store_callback() { | |
200 return base::Bind(&AttachmentServiceImplTest::StoreDone, | |
201 base::Unretained(this)); | |
202 } | |
203 | |
204 void DownloadDone(const AttachmentService::GetOrDownloadResult& result, | |
205 scoped_ptr<AttachmentMap> attachments) { | |
206 download_results_.push_back(result); | |
207 last_download_attachments_ = attachments.Pass(); | |
208 } | |
209 | |
210 void StoreDone(const AttachmentService::StoreResult& result) { | |
211 store_results_.push_back(result); | |
212 } | |
213 | |
214 void RunLoop() { | |
215 base::RunLoop run_loop; | |
216 run_loop.RunUntilIdle(); | |
217 } | |
218 | |
219 const std::vector<AttachmentService::GetOrDownloadResult>& | |
220 download_results() const { | |
221 return download_results_; | |
222 } | |
223 | |
224 const AttachmentMap& last_download_attachments() const { | |
225 return *last_download_attachments_.get(); | |
226 } | |
227 | |
228 const std::vector<AttachmentService::StoreResult>& store_results() const { | |
229 return store_results_; | |
230 } | |
231 | |
232 MockAttachmentStore* store() { return attachment_store_.get(); } | |
233 | |
234 MockAttachmentDownloader* downloader() { | |
235 return attachment_downloader_.get(); | |
236 } | |
237 | |
238 MockAttachmentUploader* uploader() { | |
239 return attachment_uploader_.get(); | |
240 } | |
241 | |
242 const std::vector<AttachmentId>& on_attachment_uploaded_list() const { | |
243 return on_attachment_uploaded_list_; | |
244 } | |
245 | |
246 private: | |
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_; | |
252 | |
253 std::vector<AttachmentService::GetOrDownloadResult> download_results_; | |
254 scoped_ptr<AttachmentMap> last_download_attachments_; | |
255 std::vector<AttachmentId> on_attachment_uploaded_list_; | |
256 | |
257 std::vector<AttachmentService::StoreResult> store_results_; | |
258 }; | |
259 | |
260 TEST_F(AttachmentServiceImplTest, GetOrDownload_EmptyAttachmentList) { | |
261 AttachmentIdList attachment_ids; | |
262 attachment_service()->GetOrDownloadAttachments(attachment_ids, | |
263 download_callback()); | |
264 store()->RespondToRead(AttachmentIdSet()); | |
265 | |
266 RunLoop(); | |
267 EXPECT_EQ(1U, download_results().size()); | |
268 EXPECT_EQ(0U, last_download_attachments().size()); | |
269 } | |
270 | |
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); | |
279 | |
280 RunLoop(); | |
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()); | |
285 } | |
286 | |
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()); | |
298 | |
299 // make AttachmentStore return only attachment 0. | |
300 AttachmentIdSet local_attachments; | |
301 local_attachments.insert(attachment_ids[0]); | |
302 store()->RespondToRead(local_attachments); | |
303 RunLoop(); | |
304 // Ensure Downloader called with right attachment ids | |
305 EXPECT_EQ(2U, downloader()->download_requests.size()); | |
306 | |
307 // Make downloader return attachment 1. | |
308 downloader()->RespondToDownload(attachment_ids[1], | |
309 AttachmentDownloader::DOWNLOAD_SUCCESS); | |
310 RunLoop(); | |
311 // Ensure consumer callback is not called. | |
312 EXPECT_TRUE(download_results().empty()); | |
313 | |
314 // Make downloader fail attachment 2. | |
315 downloader()->RespondToDownload( | |
316 attachment_ids[2], AttachmentDownloader::DOWNLOAD_UNSPECIFIED_ERROR); | |
317 RunLoop(); | |
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()); | |
328 } | |
329 | |
330 TEST_F(AttachmentServiceImplTest, GetOrDownload_NoDownloader) { | |
331 // No downloader. | |
332 InitializeAttachmentService( | |
333 make_scoped_ptr<MockAttachmentUploader>(new MockAttachmentUploader()), | |
334 make_scoped_ptr<MockAttachmentDownloader>(NULL), | |
335 this); | |
336 | |
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()); | |
342 | |
343 AttachmentIdSet local_attachments; | |
344 store()->RespondToRead(local_attachments); | |
345 RunLoop(); | |
346 ASSERT_EQ(1U, download_results().size()); | |
347 EXPECT_EQ(AttachmentService::GET_UNSPECIFIED_ERROR, download_results()[0]); | |
348 EXPECT_TRUE(last_download_attachments().empty()); | |
349 } | |
350 | |
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()); | |
359 | |
360 store()->RespondToWrite(AttachmentStore::SUCCESS); | |
361 uploader()->RespondToUpload(attachment.GetId(), | |
362 AttachmentUploader::UPLOAD_SUCCESS); | |
363 RunLoop(); | |
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]); | |
368 } | |
369 | |
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()); | |
379 | |
380 store()->RespondToWrite(AttachmentStore::UNSPECIFIED_ERROR); | |
381 uploader()->RespondToUpload(attachment.GetId(), | |
382 AttachmentUploader::UPLOAD_SUCCESS); | |
383 RunLoop(); | |
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]); | |
388 } | |
389 | |
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()); | |
399 | |
400 store()->RespondToWrite(AttachmentStore::SUCCESS); | |
401 uploader()->RespondToUpload(attachment.GetId(), | |
402 AttachmentUploader::UPLOAD_UNSPECIFIED_ERROR); | |
403 RunLoop(); | |
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()); | |
408 } | |
409 | |
410 TEST_F(AttachmentServiceImplTest, StoreAttachments_NoDelegate) { | |
411 InitializeAttachmentService(make_scoped_ptr(new MockAttachmentUploader()), | |
412 make_scoped_ptr(new MockAttachmentDownloader()), | |
413 NULL); // No delegate. | |
414 | |
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()); | |
422 | |
423 store()->RespondToWrite(AttachmentStore::SUCCESS); | |
424 uploader()->RespondToUpload(attachment.GetId(), | |
425 AttachmentUploader::UPLOAD_SUCCESS); | |
426 RunLoop(); | |
427 ASSERT_EQ(1U, store_results().size()); | |
428 EXPECT_EQ(AttachmentService::STORE_SUCCESS, store_results()[0]); | |
429 EXPECT_TRUE(on_attachment_uploaded_list().empty()); | |
430 } | |
431 | |
432 TEST_F(AttachmentServiceImplTest, StoreAttachments_NoUploader) { | |
433 // No uploader. | |
434 InitializeAttachmentService(make_scoped_ptr<MockAttachmentUploader>(NULL), | |
435 make_scoped_ptr(new MockAttachmentDownloader()), | |
436 this); | |
437 | |
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()); | |
444 | |
445 store()->RespondToWrite(AttachmentStore::SUCCESS); | |
446 RunLoop(); | |
447 ASSERT_EQ(1U, store_results().size()); | |
448 EXPECT_EQ(AttachmentService::STORE_SUCCESS, store_results()[0]); | |
449 EXPECT_TRUE(on_attachment_uploaded_list().empty()); | |
450 } | |
451 | |
452 } // namespace syncer | |
OLD | NEW |