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 "google_apis/gaia/oauth2_token_service_request.h"
6
7#include <set>
8#include <string>
9#include <vector>
10#include "base/threading/thread.h"
11#include "google_apis/gaia/fake_oauth2_token_service.h"
12#include "google_apis/gaia/google_service_auth_error.h"
13#include "google_apis/gaia/oauth2_token_service.h"
14#include "testing/gtest/include/gtest/gtest.h"
15
16namespace {
17
18const char kAccessToken[] = "access_token";
19const char kAccountId[] = "test_user@gmail.com";
20const char kScope[] = "SCOPE";
21
22class TestingOAuth2TokenServiceConsumer : public OAuth2TokenService::Consumer {
23 public:
24  TestingOAuth2TokenServiceConsumer();
25  virtual ~TestingOAuth2TokenServiceConsumer();
26
27  virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
28                                 const std::string& access_token,
29                                 const base::Time& expiration_time) OVERRIDE;
30  virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
31                                 const GoogleServiceAuthError& error) OVERRIDE;
32
33  int num_get_token_success_;
34  int num_get_token_failure_;
35  std::string last_token_;
36  GoogleServiceAuthError last_error_;
37};
38
39TestingOAuth2TokenServiceConsumer::TestingOAuth2TokenServiceConsumer()
40    : OAuth2TokenService::Consumer("test"),
41      num_get_token_success_(0),
42      num_get_token_failure_(0),
43      last_error_(GoogleServiceAuthError::AuthErrorNone()) {
44}
45
46TestingOAuth2TokenServiceConsumer::~TestingOAuth2TokenServiceConsumer() {
47}
48
49void TestingOAuth2TokenServiceConsumer::OnGetTokenSuccess(
50    const OAuth2TokenService::Request* request,
51    const std::string& token,
52    const base::Time& expiration_date) {
53  last_token_ = token;
54  ++num_get_token_success_;
55}
56
57void TestingOAuth2TokenServiceConsumer::OnGetTokenFailure(
58    const OAuth2TokenService::Request* request,
59    const GoogleServiceAuthError& error) {
60  last_error_ = error;
61  ++num_get_token_failure_;
62}
63
64// A mock implementation of an OAuth2TokenService.
65//
66// Use SetResponse to vary the response to token requests.
67class MockOAuth2TokenService : public FakeOAuth2TokenService {
68 public:
69  MockOAuth2TokenService();
70  virtual ~MockOAuth2TokenService();
71
72  void SetResponse(const GoogleServiceAuthError& error,
73                   const std::string& access_token,
74                   const base::Time& expiration);
75
76  int num_invalidate_token() const { return num_invalidate_token_; }
77
78  const std::string& last_token_invalidated() const {
79    return last_token_invalidated_;
80  }
81
82 protected:
83  virtual void FetchOAuth2Token(RequestImpl* request,
84                                const std::string& account_id,
85                                net::URLRequestContextGetter* getter,
86                                const std::string& client_id,
87                                const std::string& client_secret,
88                                const ScopeSet& scopes) OVERRIDE;
89
90  virtual void InvalidateOAuth2Token(const std::string& account_id,
91                                     const std::string& client_id,
92                                     const ScopeSet& scopes,
93                                     const std::string& access_token) OVERRIDE;
94
95 private:
96  GoogleServiceAuthError response_error_;
97  std::string response_access_token_;
98  base::Time response_expiration_;
99  int num_invalidate_token_;
100  std::string last_token_invalidated_;
101};
102
103MockOAuth2TokenService::MockOAuth2TokenService()
104    : response_error_(GoogleServiceAuthError::AuthErrorNone()),
105      response_access_token_(kAccessToken),
106      response_expiration_(base::Time::Max()),
107      num_invalidate_token_(0) {
108}
109
110MockOAuth2TokenService::~MockOAuth2TokenService() {
111}
112
113void MockOAuth2TokenService::SetResponse(const GoogleServiceAuthError& error,
114                                         const std::string& access_token,
115                                         const base::Time& expiration) {
116  response_error_ = error;
117  response_access_token_ = access_token;
118  response_expiration_ = expiration;
119}
120
121void MockOAuth2TokenService::FetchOAuth2Token(
122    RequestImpl* request,
123    const std::string& account_id,
124    net::URLRequestContextGetter* getter,
125    const std::string& client_id,
126    const std::string& client_secret,
127    const ScopeSet& scopes) {
128  base::MessageLoop::current()->PostTask(
129      FROM_HERE,
130      base::Bind(&OAuth2TokenService::RequestImpl::InformConsumer,
131                 request->AsWeakPtr(),
132                 response_error_,
133                 response_access_token_,
134                 response_expiration_));
135}
136
137void MockOAuth2TokenService::InvalidateOAuth2Token(
138    const std::string& account_id,
139    const std::string& client_id,
140    const ScopeSet& scopes,
141    const std::string& access_token) {
142  ++num_invalidate_token_;
143  last_token_invalidated_ = access_token;
144}
145
146class OAuth2TokenServiceRequestTest : public testing::Test {
147 public:
148  virtual void SetUp() OVERRIDE;
149  virtual void TearDown() OVERRIDE;
150
151 protected:
152  class Provider : public OAuth2TokenServiceRequest::TokenServiceProvider {
153   public:
154    Provider(const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
155             OAuth2TokenService* token_service);
156
157    virtual scoped_refptr<base::SingleThreadTaskRunner>
158        GetTokenServiceTaskRunner() OVERRIDE;
159    virtual OAuth2TokenService* GetTokenService() OVERRIDE;
160
161   private:
162    virtual ~Provider();
163
164    scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
165    OAuth2TokenService* token_service_;
166  };
167
168  base::MessageLoop ui_loop_;
169  OAuth2TokenService::ScopeSet scopes_;
170  scoped_ptr<MockOAuth2TokenService> oauth2_service_;
171  scoped_refptr<OAuth2TokenServiceRequest::TokenServiceProvider> provider_;
172  TestingOAuth2TokenServiceConsumer consumer_;
173};
174
175void OAuth2TokenServiceRequestTest::SetUp() {
176  scopes_.insert(kScope);
177  oauth2_service_.reset(new MockOAuth2TokenService);
178  oauth2_service_->AddAccount(kAccountId);
179  provider_ =
180      new Provider(base::MessageLoopProxy::current(), oauth2_service_.get());
181}
182
183void OAuth2TokenServiceRequestTest::TearDown() {
184  // Run the loop to execute any pending tasks that may free resources.
185  ui_loop_.RunUntilIdle();
186}
187
188OAuth2TokenServiceRequestTest::Provider::Provider(
189    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
190    OAuth2TokenService* token_service)
191    : task_runner_(task_runner), token_service_(token_service) {
192}
193
194scoped_refptr<base::SingleThreadTaskRunner>
195OAuth2TokenServiceRequestTest::Provider::GetTokenServiceTaskRunner() {
196  return task_runner_;
197}
198
199OAuth2TokenService* OAuth2TokenServiceRequestTest::Provider::GetTokenService() {
200  return token_service_;
201}
202
203OAuth2TokenServiceRequestTest::Provider::~Provider() {
204}
205
206TEST_F(OAuth2TokenServiceRequestTest, CreateAndStart_Failure) {
207  oauth2_service_->SetResponse(
208      GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE),
209      std::string(),
210      base::Time());
211  scoped_ptr<OAuth2TokenServiceRequest> request(
212      OAuth2TokenServiceRequest::CreateAndStart(
213          provider_.get(), kAccountId, scopes_, &consumer_));
214  ui_loop_.RunUntilIdle();
215  EXPECT_EQ(0, consumer_.num_get_token_success_);
216  EXPECT_EQ(1, consumer_.num_get_token_failure_);
217  EXPECT_EQ(GoogleServiceAuthError::SERVICE_UNAVAILABLE,
218            consumer_.last_error_.state());
219  EXPECT_EQ(0, oauth2_service_->num_invalidate_token());
220}
221
222TEST_F(OAuth2TokenServiceRequestTest, CreateAndStart_Success) {
223  scoped_ptr<OAuth2TokenServiceRequest> request(
224      OAuth2TokenServiceRequest::CreateAndStart(
225          provider_.get(), kAccountId, scopes_, &consumer_));
226  ui_loop_.RunUntilIdle();
227  EXPECT_EQ(1, consumer_.num_get_token_success_);
228  EXPECT_EQ(0, consumer_.num_get_token_failure_);
229  EXPECT_EQ(kAccessToken, consumer_.last_token_);
230  EXPECT_EQ(0, oauth2_service_->num_invalidate_token());
231}
232
233TEST_F(OAuth2TokenServiceRequestTest,
234       CreateAndStart_DestroyRequestBeforeCompletes) {
235  scoped_ptr<OAuth2TokenServiceRequest> request(
236      OAuth2TokenServiceRequest::CreateAndStart(
237          provider_.get(), kAccountId, scopes_, &consumer_));
238  request.reset();
239  ui_loop_.RunUntilIdle();
240  EXPECT_EQ(0, consumer_.num_get_token_success_);
241  EXPECT_EQ(0, consumer_.num_get_token_failure_);
242  EXPECT_EQ(0, oauth2_service_->num_invalidate_token());
243}
244
245TEST_F(OAuth2TokenServiceRequestTest,
246       CreateAndStart_DestroyRequestAfterCompletes) {
247  scoped_ptr<OAuth2TokenServiceRequest> request(
248      OAuth2TokenServiceRequest::CreateAndStart(
249          provider_.get(), kAccountId, scopes_, &consumer_));
250  ui_loop_.RunUntilIdle();
251  request.reset();
252  EXPECT_EQ(1, consumer_.num_get_token_success_);
253  EXPECT_EQ(0, consumer_.num_get_token_failure_);
254  EXPECT_EQ(kAccessToken, consumer_.last_token_);
255  EXPECT_EQ(0, oauth2_service_->num_invalidate_token());
256}
257
258TEST_F(OAuth2TokenServiceRequestTest, InvalidateToken) {
259  OAuth2TokenServiceRequest::InvalidateToken(
260      provider_.get(), kAccountId, scopes_, kAccessToken);
261  ui_loop_.RunUntilIdle();
262  EXPECT_EQ(0, consumer_.num_get_token_success_);
263  EXPECT_EQ(0, consumer_.num_get_token_failure_);
264  EXPECT_EQ(kAccessToken, oauth2_service_->last_token_invalidated());
265  EXPECT_EQ(1, oauth2_service_->num_invalidate_token());
266}
267
268}  // namespace
269