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