• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
MockAttachmentStore()20   MockAttachmentStore() {}
21 
Read(const AttachmentIdList & ids,const ReadCallback & callback)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 
Write(const AttachmentList & attachments,const WriteCallback & callback)28   virtual void Write(const AttachmentList& attachments,
29                      const WriteCallback& callback) OVERRIDE {
30     NOTREACHED();
31   }
32 
Drop(const AttachmentIdList & ids,const DropCallback & callback)33   virtual void Drop(const AttachmentIdList& ids,
34                     const DropCallback& callback) OVERRIDE {
35     NOTREACHED();
36   }
37 
38   // Respond to Read request. Attachments found in local_attachments should be
39   // returned, everything else should be reported unavailable.
RespondToRead(const AttachmentIdSet & local_attachments)40   void RespondToRead(const AttachmentIdSet& local_attachments) {
41     scoped_refptr<base::RefCountedString> data = new base::RefCountedString();
42     ReadCallback callback = read_callbacks.back();
43     AttachmentIdList ids = read_ids.back();
44     read_callbacks.pop_back();
45     read_ids.pop_back();
46 
47     scoped_ptr<AttachmentMap> attachments(new AttachmentMap());
48     scoped_ptr<AttachmentIdList> unavailable_attachments(
49         new AttachmentIdList());
50     for (AttachmentIdList::const_iterator iter = ids.begin(); iter != ids.end();
51          ++iter) {
52       if (local_attachments.find(*iter) != local_attachments.end()) {
53         Attachment attachment = Attachment::CreateWithId(*iter, data);
54         attachments->insert(std::make_pair(*iter, attachment));
55       } else {
56         unavailable_attachments->push_back(*iter);
57       }
58     }
59     Result result =
60         unavailable_attachments->empty() ? SUCCESS : UNSPECIFIED_ERROR;
61 
62     base::MessageLoop::current()->PostTask(
63         FROM_HERE,
64         base::Bind(callback,
65                    result,
66                    base::Passed(&attachments),
67                    base::Passed(&unavailable_attachments)));
68   }
69 
70   std::vector<AttachmentIdList> read_ids;
71   std::vector<ReadCallback> read_callbacks;
72 
73   DISALLOW_COPY_AND_ASSIGN(MockAttachmentStore);
74 };
75 
76 class MockAttachmentDownloader
77     : public AttachmentDownloader,
78       public base::SupportsWeakPtr<MockAttachmentDownloader> {
79  public:
MockAttachmentDownloader()80   MockAttachmentDownloader() {}
81 
DownloadAttachment(const AttachmentId & id,const DownloadCallback & callback)82   virtual void DownloadAttachment(const AttachmentId& id,
83                                   const DownloadCallback& callback) OVERRIDE {
84     ASSERT_TRUE(download_requests.find(id) == download_requests.end());
85     download_requests.insert(std::make_pair(id, callback));
86   }
87 
88   // Multiple requests to download will be active at the same time.
89   // RespondToDownload should respond to only one of them.
RespondToDownload(const AttachmentId & id,const DownloadResult & result)90   void RespondToDownload(const AttachmentId& id, const DownloadResult& result) {
91     ASSERT_TRUE(download_requests.find(id) != download_requests.end());
92     scoped_ptr<Attachment> attachment;
93     if (result == DOWNLOAD_SUCCESS) {
94       scoped_refptr<base::RefCountedString> data = new base::RefCountedString();
95       attachment.reset(new Attachment(Attachment::CreateWithId(id, data)));
96     }
97     base::MessageLoop::current()->PostTask(
98         FROM_HERE,
99         base::Bind(download_requests[id], result, base::Passed(&attachment)));
100 
101     download_requests.erase(id);
102   }
103 
104   std::map<AttachmentId, DownloadCallback> download_requests;
105 
106   DISALLOW_COPY_AND_ASSIGN(MockAttachmentDownloader);
107 };
108 
109 class AttachmentServiceImplTest : public testing::Test {
110  protected:
AttachmentServiceImplTest()111   AttachmentServiceImplTest() {}
112 
SetUp()113   virtual void SetUp() OVERRIDE {
114     scoped_ptr<MockAttachmentStore> attachment_store(new MockAttachmentStore());
115     scoped_ptr<AttachmentUploader> attachment_uploader(
116         new FakeAttachmentUploader());
117     scoped_ptr<MockAttachmentDownloader> attachment_downloader(
118         new MockAttachmentDownloader());
119 
120     attachment_store_ = attachment_store->AsWeakPtr();
121     attachment_downloader_ = attachment_downloader->AsWeakPtr();
122 
123     attachment_service_.reset(new AttachmentServiceImpl(
124         attachment_store.PassAs<AttachmentStore>(),
125         attachment_uploader.Pass(),
126         attachment_downloader.PassAs<AttachmentDownloader>(),
127         NULL));
128   }
129 
TearDown()130   virtual void TearDown() OVERRIDE {
131     attachment_service_.reset();
132     ASSERT_FALSE(attachment_store_);
133     ASSERT_FALSE(attachment_downloader_);
134   }
135 
attachment_service()136   AttachmentService* attachment_service() { return attachment_service_.get(); }
137 
download_callback()138   AttachmentService::GetOrDownloadCallback download_callback() {
139     return base::Bind(&AttachmentServiceImplTest::DownloadDone,
140                       base::Unretained(this));
141   }
142 
DownloadDone(const AttachmentService::GetOrDownloadResult & result,scoped_ptr<AttachmentMap> attachments)143   void DownloadDone(const AttachmentService::GetOrDownloadResult& result,
144                     scoped_ptr<AttachmentMap> attachments) {
145     download_results_.push_back(result);
146     last_download_attachments_ = attachments.Pass();
147   }
148 
RunLoop()149   void RunLoop() {
150     base::RunLoop run_loop;
151     run_loop.RunUntilIdle();
152   }
153 
154   const std::vector<AttachmentService::GetOrDownloadResult>&
download_results()155   download_results() {
156     return download_results_;
157   }
158 
last_download_attachments()159   AttachmentMap* last_download_attachments() {
160     return last_download_attachments_.get();
161   }
162 
store()163   MockAttachmentStore* store() { return attachment_store_.get(); }
164 
downloader()165   MockAttachmentDownloader* downloader() {
166     return attachment_downloader_.get();
167   }
168 
169  private:
170   base::MessageLoop message_loop_;
171   base::WeakPtr<MockAttachmentStore> attachment_store_;
172   base::WeakPtr<MockAttachmentDownloader> attachment_downloader_;
173   scoped_ptr<AttachmentService> attachment_service_;
174 
175   std::vector<AttachmentService::GetOrDownloadResult> download_results_;
176   scoped_ptr<AttachmentMap> last_download_attachments_;
177 };
178 
TEST_F(AttachmentServiceImplTest,GetOrDownload_EmptyAttachmentList)179 TEST_F(AttachmentServiceImplTest, GetOrDownload_EmptyAttachmentList) {
180   AttachmentIdList attachment_ids;
181   attachment_service()->GetOrDownloadAttachments(attachment_ids,
182                                                  download_callback());
183   store()->RespondToRead(AttachmentIdSet());
184 
185   RunLoop();
186   EXPECT_EQ(1U, download_results().size());
187   EXPECT_EQ(0U, last_download_attachments()->size());
188 }
189 
TEST_F(AttachmentServiceImplTest,GetOrDownload_Local)190 TEST_F(AttachmentServiceImplTest, GetOrDownload_Local) {
191   AttachmentIdList attachment_ids;
192   attachment_ids.push_back(AttachmentId::Create());
193   attachment_service()->GetOrDownloadAttachments(attachment_ids,
194                                                  download_callback());
195   AttachmentIdSet local_attachments;
196   local_attachments.insert(attachment_ids[0]);
197   store()->RespondToRead(local_attachments);
198 
199   RunLoop();
200   EXPECT_EQ(1U, download_results().size());
201   EXPECT_EQ(1U, last_download_attachments()->size());
202   EXPECT_TRUE(last_download_attachments()->find(attachment_ids[0]) !=
203               last_download_attachments()->end());
204 }
205 
TEST_F(AttachmentServiceImplTest,GetOrDownload_LocalRemoteUnavailable)206 TEST_F(AttachmentServiceImplTest, GetOrDownload_LocalRemoteUnavailable) {
207   // Create attachment list with 3 ids.
208   AttachmentIdList attachment_ids;
209   attachment_ids.push_back(AttachmentId::Create());
210   attachment_ids.push_back(AttachmentId::Create());
211   attachment_ids.push_back(AttachmentId::Create());
212   // Call attachment service.
213   attachment_service()->GetOrDownloadAttachments(attachment_ids,
214                                                  download_callback());
215   // Ensure AttachmentStore is called.
216   EXPECT_FALSE(store()->read_ids.empty());
217 
218   // make AttachmentStore return only attachment 0.
219   AttachmentIdSet local_attachments;
220   local_attachments.insert(attachment_ids[0]);
221   store()->RespondToRead(local_attachments);
222   RunLoop();
223   // Ensure Downloader called with right attachment ids
224   EXPECT_EQ(2U, downloader()->download_requests.size());
225 
226   // Make downloader return attachment 1.
227   downloader()->RespondToDownload(attachment_ids[1],
228                                   AttachmentDownloader::DOWNLOAD_SUCCESS);
229   RunLoop();
230   // Ensure consumer callback is not called.
231   EXPECT_TRUE(download_results().empty());
232 
233   // Make downloader fail attachment 2.
234   downloader()->RespondToDownload(
235       attachment_ids[2], AttachmentDownloader::DOWNLOAD_UNSPECIFIED_ERROR);
236   RunLoop();
237   // Ensure callback is called
238   EXPECT_FALSE(download_results().empty());
239   // There should be only two attachments returned, 0 and 1.
240   EXPECT_EQ(2U, last_download_attachments()->size());
241   EXPECT_TRUE(last_download_attachments()->find(attachment_ids[0]) !=
242               last_download_attachments()->end());
243   EXPECT_TRUE(last_download_attachments()->find(attachment_ids[1]) !=
244               last_download_attachments()->end());
245   EXPECT_TRUE(last_download_attachments()->find(attachment_ids[2]) ==
246               last_download_attachments()->end());
247 }
248 
249 }  // namespace syncer
250