1 // Copyright (c) 2012 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 // A complete set of unit tests for GaiaOAuthClient.
10 #include "base/strings/string_number_conversions.h"
11 #include "base/values.h"
12 #include "google_apis/gaia/gaia_oauth_client.h"
13 #include "net/base/net_errors.h"
14 #include "net/http/http_status_code.h"
15 #include "net/url_request/test_url_fetcher_factory.h"
16 #include "net/url_request/url_fetcher_delegate.h"
17 #include "net/url_request/url_request_status.h"
18 #include "net/url_request/url_request_test_util.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20 #include "testing/gtest/include/gtest/gtest.h"
25 using ::testing::HasSubstr
;
26 using ::testing::Pointee
;
27 using ::testing::SaveArg
;
31 // Responds as though OAuth returned from the server.
32 class MockOAuthFetcher
: public net::TestURLFetcher
{
34 MockOAuthFetcher(int response_code
,
35 int max_failure_count
,
36 bool complete_immediately
,
38 const std::string
& results
,
39 net::URLFetcher::RequestType request_type
,
40 net::URLFetcherDelegate
* d
)
41 : net::TestURLFetcher(0, url
, d
),
42 max_failure_count_(max_failure_count
),
43 current_failure_count_(0),
44 complete_immediately_(complete_immediately
) {
46 set_response_code(response_code
);
47 SetResponseString(results
);
50 virtual ~MockOAuthFetcher() { }
52 virtual void Start() OVERRIDE
{
53 if ((GetResponseCode() != net::HTTP_OK
) && (max_failure_count_
!= -1) &&
54 (current_failure_count_
== max_failure_count_
)) {
55 set_response_code(net::HTTP_OK
);
58 net::URLRequestStatus::Status code
= net::URLRequestStatus::SUCCESS
;
59 if (GetResponseCode() != net::HTTP_OK
) {
60 code
= net::URLRequestStatus::FAILED
;
61 current_failure_count_
++;
63 set_status(net::URLRequestStatus(code
, 0));
65 if (complete_immediately_
)
66 delegate()->OnURLFetchComplete(this);
70 ASSERT_FALSE(complete_immediately_
);
71 delegate()->OnURLFetchComplete(this);
75 int max_failure_count_
;
76 int current_failure_count_
;
77 bool complete_immediately_
;
78 DISALLOW_COPY_AND_ASSIGN(MockOAuthFetcher
);
81 class MockOAuthFetcherFactory
: public net::URLFetcherFactory
,
82 public net::ScopedURLFetcherFactory
{
84 MockOAuthFetcherFactory()
85 : net::ScopedURLFetcherFactory(this),
86 response_code_(net::HTTP_OK
),
87 complete_immediately_(true) {
89 virtual ~MockOAuthFetcherFactory() {}
90 virtual net::URLFetcher
* CreateURLFetcher(
93 net::URLFetcher::RequestType request_type
,
94 net::URLFetcherDelegate
* d
) OVERRIDE
{
95 url_fetcher_
= new MockOAuthFetcher(
98 complete_immediately_
,
105 void set_response_code(int response_code
) {
106 response_code_
= response_code
;
108 void set_max_failure_count(int count
) {
109 max_failure_count_
= count
;
111 void set_results(const std::string
& results
) {
114 MockOAuthFetcher
* get_url_fetcher() {
117 void set_complete_immediately(bool complete_immediately
) {
118 complete_immediately_
= complete_immediately
;
121 MockOAuthFetcher
* url_fetcher_
;
123 bool complete_immediately_
;
124 int max_failure_count_
;
125 std::string results_
;
126 DISALLOW_COPY_AND_ASSIGN(MockOAuthFetcherFactory
);
129 const std::string kTestAccessToken
= "1/fFAGRNJru1FTz70BzhT3Zg";
130 const std::string kTestRefreshToken
=
131 "1/6BMfW9j53gdGImsixUH6kU5RsR4zwI9lUVX-tqf8JXQ";
132 const std::string kTestUserEmail
= "a_user@gmail.com";
133 const std::string kTestUserId
= "8675309";
134 const int kTestExpiresIn
= 3920;
136 const std::string kDummyGetTokensResult
=
137 "{\"access_token\":\"" + kTestAccessToken
+ "\","
138 "\"expires_in\":" + base::IntToString(kTestExpiresIn
) + ","
139 "\"refresh_token\":\"" + kTestRefreshToken
+ "\"}";
141 const std::string kDummyRefreshTokenResult
=
142 "{\"access_token\":\"" + kTestAccessToken
+ "\","
143 "\"expires_in\":" + base::IntToString(kTestExpiresIn
) + "}";
145 const std::string kDummyUserIdResult
=
146 "{\"id\":\"" + kTestUserId
+ "\"}";
148 const std::string kDummyTokenInfoResult
=
149 "{\"issued_to\": \"1234567890.apps.googleusercontent.com\","
150 "\"audience\": \"1234567890.apps.googleusercontent.com\","
151 "\"scope\": \"https://googleapis.com/oauth2/v2/tokeninfo\","
152 "\"expires_in\":" + base::IntToString(kTestExpiresIn
) + "}";
157 class GaiaOAuthClientTest
: public testing::Test
{
159 virtual void SetUp() OVERRIDE
{
160 client_info_
.client_id
= "test_client_id";
161 client_info_
.client_secret
= "test_client_secret";
162 client_info_
.redirect_uri
= "test_redirect_uri";
166 net::TestURLRequestContextGetter
* GetRequestContext() {
167 if (!request_context_getter_
) {
168 request_context_getter_
= new net::TestURLRequestContextGetter(
169 message_loop_
.message_loop_proxy());
171 return request_context_getter_
;
174 base::MessageLoop message_loop_
;
175 scoped_refptr
<net::TestURLRequestContextGetter
> request_context_getter_
;
176 OAuthClientInfo client_info_
;
179 class MockGaiaOAuthClientDelegate
: public gaia::GaiaOAuthClient::Delegate
{
181 MockGaiaOAuthClientDelegate() {}
182 ~MockGaiaOAuthClientDelegate() {}
184 MOCK_METHOD3(OnGetTokensResponse
, void(const std::string
& refresh_token
,
185 const std::string
& access_token
,
186 int expires_in_seconds
));
187 MOCK_METHOD2(OnRefreshTokenResponse
, void(const std::string
& access_token
,
188 int expires_in_seconds
));
189 MOCK_METHOD1(OnGetUserEmailResponse
, void(const std::string
& user_email
));
190 MOCK_METHOD1(OnGetUserIdResponse
, void(const std::string
& user_id
));
191 MOCK_METHOD0(OnOAuthError
, void());
192 MOCK_METHOD1(OnNetworkError
, void(int response_code
));
194 // gMock doesn't like methods that take or return scoped_ptr. A
195 // work-around is to create a mock method that takes a raw ptr, and
196 // override the problematic method to call through to it.
197 // https://groups.google.com/a/chromium.org/d/msg/chromium-dev/01sDxsJ1OYw/I_S0xCBRF2oJ
198 MOCK_METHOD1(OnGetTokenInfoResponsePtr
,
199 void(const base::DictionaryValue
* token_info
));
200 virtual void OnGetTokenInfoResponse(
201 scoped_ptr
<base::DictionaryValue
> token_info
) OVERRIDE
{
202 token_info_
.reset(token_info
.release());
203 OnGetTokenInfoResponsePtr(token_info_
.get());
207 scoped_ptr
<base::DictionaryValue
> token_info_
;
208 DISALLOW_COPY_AND_ASSIGN(MockGaiaOAuthClientDelegate
);
211 TEST_F(GaiaOAuthClientTest
, NetworkFailure
) {
212 int response_code
= net::HTTP_INTERNAL_SERVER_ERROR
;
214 MockGaiaOAuthClientDelegate delegate
;
215 EXPECT_CALL(delegate
, OnNetworkError(response_code
))
218 MockOAuthFetcherFactory factory
;
219 factory
.set_response_code(response_code
);
220 factory
.set_max_failure_count(4);
222 GaiaOAuthClient
auth(GetRequestContext());
223 auth
.GetTokensFromAuthCode(client_info_
, "auth_code", 2, &delegate
);
226 TEST_F(GaiaOAuthClientTest
, NetworkFailureRecover
) {
227 int response_code
= net::HTTP_INTERNAL_SERVER_ERROR
;
229 MockGaiaOAuthClientDelegate delegate
;
230 EXPECT_CALL(delegate
, OnGetTokensResponse(kTestRefreshToken
, kTestAccessToken
,
231 kTestExpiresIn
)).Times(1);
233 MockOAuthFetcherFactory factory
;
234 factory
.set_response_code(response_code
);
235 factory
.set_max_failure_count(4);
236 factory
.set_results(kDummyGetTokensResult
);
238 GaiaOAuthClient
auth(GetRequestContext());
239 auth
.GetTokensFromAuthCode(client_info_
, "auth_code", -1, &delegate
);
242 TEST_F(GaiaOAuthClientTest
, OAuthFailure
) {
243 int response_code
= net::HTTP_BAD_REQUEST
;
245 MockGaiaOAuthClientDelegate delegate
;
246 EXPECT_CALL(delegate
, OnOAuthError()).Times(1);
248 MockOAuthFetcherFactory factory
;
249 factory
.set_response_code(response_code
);
250 factory
.set_max_failure_count(-1);
251 factory
.set_results(kDummyGetTokensResult
);
253 GaiaOAuthClient
auth(GetRequestContext());
254 auth
.GetTokensFromAuthCode(client_info_
, "auth_code", -1, &delegate
);
258 TEST_F(GaiaOAuthClientTest
, GetTokensSuccess
) {
259 MockGaiaOAuthClientDelegate delegate
;
260 EXPECT_CALL(delegate
, OnGetTokensResponse(kTestRefreshToken
, kTestAccessToken
,
261 kTestExpiresIn
)).Times(1);
263 MockOAuthFetcherFactory factory
;
264 factory
.set_results(kDummyGetTokensResult
);
266 GaiaOAuthClient
auth(GetRequestContext());
267 auth
.GetTokensFromAuthCode(client_info_
, "auth_code", -1, &delegate
);
270 TEST_F(GaiaOAuthClientTest
, RefreshTokenSuccess
) {
271 MockGaiaOAuthClientDelegate delegate
;
272 EXPECT_CALL(delegate
, OnRefreshTokenResponse(kTestAccessToken
,
273 kTestExpiresIn
)).Times(1);
275 MockOAuthFetcherFactory factory
;
276 factory
.set_results(kDummyRefreshTokenResult
);
277 factory
.set_complete_immediately(false);
279 GaiaOAuthClient
auth(GetRequestContext());
280 auth
.RefreshToken(client_info_
, "refresh_token", std::vector
<std::string
>(),
282 EXPECT_THAT(factory
.get_url_fetcher()->upload_data(),
283 Not(HasSubstr("scope")));
284 factory
.get_url_fetcher()->Finish();
287 TEST_F(GaiaOAuthClientTest
, RefreshTokenDownscopingSuccess
) {
288 MockGaiaOAuthClientDelegate delegate
;
289 EXPECT_CALL(delegate
, OnRefreshTokenResponse(kTestAccessToken
,
290 kTestExpiresIn
)).Times(1);
292 MockOAuthFetcherFactory factory
;
293 factory
.set_results(kDummyRefreshTokenResult
);
294 factory
.set_complete_immediately(false);
296 GaiaOAuthClient
auth(GetRequestContext());
297 auth
.RefreshToken(client_info_
, "refresh_token",
298 std::vector
<std::string
>(1, "scope4test"), -1, &delegate
);
299 EXPECT_THAT(factory
.get_url_fetcher()->upload_data(),
300 HasSubstr("&scope=scope4test"));
301 factory
.get_url_fetcher()->Finish();
304 TEST_F(GaiaOAuthClientTest
, GetUserEmail
) {
305 MockGaiaOAuthClientDelegate delegate
;
306 EXPECT_CALL(delegate
, OnGetUserEmailResponse(kTestUserEmail
)).Times(1);
308 const std::string kDummyUserInfoResult
=
309 "{\"emails\": [{\"value\":\"" + kTestUserEmail
+
310 "\", \"type\":\"account\"}]}";
312 MockOAuthFetcherFactory factory
;
313 factory
.set_results(kDummyUserInfoResult
);
315 GaiaOAuthClient
auth(GetRequestContext());
316 auth
.GetUserEmail("access_token", 1, &delegate
);
319 TEST_F(GaiaOAuthClientTest
, GetUserEmailSecondItemValid
) {
320 MockGaiaOAuthClientDelegate delegate
;
321 EXPECT_CALL(delegate
, OnGetUserEmailResponse(kTestUserEmail
)).Times(1);
323 const std::string kDummyUserInfoResult
=
324 "{\"emails\": [{\"value\":\"foo\"},"
325 "{\"value\":\"" + kTestUserEmail
+
326 "\", \"type\":\"account\"}]}";
328 MockOAuthFetcherFactory factory
;
329 factory
.set_results(kDummyUserInfoResult
);
331 GaiaOAuthClient
auth(GetRequestContext());
332 auth
.GetUserEmail("access_token", 1, &delegate
);
335 TEST_F(GaiaOAuthClientTest
, GetUserEmailNoValidItems
) {
336 MockGaiaOAuthClientDelegate delegate
;
337 EXPECT_CALL(delegate
, OnNetworkError(_
)).Times(1);
339 const std::string kDummyUserInfoResult
=
340 "{\"emails\": [{\"value\":\"" + kTestUserEmail
+
341 "\", \"type\":\"foo\"}]}";
343 MockOAuthFetcherFactory factory
;
344 factory
.set_results(kDummyUserInfoResult
);
346 GaiaOAuthClient
auth(GetRequestContext());
347 auth
.GetUserEmail("access_token", 1, &delegate
);
350 TEST_F(GaiaOAuthClientTest
, GetUserId
) {
351 MockGaiaOAuthClientDelegate delegate
;
352 EXPECT_CALL(delegate
, OnGetUserIdResponse(kTestUserId
)).Times(1);
354 MockOAuthFetcherFactory factory
;
355 factory
.set_results(kDummyUserIdResult
);
357 GaiaOAuthClient
auth(GetRequestContext());
358 auth
.GetUserId("access_token", 1, &delegate
);
361 TEST_F(GaiaOAuthClientTest
, GetTokenInfo
) {
362 const base::DictionaryValue
* captured_result
;
364 MockGaiaOAuthClientDelegate delegate
;
365 EXPECT_CALL(delegate
, OnGetTokenInfoResponsePtr(_
))
366 .WillOnce(SaveArg
<0>(&captured_result
));
368 MockOAuthFetcherFactory factory
;
369 factory
.set_results(kDummyTokenInfoResult
);
371 GaiaOAuthClient
auth(GetRequestContext());
372 auth
.GetTokenInfo("access_token", 1, &delegate
);
374 std::string issued_to
;
375 ASSERT_TRUE(captured_result
->GetString("issued_to", &issued_to
));
376 ASSERT_EQ("1234567890.apps.googleusercontent.com", issued_to
);