[SyncFS] Build indexes from FileTracker entries on disk.
[chromium-blink-merge.git] / sync / internal_api / attachments / attachment_downloader_impl_unittest.cc
blob6330833bcf237f28f9ebd238442e4660a74131ac
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/api/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);
102 virtual ~TokenServiceProvider();
104 // OAuth2TokenService::TokenServiceProvider implementation.
105 virtual scoped_refptr<base::SingleThreadTaskRunner>
106 GetTokenServiceTaskRunner() OVERRIDE;
107 virtual OAuth2TokenService* GetTokenService() OVERRIDE;
109 private:
110 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
111 OAuth2TokenService* token_service_;
114 TokenServiceProvider::TokenServiceProvider(OAuth2TokenService* token_service)
115 : task_runner_(base::ThreadTaskRunnerHandle::Get()),
116 token_service_(token_service) {
117 DCHECK(token_service_);
120 TokenServiceProvider::~TokenServiceProvider() {
123 scoped_refptr<base::SingleThreadTaskRunner>
124 TokenServiceProvider::GetTokenServiceTaskRunner() {
125 return task_runner_;
128 OAuth2TokenService* TokenServiceProvider::GetTokenService() {
129 DCHECK(task_runner_->BelongsToCurrentThread());
130 return token_service_;
133 } // namespace
135 class AttachmentDownloaderImplTest : public testing::Test {
136 protected:
137 typedef std::map<AttachmentId, AttachmentDownloader::DownloadResult>
138 ResultsMap;
140 AttachmentDownloaderImplTest() : num_completed_downloads_(0) {}
142 virtual void SetUp() OVERRIDE;
143 virtual void TearDown() OVERRIDE;
145 AttachmentDownloader* downloader() { return attachment_downloader_.get(); }
147 MockOAuth2TokenService* token_service() { return token_service_.get(); }
149 int num_completed_downloads() { return num_completed_downloads_; }
151 AttachmentDownloader::DownloadCallback download_callback(
152 const AttachmentId& id) {
153 return base::Bind(&AttachmentDownloaderImplTest::DownloadDone,
154 base::Unretained(this),
155 id);
158 void CompleteDownload(int response_code);
160 void DownloadDone(const AttachmentId& attachment_id,
161 const AttachmentDownloader::DownloadResult& result,
162 scoped_ptr<Attachment> attachment);
164 void VerifyDownloadResult(const AttachmentId& attachment_id,
165 const AttachmentDownloader::DownloadResult& result);
167 void RunMessageLoop();
169 private:
170 base::MessageLoopForIO message_loop_;
171 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
172 net::TestURLFetcherFactory url_fetcher_factory_;
173 scoped_ptr<MockOAuth2TokenService> token_service_;
174 scoped_ptr<AttachmentDownloader> attachment_downloader_;
175 ResultsMap download_results_;
176 int num_completed_downloads_;
179 void AttachmentDownloaderImplTest::SetUp() {
180 url_request_context_getter_ =
181 new net::TestURLRequestContextGetter(message_loop_.message_loop_proxy());
182 url_fetcher_factory_.set_remove_fetcher_on_delete(true);
183 token_service_.reset(new MockOAuth2TokenService());
184 token_service_->AddAccount(kAccountId);
185 scoped_ptr<OAuth2TokenServiceRequest::TokenServiceProvider>
186 token_service_provider(new TokenServiceProvider(token_service_.get()));
188 OAuth2TokenService::ScopeSet scopes;
189 scopes.insert(GaiaConstants::kChromeSyncOAuth2Scope);
190 attachment_downloader_ =
191 AttachmentDownloader::Create(GURL(kAttachmentServerUrl),
192 url_request_context_getter_,
193 kAccountId,
194 scopes,
195 token_service_provider.Pass());
198 void AttachmentDownloaderImplTest::TearDown() {
199 RunMessageLoop();
202 void AttachmentDownloaderImplTest::CompleteDownload(int response_code) {
203 // TestURLFetcherFactory remembers last active URLFetcher.
204 net::TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0);
205 // There should be outstanding url fetch request.
206 EXPECT_TRUE(fetcher != NULL);
207 fetcher->set_status(net::URLRequestStatus());
208 fetcher->set_response_code(response_code);
209 if (response_code == net::HTTP_OK) {
210 fetcher->SetResponseString(kAttachmentContent);
212 // Call URLFetcherDelegate.
213 net::URLFetcherDelegate* delegate = fetcher->delegate();
214 delegate->OnURLFetchComplete(fetcher);
215 RunMessageLoop();
216 // Once result is processed URLFetcher should be deleted.
217 fetcher = url_fetcher_factory_.GetFetcherByID(0);
218 EXPECT_TRUE(fetcher == NULL);
221 void AttachmentDownloaderImplTest::DownloadDone(
222 const AttachmentId& attachment_id,
223 const AttachmentDownloader::DownloadResult& result,
224 scoped_ptr<Attachment> attachment) {
225 download_results_.insert(std::make_pair(attachment_id, result));
226 if (result == AttachmentDownloader::DOWNLOAD_SUCCESS) {
227 // Successful download should be accompanied by valid attachment with
228 // matching id and valid data.
229 EXPECT_TRUE(attachment != NULL);
230 EXPECT_EQ(attachment_id, attachment->GetId());
232 scoped_refptr<base::RefCountedMemory> data = attachment->GetData();
233 std::string data_as_string(data->front_as<char>(), data->size());
234 EXPECT_EQ(data_as_string, kAttachmentContent);
235 } else {
236 EXPECT_TRUE(attachment == NULL);
238 ++num_completed_downloads_;
241 void AttachmentDownloaderImplTest::VerifyDownloadResult(
242 const AttachmentId& attachment_id,
243 const AttachmentDownloader::DownloadResult& result) {
244 ResultsMap::const_iterator iter = download_results_.find(attachment_id);
245 EXPECT_TRUE(iter != download_results_.end());
246 EXPECT_EQ(iter->second, result);
249 void AttachmentDownloaderImplTest::RunMessageLoop() {
250 base::RunLoop run_loop;
251 run_loop.RunUntilIdle();
254 TEST_F(AttachmentDownloaderImplTest, HappyCase) {
255 AttachmentId id1 = AttachmentId::Create();
256 // DownloadAttachment should trigger RequestAccessToken.
257 downloader()->DownloadAttachment(id1, download_callback(id1));
258 RunMessageLoop();
259 // Return valid access token.
260 token_service()->RespondToAccessTokenRequest(
261 GoogleServiceAuthError::AuthErrorNone());
262 RunMessageLoop();
263 // Check that there is outstanding URLFetcher request and complete it.
264 CompleteDownload(net::HTTP_OK);
265 // Verify that callback was called for the right id with the right result.
266 VerifyDownloadResult(id1, AttachmentDownloader::DOWNLOAD_SUCCESS);
269 TEST_F(AttachmentDownloaderImplTest, SameIdMultipleDownloads) {
270 AttachmentId id1 = AttachmentId::Create();
271 // Call DownloadAttachment two times for the same id.
272 downloader()->DownloadAttachment(id1, download_callback(id1));
273 downloader()->DownloadAttachment(id1, download_callback(id1));
274 RunMessageLoop();
275 // Return valid access token.
276 token_service()->RespondToAccessTokenRequest(
277 GoogleServiceAuthError::AuthErrorNone());
278 RunMessageLoop();
279 // Start one more download after access token is received.
280 downloader()->DownloadAttachment(id1, download_callback(id1));
281 // Complete URLFetcher request.
282 CompleteDownload(net::HTTP_OK);
283 // Verify that all download requests completed.
284 VerifyDownloadResult(id1, AttachmentDownloader::DOWNLOAD_SUCCESS);
285 EXPECT_EQ(3, num_completed_downloads());
287 // Let's download the same attachment again.
288 downloader()->DownloadAttachment(id1, download_callback(id1));
289 RunMessageLoop();
290 // Verify that it didn't finish prematurely.
291 EXPECT_EQ(3, num_completed_downloads());
292 // Return valid access token.
293 token_service()->RespondToAccessTokenRequest(
294 GoogleServiceAuthError::AuthErrorNone());
295 RunMessageLoop();
296 // Complete URLFetcher request.
297 CompleteDownload(net::HTTP_OK);
298 // Verify that all download requests completed.
299 VerifyDownloadResult(id1, AttachmentDownloader::DOWNLOAD_SUCCESS);
300 EXPECT_EQ(4, num_completed_downloads());
303 TEST_F(AttachmentDownloaderImplTest, RequestAccessTokenFails) {
304 AttachmentId id1 = AttachmentId::Create();
305 AttachmentId id2 = AttachmentId::Create();
306 // Trigger first RequestAccessToken.
307 downloader()->DownloadAttachment(id1, download_callback(id1));
308 RunMessageLoop();
309 // Return valid access token.
310 token_service()->RespondToAccessTokenRequest(
311 GoogleServiceAuthError::AuthErrorNone());
312 RunMessageLoop();
313 // Trigger second RequestAccessToken.
314 downloader()->DownloadAttachment(id2, download_callback(id2));
315 RunMessageLoop();
316 // Fail RequestAccessToken.
317 token_service()->RespondToAccessTokenRequest(
318 GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
319 RunMessageLoop();
320 // Only id2 should fail.
321 VerifyDownloadResult(id2, AttachmentDownloader::DOWNLOAD_UNSPECIFIED_ERROR);
322 // Complete request for id1.
323 CompleteDownload(net::HTTP_OK);
324 VerifyDownloadResult(id1, AttachmentDownloader::DOWNLOAD_SUCCESS);
327 TEST_F(AttachmentDownloaderImplTest, URLFetcher_BadToken) {
328 AttachmentId id1 = AttachmentId::Create();
329 downloader()->DownloadAttachment(id1, download_callback(id1));
330 RunMessageLoop();
331 // Return valid access token.
332 token_service()->RespondToAccessTokenRequest(
333 GoogleServiceAuthError::AuthErrorNone());
334 RunMessageLoop();
335 // Fail URLFetcher. This should trigger download failure and access token
336 // invalidation.
337 CompleteDownload(net::HTTP_UNAUTHORIZED);
338 EXPECT_EQ(1, token_service()->num_invalidate_token());
339 VerifyDownloadResult(id1, AttachmentDownloader::DOWNLOAD_UNSPECIFIED_ERROR);
342 TEST_F(AttachmentDownloaderImplTest, URLFetcher_ServiceUnavailable) {
343 AttachmentId id1 = AttachmentId::Create();
344 downloader()->DownloadAttachment(id1, download_callback(id1));
345 RunMessageLoop();
346 // Return valid access token.
347 token_service()->RespondToAccessTokenRequest(
348 GoogleServiceAuthError::AuthErrorNone());
349 RunMessageLoop();
350 // Fail URLFetcher. This should trigger download failure. Access token
351 // shouldn't be invalidated.
352 CompleteDownload(net::HTTP_SERVICE_UNAVAILABLE);
353 EXPECT_EQ(0, token_service()->num_invalidate_token());
354 VerifyDownloadResult(id1, AttachmentDownloader::DOWNLOAD_UNSPECIFIED_ERROR);
357 } // namespace syncer