Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / sync / internal_api / attachments / attachment_downloader_impl_unittest.cc
blob01b12c17c974040dedd0df5a073d18f0a802a44f
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_downloader.h"
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 "base/thread_task_runner_handle.h"
12 #include "google_apis/gaia/fake_oauth2_token_service.h"
13 #include "google_apis/gaia/gaia_constants.h"
14 #include "net/url_request/test_url_fetcher_factory.h"
15 #include "net/url_request/url_request_test_util.h"
16 #include "sync/api/attachments/attachment.h"
17 #include "testing/gtest/include/gtest/gtest.h"
19 namespace syncer {
21 namespace {
23 const char kAccountId[] = "attachments@gmail.com";
24 const char kAccessToken[] = "access.token";
25 const char kAttachmentServerUrl[] = "http://attachments.com/";
26 const char kAttachmentContent[] = "attachment.content";
28 // MockOAuth2TokenService remembers last request for access token and verifies
29 // that only one request is active at a time.
30 // Call RespondToAccessTokenRequest to respond to it.
31 class MockOAuth2TokenService : public FakeOAuth2TokenService {
32 public:
33 MockOAuth2TokenService() : num_invalidate_token_(0) {}
35 virtual ~MockOAuth2TokenService() {}
37 void RespondToAccessTokenRequest(GoogleServiceAuthError error);
39 int num_invalidate_token() const { return num_invalidate_token_; }
41 protected:
42 virtual void FetchOAuth2Token(RequestImpl* request,
43 const std::string& account_id,
44 net::URLRequestContextGetter* getter,
45 const std::string& client_id,
46 const std::string& client_secret,
47 const ScopeSet& scopes) OVERRIDE;
49 virtual void InvalidateOAuth2Token(const std::string& account_id,
50 const std::string& client_id,
51 const ScopeSet& scopes,
52 const std::string& access_token) OVERRIDE;
54 private:
55 base::WeakPtr<RequestImpl> last_request_;
56 int num_invalidate_token_;
59 void MockOAuth2TokenService::RespondToAccessTokenRequest(
60 GoogleServiceAuthError error) {
61 EXPECT_TRUE(last_request_ != NULL);
62 std::string access_token;
63 base::Time expiration_time;
64 if (error == GoogleServiceAuthError::AuthErrorNone()) {
65 access_token = kAccessToken;
66 expiration_time = base::Time::Max();
68 base::MessageLoop::current()->PostTask(
69 FROM_HERE,
70 base::Bind(&OAuth2TokenService::RequestImpl::InformConsumer,
71 last_request_,
72 error,
73 access_token,
74 expiration_time));
77 void MockOAuth2TokenService::FetchOAuth2Token(
78 RequestImpl* request,
79 const std::string& account_id,
80 net::URLRequestContextGetter* getter,
81 const std::string& client_id,
82 const std::string& client_secret,
83 const ScopeSet& scopes) {
84 // Only one request at a time is allowed.
85 EXPECT_TRUE(last_request_ == NULL);
86 last_request_ = request->AsWeakPtr();
89 void MockOAuth2TokenService::InvalidateOAuth2Token(
90 const std::string& account_id,
91 const std::string& client_id,
92 const ScopeSet& scopes,
93 const std::string& access_token) {
94 ++num_invalidate_token_;
97 class TokenServiceProvider
98 : public OAuth2TokenServiceRequest::TokenServiceProvider,
99 base::NonThreadSafe {
100 public:
101 TokenServiceProvider(OAuth2TokenService* token_service);
103 // OAuth2TokenService::TokenServiceProvider implementation.
104 virtual scoped_refptr<base::SingleThreadTaskRunner>
105 GetTokenServiceTaskRunner() OVERRIDE;
106 virtual OAuth2TokenService* GetTokenService() OVERRIDE;
108 private:
109 virtual ~TokenServiceProvider();
111 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
112 OAuth2TokenService* token_service_;
115 TokenServiceProvider::TokenServiceProvider(OAuth2TokenService* token_service)
116 : task_runner_(base::ThreadTaskRunnerHandle::Get()),
117 token_service_(token_service) {
118 DCHECK(token_service_);
121 TokenServiceProvider::~TokenServiceProvider() {
124 scoped_refptr<base::SingleThreadTaskRunner>
125 TokenServiceProvider::GetTokenServiceTaskRunner() {
126 return task_runner_;
129 OAuth2TokenService* TokenServiceProvider::GetTokenService() {
130 DCHECK(task_runner_->BelongsToCurrentThread());
131 return token_service_;
134 } // namespace
136 class AttachmentDownloaderImplTest : public testing::Test {
137 protected:
138 typedef std::map<AttachmentId, AttachmentDownloader::DownloadResult>
139 ResultsMap;
141 AttachmentDownloaderImplTest() : num_completed_downloads_(0) {}
143 virtual void SetUp() OVERRIDE;
144 virtual void TearDown() OVERRIDE;
146 AttachmentDownloader* downloader() { return attachment_downloader_.get(); }
148 MockOAuth2TokenService* token_service() { return token_service_.get(); }
150 int num_completed_downloads() { return num_completed_downloads_; }
152 AttachmentDownloader::DownloadCallback download_callback(
153 const AttachmentId& id) {
154 return base::Bind(&AttachmentDownloaderImplTest::DownloadDone,
155 base::Unretained(this),
156 id);
159 void CompleteDownload(int response_code);
161 void DownloadDone(const AttachmentId& attachment_id,
162 const AttachmentDownloader::DownloadResult& result,
163 scoped_ptr<Attachment> attachment);
165 void VerifyDownloadResult(const AttachmentId& attachment_id,
166 const AttachmentDownloader::DownloadResult& result);
168 void RunMessageLoop();
170 private:
171 base::MessageLoopForIO message_loop_;
172 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
173 net::TestURLFetcherFactory url_fetcher_factory_;
174 scoped_ptr<MockOAuth2TokenService> token_service_;
175 scoped_ptr<AttachmentDownloader> attachment_downloader_;
176 ResultsMap download_results_;
177 int num_completed_downloads_;
180 void AttachmentDownloaderImplTest::SetUp() {
181 url_request_context_getter_ =
182 new net::TestURLRequestContextGetter(message_loop_.message_loop_proxy());
183 url_fetcher_factory_.set_remove_fetcher_on_delete(true);
184 token_service_.reset(new MockOAuth2TokenService());
185 token_service_->AddAccount(kAccountId);
186 scoped_refptr<OAuth2TokenServiceRequest::TokenServiceProvider>
187 token_service_provider(new TokenServiceProvider(token_service_.get()));
189 OAuth2TokenService::ScopeSet scopes;
190 scopes.insert(GaiaConstants::kChromeSyncOAuth2Scope);
191 attachment_downloader_ =
192 AttachmentDownloader::Create(GURL(kAttachmentServerUrl),
193 url_request_context_getter_,
194 kAccountId,
195 scopes,
196 token_service_provider);
199 void AttachmentDownloaderImplTest::TearDown() {
200 RunMessageLoop();
203 void AttachmentDownloaderImplTest::CompleteDownload(int response_code) {
204 // TestURLFetcherFactory remembers last active URLFetcher.
205 net::TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0);
206 // There should be outstanding url fetch request.
207 EXPECT_TRUE(fetcher != NULL);
208 fetcher->set_status(net::URLRequestStatus());
209 fetcher->set_response_code(response_code);
210 if (response_code == net::HTTP_OK) {
211 fetcher->SetResponseString(kAttachmentContent);
213 // Call URLFetcherDelegate.
214 net::URLFetcherDelegate* delegate = fetcher->delegate();
215 delegate->OnURLFetchComplete(fetcher);
216 RunMessageLoop();
217 // Once result is processed URLFetcher should be deleted.
218 fetcher = url_fetcher_factory_.GetFetcherByID(0);
219 EXPECT_TRUE(fetcher == NULL);
222 void AttachmentDownloaderImplTest::DownloadDone(
223 const AttachmentId& attachment_id,
224 const AttachmentDownloader::DownloadResult& result,
225 scoped_ptr<Attachment> attachment) {
226 download_results_.insert(std::make_pair(attachment_id, result));
227 if (result == AttachmentDownloader::DOWNLOAD_SUCCESS) {
228 // Successful download should be accompanied by valid attachment with
229 // matching id and valid data.
230 EXPECT_TRUE(attachment != NULL);
231 EXPECT_EQ(attachment_id, attachment->GetId());
233 scoped_refptr<base::RefCountedMemory> data = attachment->GetData();
234 std::string data_as_string(data->front_as<char>(), data->size());
235 EXPECT_EQ(data_as_string, kAttachmentContent);
236 } else {
237 EXPECT_TRUE(attachment == NULL);
239 ++num_completed_downloads_;
242 void AttachmentDownloaderImplTest::VerifyDownloadResult(
243 const AttachmentId& attachment_id,
244 const AttachmentDownloader::DownloadResult& result) {
245 ResultsMap::const_iterator iter = download_results_.find(attachment_id);
246 EXPECT_TRUE(iter != download_results_.end());
247 EXPECT_EQ(iter->second, result);
250 void AttachmentDownloaderImplTest::RunMessageLoop() {
251 base::RunLoop run_loop;
252 run_loop.RunUntilIdle();
255 TEST_F(AttachmentDownloaderImplTest, HappyCase) {
256 AttachmentId id1 = AttachmentId::Create();
257 // DownloadAttachment should trigger RequestAccessToken.
258 downloader()->DownloadAttachment(id1, download_callback(id1));
259 RunMessageLoop();
260 // Return valid access token.
261 token_service()->RespondToAccessTokenRequest(
262 GoogleServiceAuthError::AuthErrorNone());
263 RunMessageLoop();
264 // Check that there is outstanding URLFetcher request and complete it.
265 CompleteDownload(net::HTTP_OK);
266 // Verify that callback was called for the right id with the right result.
267 VerifyDownloadResult(id1, AttachmentDownloader::DOWNLOAD_SUCCESS);
270 TEST_F(AttachmentDownloaderImplTest, SameIdMultipleDownloads) {
271 AttachmentId id1 = AttachmentId::Create();
272 // Call DownloadAttachment two times for the same id.
273 downloader()->DownloadAttachment(id1, download_callback(id1));
274 downloader()->DownloadAttachment(id1, download_callback(id1));
275 RunMessageLoop();
276 // Return valid access token.
277 token_service()->RespondToAccessTokenRequest(
278 GoogleServiceAuthError::AuthErrorNone());
279 RunMessageLoop();
280 // Start one more download after access token is received.
281 downloader()->DownloadAttachment(id1, download_callback(id1));
282 // Complete URLFetcher request.
283 CompleteDownload(net::HTTP_OK);
284 // Verify that all download requests completed.
285 VerifyDownloadResult(id1, AttachmentDownloader::DOWNLOAD_SUCCESS);
286 EXPECT_EQ(3, num_completed_downloads());
288 // Let's download the same attachment again.
289 downloader()->DownloadAttachment(id1, download_callback(id1));
290 RunMessageLoop();
291 // Verify that it didn't finish prematurely.
292 EXPECT_EQ(3, num_completed_downloads());
293 // Return valid access token.
294 token_service()->RespondToAccessTokenRequest(
295 GoogleServiceAuthError::AuthErrorNone());
296 RunMessageLoop();
297 // Complete URLFetcher request.
298 CompleteDownload(net::HTTP_OK);
299 // Verify that all download requests completed.
300 VerifyDownloadResult(id1, AttachmentDownloader::DOWNLOAD_SUCCESS);
301 EXPECT_EQ(4, num_completed_downloads());
304 TEST_F(AttachmentDownloaderImplTest, RequestAccessTokenFails) {
305 AttachmentId id1 = AttachmentId::Create();
306 AttachmentId id2 = AttachmentId::Create();
307 // Trigger first RequestAccessToken.
308 downloader()->DownloadAttachment(id1, download_callback(id1));
309 RunMessageLoop();
310 // Return valid access token.
311 token_service()->RespondToAccessTokenRequest(
312 GoogleServiceAuthError::AuthErrorNone());
313 RunMessageLoop();
314 // Trigger second RequestAccessToken.
315 downloader()->DownloadAttachment(id2, download_callback(id2));
316 RunMessageLoop();
317 // Fail RequestAccessToken.
318 token_service()->RespondToAccessTokenRequest(
319 GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
320 RunMessageLoop();
321 // Only id2 should fail.
322 VerifyDownloadResult(id2, AttachmentDownloader::DOWNLOAD_UNSPECIFIED_ERROR);
323 // Complete request for id1.
324 CompleteDownload(net::HTTP_OK);
325 VerifyDownloadResult(id1, AttachmentDownloader::DOWNLOAD_SUCCESS);
328 TEST_F(AttachmentDownloaderImplTest, URLFetcher_BadToken) {
329 AttachmentId id1 = AttachmentId::Create();
330 downloader()->DownloadAttachment(id1, download_callback(id1));
331 RunMessageLoop();
332 // Return valid access token.
333 token_service()->RespondToAccessTokenRequest(
334 GoogleServiceAuthError::AuthErrorNone());
335 RunMessageLoop();
336 // Fail URLFetcher. This should trigger download failure and access token
337 // invalidation.
338 CompleteDownload(net::HTTP_UNAUTHORIZED);
339 EXPECT_EQ(1, token_service()->num_invalidate_token());
340 VerifyDownloadResult(id1, AttachmentDownloader::DOWNLOAD_UNSPECIFIED_ERROR);
343 TEST_F(AttachmentDownloaderImplTest, URLFetcher_ServiceUnavailable) {
344 AttachmentId id1 = AttachmentId::Create();
345 downloader()->DownloadAttachment(id1, download_callback(id1));
346 RunMessageLoop();
347 // Return valid access token.
348 token_service()->RespondToAccessTokenRequest(
349 GoogleServiceAuthError::AuthErrorNone());
350 RunMessageLoop();
351 // Fail URLFetcher. This should trigger download failure. Access token
352 // shouldn't be invalidated.
353 CompleteDownload(net::HTTP_SERVICE_UNAVAILABLE);
354 EXPECT_EQ(0, token_service()->num_invalidate_token());
355 VerifyDownloadResult(id1, AttachmentDownloader::DOWNLOAD_UNSPECIFIED_ERROR);
358 } // namespace syncer