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/internal_api/public/attachments/attachment_service_impl.h" | |
6 | |
7 #include <algorithm> | |
8 #include <map> | |
9 #include <utility> | |
10 #include <vector> | |
11 | |
12 #include "base/bind.h" | |
13 #include "base/location.h" | |
14 #include "base/macros.h" | |
15 #include "base/memory/ptr_util.h" | |
16 #include "base/memory/weak_ptr.h" | |
17 #include "base/message_loop/message_loop.h" | |
18 #include "base/run_loop.h" | |
19 #include "base/single_thread_task_runner.h" | |
20 #include "base/threading/thread_task_runner_handle.h" | |
21 #include "base/timer/mock_timer.h" | |
22 #include "sync/api/attachments/attachment_store_backend.h" | |
23 #include "sync/internal_api/public/attachments/attachment_util.h" | |
24 #include "sync/internal_api/public/attachments/fake_attachment_downloader.h" | |
25 #include "sync/internal_api/public/attachments/fake_attachment_uploader.h" | |
26 #include "testing/gmock/include/gmock/gmock-matchers.h" | |
27 #include "testing/gtest/include/gtest/gtest.h" | |
28 | |
29 namespace syncer { | |
30 | |
31 namespace { | |
32 | |
33 class MockAttachmentStoreBackend | |
34 : public AttachmentStoreBackend, | |
35 public base::SupportsWeakPtr<MockAttachmentStoreBackend> { | |
36 public: | |
37 MockAttachmentStoreBackend( | |
38 const scoped_refptr<base::SequencedTaskRunner>& callback_task_runner) | |
39 : AttachmentStoreBackend(callback_task_runner) {} | |
40 | |
41 ~MockAttachmentStoreBackend() override {} | |
42 | |
43 void Init(const AttachmentStore::InitCallback& callback) override {} | |
44 | |
45 void Read(AttachmentStore::Component component, | |
46 const AttachmentIdList& ids, | |
47 const AttachmentStore::ReadCallback& callback) override { | |
48 read_ids.push_back(ids); | |
49 read_callbacks.push_back(callback); | |
50 } | |
51 | |
52 void Write(AttachmentStore::Component component, | |
53 const AttachmentList& attachments, | |
54 const AttachmentStore::WriteCallback& callback) override { | |
55 write_attachments.push_back(attachments); | |
56 write_callbacks.push_back(callback); | |
57 } | |
58 | |
59 void SetReference(AttachmentStore::Component component, | |
60 const AttachmentIdList& ids) override { | |
61 set_reference_ids.push_back(std::make_pair(component, ids)); | |
62 } | |
63 | |
64 void DropReference(AttachmentStore::Component component, | |
65 const AttachmentIdList& ids, | |
66 const AttachmentStore::DropCallback& callback) override { | |
67 ASSERT_EQ(AttachmentStore::SYNC, component); | |
68 drop_ids.push_back(ids); | |
69 } | |
70 | |
71 void ReadMetadataById( | |
72 AttachmentStore::Component component, | |
73 const AttachmentIdList& ids, | |
74 const AttachmentStore::ReadMetadataCallback& callback) override { | |
75 NOTREACHED(); | |
76 } | |
77 | |
78 void ReadMetadata( | |
79 AttachmentStore::Component component, | |
80 const AttachmentStore::ReadMetadataCallback& callback) override { | |
81 NOTREACHED(); | |
82 } | |
83 | |
84 // Respond to Read request. Attachments found in local_attachments should be | |
85 // returned, everything else should be reported unavailable. | |
86 void RespondToRead(const AttachmentIdSet& local_attachments) { | |
87 scoped_refptr<base::RefCountedString> data = new base::RefCountedString(); | |
88 AttachmentStore::ReadCallback callback = read_callbacks.back(); | |
89 AttachmentIdList ids = read_ids.back(); | |
90 read_callbacks.pop_back(); | |
91 read_ids.pop_back(); | |
92 | |
93 std::unique_ptr<AttachmentMap> attachments(new AttachmentMap()); | |
94 std::unique_ptr<AttachmentIdList> unavailable_attachments( | |
95 new AttachmentIdList()); | |
96 for (AttachmentIdList::const_iterator iter = ids.begin(); iter != ids.end(); | |
97 ++iter) { | |
98 if (local_attachments.find(*iter) != local_attachments.end()) { | |
99 Attachment attachment = Attachment::CreateFromParts(*iter, data); | |
100 attachments->insert(std::make_pair(*iter, attachment)); | |
101 } else { | |
102 unavailable_attachments->push_back(*iter); | |
103 } | |
104 } | |
105 AttachmentStore::Result result = unavailable_attachments->empty() | |
106 ? AttachmentStore::SUCCESS | |
107 : AttachmentStore::UNSPECIFIED_ERROR; | |
108 | |
109 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
110 FROM_HERE, base::Bind(callback, result, base::Passed(&attachments), | |
111 base::Passed(&unavailable_attachments))); | |
112 } | |
113 | |
114 // Respond to Write request with |result|. | |
115 void RespondToWrite(const AttachmentStore::Result& result) { | |
116 AttachmentStore::WriteCallback callback = write_callbacks.back(); | |
117 write_callbacks.pop_back(); | |
118 write_attachments.pop_back(); | |
119 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, | |
120 base::Bind(callback, result)); | |
121 } | |
122 | |
123 std::vector<AttachmentIdList> read_ids; | |
124 std::vector<AttachmentStore::ReadCallback> read_callbacks; | |
125 std::vector<AttachmentList> write_attachments; | |
126 std::vector<AttachmentStore::WriteCallback> write_callbacks; | |
127 std::vector<std::pair<AttachmentStore::Component, AttachmentIdList>> | |
128 set_reference_ids; | |
129 std::vector<AttachmentIdList> drop_ids; | |
130 | |
131 private: | |
132 DISALLOW_COPY_AND_ASSIGN(MockAttachmentStoreBackend); | |
133 }; | |
134 | |
135 class MockAttachmentDownloader | |
136 : public AttachmentDownloader, | |
137 public base::SupportsWeakPtr<MockAttachmentDownloader> { | |
138 public: | |
139 MockAttachmentDownloader() {} | |
140 | |
141 void DownloadAttachment(const AttachmentId& id, | |
142 const DownloadCallback& callback) override { | |
143 ASSERT_TRUE(download_requests.find(id) == download_requests.end()); | |
144 download_requests.insert(std::make_pair(id, callback)); | |
145 } | |
146 | |
147 // Multiple requests to download will be active at the same time. | |
148 // RespondToDownload should respond to only one of them. | |
149 void RespondToDownload(const AttachmentId& id, const DownloadResult& result) { | |
150 ASSERT_TRUE(download_requests.find(id) != download_requests.end()); | |
151 std::unique_ptr<Attachment> attachment; | |
152 if (result == DOWNLOAD_SUCCESS) { | |
153 scoped_refptr<base::RefCountedString> data = new base::RefCountedString(); | |
154 attachment.reset(new Attachment(Attachment::CreateFromParts(id, data))); | |
155 } | |
156 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
157 FROM_HERE, | |
158 base::Bind(download_requests[id], result, base::Passed(&attachment))); | |
159 | |
160 download_requests.erase(id); | |
161 } | |
162 | |
163 std::map<AttachmentId, DownloadCallback> download_requests; | |
164 | |
165 private: | |
166 DISALLOW_COPY_AND_ASSIGN(MockAttachmentDownloader); | |
167 }; | |
168 | |
169 class MockAttachmentUploader | |
170 : public AttachmentUploader, | |
171 public base::SupportsWeakPtr<MockAttachmentUploader> { | |
172 public: | |
173 MockAttachmentUploader() {} | |
174 | |
175 // AttachmentUploader implementation. | |
176 void UploadAttachment(const Attachment& attachment, | |
177 const UploadCallback& callback) override { | |
178 const AttachmentId id = attachment.GetId(); | |
179 ASSERT_TRUE(upload_requests.find(id) == upload_requests.end()); | |
180 upload_requests.insert(std::make_pair(id, callback)); | |
181 } | |
182 | |
183 void RespondToUpload(const AttachmentId& id, const UploadResult& result) { | |
184 ASSERT_TRUE(upload_requests.find(id) != upload_requests.end()); | |
185 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
186 FROM_HERE, base::Bind(upload_requests[id], result, id)); | |
187 upload_requests.erase(id); | |
188 } | |
189 | |
190 std::map<AttachmentId, UploadCallback> upload_requests; | |
191 | |
192 private: | |
193 DISALLOW_COPY_AND_ASSIGN(MockAttachmentUploader); | |
194 }; | |
195 | |
196 } // namespace | |
197 | |
198 class AttachmentServiceImplTest : public testing::Test, | |
199 public AttachmentService::Delegate { | |
200 protected: | |
201 AttachmentServiceImplTest() {} | |
202 | |
203 void SetUp() override { | |
204 network_change_notifier_.reset(net::NetworkChangeNotifier::CreateMock()); | |
205 InitializeAttachmentService( | |
206 base::WrapUnique(new MockAttachmentUploader()), | |
207 base::WrapUnique(new MockAttachmentDownloader()), this); | |
208 } | |
209 | |
210 void TearDown() override { | |
211 attachment_service_.reset(); | |
212 RunLoop(); | |
213 ASSERT_FALSE(attachment_store_backend_); | |
214 ASSERT_FALSE(attachment_uploader_); | |
215 ASSERT_FALSE(attachment_downloader_); | |
216 } | |
217 | |
218 // AttachmentService::Delegate implementation. | |
219 void OnAttachmentUploaded(const AttachmentId& attachment_id) override { | |
220 on_attachment_uploaded_list_.push_back(attachment_id); | |
221 } | |
222 | |
223 void InitializeAttachmentService( | |
224 std::unique_ptr<MockAttachmentUploader> uploader, | |
225 std::unique_ptr<MockAttachmentDownloader> downloader, | |
226 AttachmentService::Delegate* delegate) { | |
227 // Initialize mock attachment store | |
228 scoped_refptr<base::SingleThreadTaskRunner> runner = | |
229 base::ThreadTaskRunnerHandle::Get(); | |
230 std::unique_ptr<MockAttachmentStoreBackend> attachment_store_backend( | |
231 new MockAttachmentStoreBackend(runner)); | |
232 attachment_store_backend_ = attachment_store_backend->AsWeakPtr(); | |
233 std::unique_ptr<AttachmentStore> attachment_store = | |
234 AttachmentStore::CreateMockStoreForTest( | |
235 std::move(attachment_store_backend)); | |
236 | |
237 if (uploader.get()) { | |
238 attachment_uploader_ = uploader->AsWeakPtr(); | |
239 } | |
240 if (downloader.get()) { | |
241 attachment_downloader_ = downloader->AsWeakPtr(); | |
242 } | |
243 attachment_service_.reset(new AttachmentServiceImpl( | |
244 attachment_store->CreateAttachmentStoreForSync(), std::move(uploader), | |
245 std::move(downloader), delegate, base::TimeDelta::FromMinutes(1), | |
246 base::TimeDelta::FromMinutes(8))); | |
247 | |
248 std::unique_ptr<base::MockTimer> timer_to_pass( | |
249 new base::MockTimer(false, false)); | |
250 mock_timer_ = timer_to_pass.get(); | |
251 attachment_service_->SetTimerForTest(std::move(timer_to_pass)); | |
252 } | |
253 | |
254 AttachmentService* attachment_service() { return attachment_service_.get(); } | |
255 | |
256 base::MockTimer* mock_timer() { return mock_timer_; } | |
257 | |
258 AttachmentService::GetOrDownloadCallback download_callback() { | |
259 return base::Bind(&AttachmentServiceImplTest::DownloadDone, | |
260 base::Unretained(this)); | |
261 } | |
262 | |
263 void DownloadDone(const AttachmentService::GetOrDownloadResult& result, | |
264 std::unique_ptr<AttachmentMap> attachments) { | |
265 download_results_.push_back(result); | |
266 last_download_attachments_ = std::move(attachments); | |
267 } | |
268 | |
269 void RunLoop() { | |
270 base::RunLoop run_loop; | |
271 run_loop.RunUntilIdle(); | |
272 } | |
273 | |
274 void RunLoopAndFireTimer() { | |
275 RunLoop(); | |
276 if (mock_timer()->IsRunning()) { | |
277 mock_timer()->Fire(); | |
278 RunLoop(); | |
279 } | |
280 } | |
281 | |
282 static AttachmentIdSet AttachmentIdSetFromList( | |
283 const AttachmentIdList& id_list) { | |
284 AttachmentIdSet id_set; | |
285 std::copy(id_list.begin(), id_list.end(), | |
286 std::inserter(id_set, id_set.end())); | |
287 return id_set; | |
288 } | |
289 | |
290 const std::vector<AttachmentService::GetOrDownloadResult>& | |
291 download_results() const { | |
292 return download_results_; | |
293 } | |
294 | |
295 const AttachmentMap& last_download_attachments() const { | |
296 return *last_download_attachments_.get(); | |
297 } | |
298 | |
299 net::NetworkChangeNotifier* network_change_notifier() { | |
300 return network_change_notifier_.get(); | |
301 } | |
302 | |
303 MockAttachmentStoreBackend* store() { | |
304 return attachment_store_backend_.get(); | |
305 } | |
306 | |
307 MockAttachmentDownloader* downloader() { | |
308 return attachment_downloader_.get(); | |
309 } | |
310 | |
311 MockAttachmentUploader* uploader() { | |
312 return attachment_uploader_.get(); | |
313 } | |
314 | |
315 const std::vector<AttachmentId>& on_attachment_uploaded_list() const { | |
316 return on_attachment_uploaded_list_; | |
317 } | |
318 | |
319 private: | |
320 base::MessageLoop message_loop_; | |
321 std::unique_ptr<net::NetworkChangeNotifier> network_change_notifier_; | |
322 base::WeakPtr<MockAttachmentStoreBackend> attachment_store_backend_; | |
323 base::WeakPtr<MockAttachmentDownloader> attachment_downloader_; | |
324 base::WeakPtr<MockAttachmentUploader> attachment_uploader_; | |
325 std::unique_ptr<AttachmentServiceImpl> attachment_service_; | |
326 base::MockTimer* mock_timer_; // not owned | |
327 | |
328 std::vector<AttachmentService::GetOrDownloadResult> download_results_; | |
329 std::unique_ptr<AttachmentMap> last_download_attachments_; | |
330 std::vector<AttachmentId> on_attachment_uploaded_list_; | |
331 }; | |
332 | |
333 TEST_F(AttachmentServiceImplTest, GetOrDownload_EmptyAttachmentList) { | |
334 AttachmentIdList attachment_ids; | |
335 attachment_service()->GetOrDownloadAttachments(attachment_ids, | |
336 download_callback()); | |
337 RunLoop(); | |
338 store()->RespondToRead(AttachmentIdSet()); | |
339 | |
340 RunLoop(); | |
341 EXPECT_EQ(1U, download_results().size()); | |
342 EXPECT_EQ(0U, last_download_attachments().size()); | |
343 } | |
344 | |
345 TEST_F(AttachmentServiceImplTest, GetOrDownload_Local) { | |
346 AttachmentIdList attachment_ids; | |
347 attachment_ids.push_back(AttachmentId::Create(0, 0)); | |
348 attachment_service()->GetOrDownloadAttachments(attachment_ids, | |
349 download_callback()); | |
350 AttachmentIdSet local_attachments; | |
351 local_attachments.insert(attachment_ids[0]); | |
352 RunLoop(); | |
353 EXPECT_EQ(1U, store()->set_reference_ids.size()); | |
354 EXPECT_EQ(AttachmentStore::MODEL_TYPE, store()->set_reference_ids[0].first); | |
355 store()->RespondToRead(local_attachments); | |
356 | |
357 RunLoop(); | |
358 EXPECT_EQ(1U, download_results().size()); | |
359 EXPECT_EQ(1U, last_download_attachments().size()); | |
360 EXPECT_TRUE(last_download_attachments().find(attachment_ids[0]) != | |
361 last_download_attachments().end()); | |
362 } | |
363 | |
364 TEST_F(AttachmentServiceImplTest, GetOrDownload_LocalRemoteUnavailable) { | |
365 // Create attachment list with 4 ids. | |
366 AttachmentIdList attachment_ids; | |
367 attachment_ids.push_back(AttachmentId::Create(0, 0)); | |
368 attachment_ids.push_back(AttachmentId::Create(0, 0)); | |
369 attachment_ids.push_back(AttachmentId::Create(0, 0)); | |
370 attachment_ids.push_back(AttachmentId::Create(0, 0)); | |
371 // Call attachment service. | |
372 attachment_service()->GetOrDownloadAttachments(attachment_ids, | |
373 download_callback()); | |
374 RunLoop(); | |
375 // Ensure AttachmentStore is called. | |
376 EXPECT_FALSE(store()->read_ids.empty()); | |
377 | |
378 // Make AttachmentStore return only attachment 0. | |
379 AttachmentIdSet local_attachments; | |
380 local_attachments.insert(attachment_ids[0]); | |
381 store()->RespondToRead(local_attachments); | |
382 RunLoop(); | |
383 // Ensure Downloader called with right attachment ids | |
384 EXPECT_EQ(3U, downloader()->download_requests.size()); | |
385 | |
386 // Make downloader return attachment 1. | |
387 downloader()->RespondToDownload(attachment_ids[1], | |
388 AttachmentDownloader::DOWNLOAD_SUCCESS); | |
389 RunLoop(); | |
390 // Ensure consumer callback is not called. | |
391 EXPECT_TRUE(download_results().empty()); | |
392 // Make AttachmentStore acknowledge writing attachment 1. | |
393 store()->RespondToWrite(AttachmentStore::SUCCESS); | |
394 RunLoop(); | |
395 // Ensure consumer callback is not called. | |
396 EXPECT_TRUE(download_results().empty()); | |
397 | |
398 // Make downloader return attachment 2. | |
399 downloader()->RespondToDownload(attachment_ids[2], | |
400 AttachmentDownloader::DOWNLOAD_SUCCESS); | |
401 RunLoop(); | |
402 // Ensure consumer callback is not called. | |
403 EXPECT_TRUE(download_results().empty()); | |
404 // Make AttachmentStore fail writing attachment 2. | |
405 store()->RespondToWrite(AttachmentStore::UNSPECIFIED_ERROR); | |
406 RunLoop(); | |
407 // Ensure consumer callback is not called. | |
408 EXPECT_TRUE(download_results().empty()); | |
409 | |
410 // Make downloader fail attachment 3. | |
411 downloader()->RespondToDownload( | |
412 attachment_ids[3], AttachmentDownloader::DOWNLOAD_UNSPECIFIED_ERROR); | |
413 RunLoop(); | |
414 | |
415 // Ensure callback is called | |
416 EXPECT_FALSE(download_results().empty()); | |
417 // There should be only two attachments returned, 0 and 1. | |
418 EXPECT_EQ(2U, last_download_attachments().size()); | |
419 EXPECT_TRUE(last_download_attachments().find(attachment_ids[0]) != | |
420 last_download_attachments().end()); | |
421 EXPECT_TRUE(last_download_attachments().find(attachment_ids[1]) != | |
422 last_download_attachments().end()); | |
423 EXPECT_TRUE(last_download_attachments().find(attachment_ids[2]) == | |
424 last_download_attachments().end()); | |
425 EXPECT_TRUE(last_download_attachments().find(attachment_ids[3]) == | |
426 last_download_attachments().end()); | |
427 } | |
428 | |
429 TEST_F(AttachmentServiceImplTest, GetOrDownload_NoDownloader) { | |
430 // No downloader. | |
431 InitializeAttachmentService( | |
432 base::WrapUnique<MockAttachmentUploader>(new MockAttachmentUploader()), | |
433 base::WrapUnique<MockAttachmentDownloader>(NULL), this); | |
434 | |
435 AttachmentIdList attachment_ids; | |
436 attachment_ids.push_back(AttachmentId::Create(0, 0)); | |
437 attachment_service()->GetOrDownloadAttachments(attachment_ids, | |
438 download_callback()); | |
439 RunLoop(); | |
440 EXPECT_FALSE(store()->read_ids.empty()); | |
441 | |
442 AttachmentIdSet local_attachments; | |
443 store()->RespondToRead(local_attachments); | |
444 RunLoop(); | |
445 ASSERT_EQ(1U, download_results().size()); | |
446 EXPECT_EQ(AttachmentService::GET_UNSPECIFIED_ERROR, download_results()[0]); | |
447 EXPECT_TRUE(last_download_attachments().empty()); | |
448 } | |
449 | |
450 TEST_F(AttachmentServiceImplTest, UploadAttachments_Success) { | |
451 AttachmentIdList attachment_ids; | |
452 const unsigned num_attachments = 3; | |
453 for (unsigned i = 0; i < num_attachments; ++i) { | |
454 attachment_ids.push_back(AttachmentId::Create(0, 0)); | |
455 } | |
456 attachment_service()->UploadAttachments(attachment_ids); | |
457 RunLoop(); | |
458 ASSERT_EQ(1U, store()->set_reference_ids.size()); | |
459 EXPECT_EQ(AttachmentStore::SYNC, store()->set_reference_ids[0].first); | |
460 for (unsigned i = 0; i < num_attachments; ++i) { | |
461 RunLoopAndFireTimer(); | |
462 // See that the service has issued a read for at least one of the | |
463 // attachments. | |
464 ASSERT_GE(store()->read_ids.size(), 1U); | |
465 store()->RespondToRead(AttachmentIdSetFromList(attachment_ids)); | |
466 RunLoop(); | |
467 ASSERT_GE(uploader()->upload_requests.size(), 1U); | |
468 uploader()->RespondToUpload(uploader()->upload_requests.begin()->first, | |
469 AttachmentUploader::UPLOAD_SUCCESS); | |
470 } | |
471 RunLoop(); | |
472 ASSERT_EQ(0U, store()->read_ids.size()); | |
473 ASSERT_EQ(0U, uploader()->upload_requests.size()); | |
474 | |
475 // See that all the attachments were uploaded. | |
476 ASSERT_EQ(attachment_ids.size(), on_attachment_uploaded_list().size()); | |
477 for (auto iter = attachment_ids.begin(); iter != attachment_ids.end(); | |
478 ++iter) { | |
479 EXPECT_THAT(on_attachment_uploaded_list(), testing::Contains(*iter)); | |
480 } | |
481 EXPECT_EQ(num_attachments, store()->drop_ids.size()); | |
482 } | |
483 | |
484 TEST_F(AttachmentServiceImplTest, UploadAttachments_Success_NoDelegate) { | |
485 InitializeAttachmentService(base::WrapUnique(new MockAttachmentUploader()), | |
486 base::WrapUnique(new MockAttachmentDownloader()), | |
487 NULL); // No delegate. | |
488 | |
489 AttachmentIdList attachment_ids; | |
490 attachment_ids.push_back(AttachmentId::Create(0, 0)); | |
491 attachment_service()->UploadAttachments(attachment_ids); | |
492 RunLoopAndFireTimer(); | |
493 ASSERT_EQ(1U, store()->read_ids.size()); | |
494 ASSERT_EQ(0U, uploader()->upload_requests.size()); | |
495 store()->RespondToRead(AttachmentIdSetFromList(attachment_ids)); | |
496 RunLoop(); | |
497 ASSERT_EQ(0U, store()->read_ids.size()); | |
498 ASSERT_EQ(1U, uploader()->upload_requests.size()); | |
499 uploader()->RespondToUpload(*attachment_ids.begin(), | |
500 AttachmentUploader::UPLOAD_SUCCESS); | |
501 RunLoop(); | |
502 ASSERT_TRUE(on_attachment_uploaded_list().empty()); | |
503 } | |
504 | |
505 TEST_F(AttachmentServiceImplTest, UploadAttachments_SomeMissingFromStore) { | |
506 AttachmentIdList attachment_ids; | |
507 attachment_ids.push_back(AttachmentId::Create(0, 0)); | |
508 attachment_ids.push_back(AttachmentId::Create(0, 0)); | |
509 attachment_service()->UploadAttachments(attachment_ids); | |
510 RunLoopAndFireTimer(); | |
511 ASSERT_GE(store()->read_ids.size(), 1U); | |
512 | |
513 ASSERT_EQ(0U, uploader()->upload_requests.size()); | |
514 store()->RespondToRead(AttachmentIdSetFromList(attachment_ids)); | |
515 RunLoop(); | |
516 ASSERT_EQ(1U, uploader()->upload_requests.size()); | |
517 | |
518 uploader()->RespondToUpload(uploader()->upload_requests.begin()->first, | |
519 AttachmentUploader::UPLOAD_SUCCESS); | |
520 RunLoopAndFireTimer(); | |
521 ASSERT_EQ(1U, on_attachment_uploaded_list().size()); | |
522 ASSERT_GE(store()->read_ids.size(), 1U); | |
523 // Not found! | |
524 store()->RespondToRead(AttachmentIdSet()); | |
525 RunLoop(); | |
526 // No upload requests since the read failed. | |
527 ASSERT_EQ(0U, uploader()->upload_requests.size()); | |
528 EXPECT_EQ(attachment_ids.size(), store()->drop_ids.size()); | |
529 } | |
530 | |
531 TEST_F(AttachmentServiceImplTest, UploadAttachments_AllMissingFromStore) { | |
532 AttachmentIdList attachment_ids; | |
533 const unsigned num_attachments = 2; | |
534 for (unsigned i = 0; i < num_attachments; ++i) { | |
535 attachment_ids.push_back(AttachmentId::Create(0, 0)); | |
536 } | |
537 attachment_service()->UploadAttachments(attachment_ids); | |
538 | |
539 for (unsigned i = 0; i < num_attachments; ++i) { | |
540 RunLoopAndFireTimer(); | |
541 ASSERT_GE(store()->read_ids.size(), 1U); | |
542 // None found! | |
543 store()->RespondToRead(AttachmentIdSet()); | |
544 } | |
545 RunLoop(); | |
546 | |
547 // Nothing uploaded. | |
548 EXPECT_EQ(0U, uploader()->upload_requests.size()); | |
549 // See that the delegate was never called. | |
550 ASSERT_EQ(0U, on_attachment_uploaded_list().size()); | |
551 EXPECT_EQ(num_attachments, store()->drop_ids.size()); | |
552 } | |
553 | |
554 TEST_F(AttachmentServiceImplTest, UploadAttachments_NoUploader) { | |
555 InitializeAttachmentService(base::WrapUnique<MockAttachmentUploader>(NULL), | |
556 base::WrapUnique(new MockAttachmentDownloader()), | |
557 this); | |
558 | |
559 AttachmentIdList attachment_ids; | |
560 attachment_ids.push_back(AttachmentId::Create(0, 0)); | |
561 attachment_service()->UploadAttachments(attachment_ids); | |
562 RunLoop(); | |
563 EXPECT_EQ(0U, store()->read_ids.size()); | |
564 ASSERT_EQ(0U, on_attachment_uploaded_list().size()); | |
565 EXPECT_EQ(0U, store()->drop_ids.size()); | |
566 } | |
567 | |
568 // Upload three attachments. For one of them, server responds with error. | |
569 TEST_F(AttachmentServiceImplTest, UploadAttachments_OneUploadFails) { | |
570 AttachmentIdList attachment_ids; | |
571 const unsigned num_attachments = 3; | |
572 for (unsigned i = 0; i < num_attachments; ++i) { | |
573 attachment_ids.push_back(AttachmentId::Create(0, 0)); | |
574 } | |
575 attachment_service()->UploadAttachments(attachment_ids); | |
576 | |
577 for (unsigned i = 0; i < 3; ++i) { | |
578 RunLoopAndFireTimer(); | |
579 ASSERT_GE(store()->read_ids.size(), 1U); | |
580 store()->RespondToRead(AttachmentIdSetFromList(attachment_ids)); | |
581 RunLoop(); | |
582 ASSERT_EQ(1U, uploader()->upload_requests.size()); | |
583 AttachmentUploader::UploadResult result = | |
584 AttachmentUploader::UPLOAD_SUCCESS; | |
585 // Fail the 2nd one. | |
586 if (i == 2U) { | |
587 result = AttachmentUploader::UPLOAD_UNSPECIFIED_ERROR; | |
588 } else { | |
589 result = AttachmentUploader::UPLOAD_SUCCESS; | |
590 } | |
591 uploader()->RespondToUpload(uploader()->upload_requests.begin()->first, | |
592 result); | |
593 RunLoop(); | |
594 } | |
595 ASSERT_EQ(2U, on_attachment_uploaded_list().size()); | |
596 EXPECT_EQ(num_attachments, store()->drop_ids.size()); | |
597 } | |
598 | |
599 // Attempt an upload, respond with transient error to trigger backoff, issue | |
600 // network disconnect/connect events and see that backoff is cleared. | |
601 TEST_F(AttachmentServiceImplTest, | |
602 UploadAttachments_ResetBackoffAfterNetworkChange) { | |
603 AttachmentIdList attachment_ids; | |
604 attachment_ids.push_back(AttachmentId::Create(0, 0)); | |
605 attachment_service()->UploadAttachments(attachment_ids); | |
606 | |
607 RunLoopAndFireTimer(); | |
608 ASSERT_EQ(1U, store()->read_ids.size()); | |
609 store()->RespondToRead(AttachmentIdSetFromList(attachment_ids)); | |
610 RunLoop(); | |
611 ASSERT_EQ(1U, uploader()->upload_requests.size()); | |
612 | |
613 uploader()->RespondToUpload(uploader()->upload_requests.begin()->first, | |
614 AttachmentUploader::UPLOAD_TRANSIENT_ERROR); | |
615 RunLoop(); | |
616 | |
617 // See that we are in backoff. | |
618 ASSERT_TRUE(mock_timer()->IsRunning()); | |
619 ASSERT_GT(mock_timer()->GetCurrentDelay(), base::TimeDelta()); | |
620 | |
621 // Issue a network disconnect event. | |
622 network_change_notifier()->NotifyObserversOfNetworkChangeForTests( | |
623 net::NetworkChangeNotifier::CONNECTION_NONE); | |
624 RunLoop(); | |
625 | |
626 // Still in backoff. | |
627 ASSERT_TRUE(mock_timer()->IsRunning()); | |
628 ASSERT_GT(mock_timer()->GetCurrentDelay(), base::TimeDelta()); | |
629 | |
630 // Issue a network connect event. | |
631 net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( | |
632 net::NetworkChangeNotifier::CONNECTION_WIFI); | |
633 RunLoop(); | |
634 | |
635 // No longer in backoff. | |
636 ASSERT_TRUE(mock_timer()->IsRunning()); | |
637 ASSERT_EQ(base::TimeDelta(), mock_timer()->GetCurrentDelay()); | |
638 } | |
639 | |
640 } // namespace syncer | |
OLD | NEW |