Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / sync / internal_api / attachments / attachment_downloader_impl_unittest.cc
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_downloader.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 "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"
18
19 namespace syncer {
20
21 namespace {
22
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";
27
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) {}
34
35   virtual ~MockOAuth2TokenService() {}
36
37   void RespondToAccessTokenRequest(GoogleServiceAuthError error);
38
39   int num_invalidate_token() const { return num_invalidate_token_; }
40
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;
48
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;
53
54  private:
55   base::WeakPtr<RequestImpl> last_request_;
56   int num_invalidate_token_;
57 };
58
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();
67   }
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));
75 }
76
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();
87 }
88
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_;
95 }
96
97 class TokenServiceProvider
98     : public OAuth2TokenServiceRequest::TokenServiceProvider,
99       base::NonThreadSafe {
100  public:
101   TokenServiceProvider(OAuth2TokenService* token_service);
102
103   // OAuth2TokenService::TokenServiceProvider implementation.
104   virtual scoped_refptr<base::SingleThreadTaskRunner>
105       GetTokenServiceTaskRunner() OVERRIDE;
106   virtual OAuth2TokenService* GetTokenService() OVERRIDE;
107
108  private:
109   virtual ~TokenServiceProvider();
110
111   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
112   OAuth2TokenService* token_service_;
113 };
114
115 TokenServiceProvider::TokenServiceProvider(OAuth2TokenService* token_service)
116     : task_runner_(base::ThreadTaskRunnerHandle::Get()),
117       token_service_(token_service) {
118   DCHECK(token_service_);
119 }
120
121 TokenServiceProvider::~TokenServiceProvider() {
122 }
123
124 scoped_refptr<base::SingleThreadTaskRunner>
125 TokenServiceProvider::GetTokenServiceTaskRunner() {
126   return task_runner_;
127 }
128
129 OAuth2TokenService* TokenServiceProvider::GetTokenService() {
130   DCHECK(task_runner_->BelongsToCurrentThread());
131   return token_service_;
132 }
133
134 }  // namespace
135
136 class AttachmentDownloaderImplTest : public testing::Test {
137  protected:
138   typedef std::map<AttachmentId, AttachmentDownloader::DownloadResult>
139       ResultsMap;
140
141   AttachmentDownloaderImplTest() : num_completed_downloads_(0) {}
142
143   virtual void SetUp() OVERRIDE;
144   virtual void TearDown() OVERRIDE;
145
146   AttachmentDownloader* downloader() { return attachment_downloader_.get(); }
147
148   MockOAuth2TokenService* token_service() { return token_service_.get(); }
149
150   int num_completed_downloads() { return num_completed_downloads_; }
151
152   AttachmentDownloader::DownloadCallback download_callback(
153       const AttachmentId& id) {
154     return base::Bind(&AttachmentDownloaderImplTest::DownloadDone,
155                       base::Unretained(this),
156                       id);
157   }
158
159   void CompleteDownload(int response_code);
160
161   void DownloadDone(const AttachmentId& attachment_id,
162                     const AttachmentDownloader::DownloadResult& result,
163                     scoped_ptr<Attachment> attachment);
164
165   void VerifyDownloadResult(const AttachmentId& attachment_id,
166                             const AttachmentDownloader::DownloadResult& result);
167
168   void RunMessageLoop();
169
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_;
178 };
179
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()));
188
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);
197 }
198
199 void AttachmentDownloaderImplTest::TearDown() {
200   RunMessageLoop();
201 }
202
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);
212   }
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);
220 }
221
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());
232
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);
238   }
239   ++num_completed_downloads_;
240 }
241
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);
248 }
249
250 void AttachmentDownloaderImplTest::RunMessageLoop() {
251   base::RunLoop run_loop;
252   run_loop.RunUntilIdle();
253 }
254
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);
268 }
269
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());
287
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());
302 }
303
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_TRANSIENT_ERROR);
323   // Complete request for id1.
324   CompleteDownload(net::HTTP_OK);
325   VerifyDownloadResult(id1, AttachmentDownloader::DOWNLOAD_SUCCESS);
326 }
327
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_TRANSIENT_ERROR);
341 }
342
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_TRANSIENT_ERROR);
356 }
357
358 }  // namespace syncer