gaia_oauth_client_unittest.cc revision 5c02ac1a9c1b504631c0a3d2b6e737b5d738bae1
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. 4// 5// A complete set of unit tests for GaiaOAuthClient. 6 7#include <string> 8#include <vector> 9 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" 21#include "url/gurl.h" 22 23using ::testing::_; 24using ::testing::Eq; 25using ::testing::HasSubstr; 26using ::testing::Pointee; 27using ::testing::SaveArg; 28 29namespace { 30 31// Responds as though OAuth returned from the server. 32class MockOAuthFetcher : public net::TestURLFetcher { 33 public: 34 MockOAuthFetcher(int response_code, 35 int max_failure_count, 36 bool complete_immediately, 37 const GURL& url, 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) { 45 set_url(url); 46 set_response_code(response_code); 47 SetResponseString(results); 48 } 49 50 virtual ~MockOAuthFetcher() { } 51 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); 56 } 57 58 net::URLRequestStatus::Status code = net::URLRequestStatus::SUCCESS; 59 if (GetResponseCode() != net::HTTP_OK) { 60 code = net::URLRequestStatus::FAILED; 61 current_failure_count_++; 62 } 63 set_status(net::URLRequestStatus(code, 0)); 64 65 if (complete_immediately_) 66 delegate()->OnURLFetchComplete(this); 67 } 68 69 void Finish() { 70 ASSERT_FALSE(complete_immediately_); 71 delegate()->OnURLFetchComplete(this); 72 } 73 74 private: 75 int max_failure_count_; 76 int current_failure_count_; 77 bool complete_immediately_; 78 DISALLOW_COPY_AND_ASSIGN(MockOAuthFetcher); 79}; 80 81class MockOAuthFetcherFactory : public net::URLFetcherFactory, 82 public net::ScopedURLFetcherFactory { 83 public: 84 MockOAuthFetcherFactory() 85 : net::ScopedURLFetcherFactory(this), 86 response_code_(net::HTTP_OK), 87 complete_immediately_(true) { 88 } 89 virtual ~MockOAuthFetcherFactory() {} 90 virtual net::URLFetcher* CreateURLFetcher( 91 int id, 92 const GURL& url, 93 net::URLFetcher::RequestType request_type, 94 net::URLFetcherDelegate* d) OVERRIDE { 95 url_fetcher_ = new MockOAuthFetcher( 96 response_code_, 97 max_failure_count_, 98 complete_immediately_, 99 url, 100 results_, 101 request_type, 102 d); 103 return url_fetcher_; 104 } 105 void set_response_code(int response_code) { 106 response_code_ = response_code; 107 } 108 void set_max_failure_count(int count) { 109 max_failure_count_ = count; 110 } 111 void set_results(const std::string& results) { 112 results_ = results; 113 } 114 MockOAuthFetcher* get_url_fetcher() { 115 return url_fetcher_; 116 } 117 void set_complete_immediately(bool complete_immediately) { 118 complete_immediately_ = complete_immediately; 119 } 120 private: 121 MockOAuthFetcher* url_fetcher_; 122 int response_code_; 123 bool complete_immediately_; 124 int max_failure_count_; 125 std::string results_; 126 DISALLOW_COPY_AND_ASSIGN(MockOAuthFetcherFactory); 127}; 128 129const std::string kTestAccessToken = "1/fFAGRNJru1FTz70BzhT3Zg"; 130const std::string kTestRefreshToken = 131 "1/6BMfW9j53gdGImsixUH6kU5RsR4zwI9lUVX-tqf8JXQ"; 132const std::string kTestUserEmail = "a_user@gmail.com"; 133const std::string kTestUserId = "8675309"; 134const int kTestExpiresIn = 3920; 135 136const std::string kDummyGetTokensResult = 137 "{\"access_token\":\"" + kTestAccessToken + "\"," 138 "\"expires_in\":" + base::IntToString(kTestExpiresIn) + "," 139 "\"refresh_token\":\"" + kTestRefreshToken + "\"}"; 140 141const std::string kDummyRefreshTokenResult = 142 "{\"access_token\":\"" + kTestAccessToken + "\"," 143 "\"expires_in\":" + base::IntToString(kTestExpiresIn) + "}"; 144 145const std::string kDummyUserIdResult = 146 "{\"id\":\"" + kTestUserId + "\"}"; 147 148const 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) + "}"; 153} 154 155namespace gaia { 156 157class GaiaOAuthClientTest : public testing::Test { 158 protected: 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"; 163 }; 164 165 protected: 166 net::TestURLRequestContextGetter* GetRequestContext() { 167 if (!request_context_getter_) { 168 request_context_getter_ = new net::TestURLRequestContextGetter( 169 message_loop_.message_loop_proxy()); 170 } 171 return request_context_getter_; 172 } 173 174 base::MessageLoop message_loop_; 175 scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_; 176 OAuthClientInfo client_info_; 177}; 178 179class MockGaiaOAuthClientDelegate : public gaia::GaiaOAuthClient::Delegate { 180 public: 181 MockGaiaOAuthClientDelegate() {} 182 ~MockGaiaOAuthClientDelegate() {} 183 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)); 193 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()); 204 } 205 206 private: 207 scoped_ptr<base::DictionaryValue> token_info_; 208 DISALLOW_COPY_AND_ASSIGN(MockGaiaOAuthClientDelegate); 209}; 210 211TEST_F(GaiaOAuthClientTest, NetworkFailure) { 212 int response_code = net::HTTP_INTERNAL_SERVER_ERROR; 213 214 MockGaiaOAuthClientDelegate delegate; 215 EXPECT_CALL(delegate, OnNetworkError(response_code)) 216 .Times(1); 217 218 MockOAuthFetcherFactory factory; 219 factory.set_response_code(response_code); 220 factory.set_max_failure_count(4); 221 222 GaiaOAuthClient auth(GetRequestContext()); 223 auth.GetTokensFromAuthCode(client_info_, "auth_code", 2, &delegate); 224} 225 226TEST_F(GaiaOAuthClientTest, NetworkFailureRecover) { 227 int response_code = net::HTTP_INTERNAL_SERVER_ERROR; 228 229 MockGaiaOAuthClientDelegate delegate; 230 EXPECT_CALL(delegate, OnGetTokensResponse(kTestRefreshToken, kTestAccessToken, 231 kTestExpiresIn)).Times(1); 232 233 MockOAuthFetcherFactory factory; 234 factory.set_response_code(response_code); 235 factory.set_max_failure_count(4); 236 factory.set_results(kDummyGetTokensResult); 237 238 GaiaOAuthClient auth(GetRequestContext()); 239 auth.GetTokensFromAuthCode(client_info_, "auth_code", -1, &delegate); 240} 241 242TEST_F(GaiaOAuthClientTest, OAuthFailure) { 243 int response_code = net::HTTP_BAD_REQUEST; 244 245 MockGaiaOAuthClientDelegate delegate; 246 EXPECT_CALL(delegate, OnOAuthError()).Times(1); 247 248 MockOAuthFetcherFactory factory; 249 factory.set_response_code(response_code); 250 factory.set_max_failure_count(-1); 251 factory.set_results(kDummyGetTokensResult); 252 253 GaiaOAuthClient auth(GetRequestContext()); 254 auth.GetTokensFromAuthCode(client_info_, "auth_code", -1, &delegate); 255} 256 257 258TEST_F(GaiaOAuthClientTest, GetTokensSuccess) { 259 MockGaiaOAuthClientDelegate delegate; 260 EXPECT_CALL(delegate, OnGetTokensResponse(kTestRefreshToken, kTestAccessToken, 261 kTestExpiresIn)).Times(1); 262 263 MockOAuthFetcherFactory factory; 264 factory.set_results(kDummyGetTokensResult); 265 266 GaiaOAuthClient auth(GetRequestContext()); 267 auth.GetTokensFromAuthCode(client_info_, "auth_code", -1, &delegate); 268} 269 270TEST_F(GaiaOAuthClientTest, RefreshTokenSuccess) { 271 MockGaiaOAuthClientDelegate delegate; 272 EXPECT_CALL(delegate, OnRefreshTokenResponse(kTestAccessToken, 273 kTestExpiresIn)).Times(1); 274 275 MockOAuthFetcherFactory factory; 276 factory.set_results(kDummyRefreshTokenResult); 277 factory.set_complete_immediately(false); 278 279 GaiaOAuthClient auth(GetRequestContext()); 280 auth.RefreshToken(client_info_, "refresh_token", std::vector<std::string>(), 281 -1, &delegate); 282 EXPECT_THAT(factory.get_url_fetcher()->upload_data(), 283 Not(HasSubstr("scope"))); 284 factory.get_url_fetcher()->Finish(); 285} 286 287TEST_F(GaiaOAuthClientTest, RefreshTokenDownscopingSuccess) { 288 MockGaiaOAuthClientDelegate delegate; 289 EXPECT_CALL(delegate, OnRefreshTokenResponse(kTestAccessToken, 290 kTestExpiresIn)).Times(1); 291 292 MockOAuthFetcherFactory factory; 293 factory.set_results(kDummyRefreshTokenResult); 294 factory.set_complete_immediately(false); 295 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(); 302} 303 304TEST_F(GaiaOAuthClientTest, GetUserEmail) { 305 MockGaiaOAuthClientDelegate delegate; 306 EXPECT_CALL(delegate, OnGetUserEmailResponse(kTestUserEmail)).Times(1); 307 308 const std::string kDummyUserInfoResult = 309 "{\"emails\": [{\"value\":\"" + kTestUserEmail + 310 "\", \"type\":\"account\"}]}"; 311 312 MockOAuthFetcherFactory factory; 313 factory.set_results(kDummyUserInfoResult); 314 315 GaiaOAuthClient auth(GetRequestContext()); 316 auth.GetUserEmail("access_token", 1, &delegate); 317} 318 319TEST_F(GaiaOAuthClientTest, GetUserEmailSecondItemValid) { 320 MockGaiaOAuthClientDelegate delegate; 321 EXPECT_CALL(delegate, OnGetUserEmailResponse(kTestUserEmail)).Times(1); 322 323 const std::string kDummyUserInfoResult = 324 "{\"emails\": [{\"value\":\"foo\"}," 325 "{\"value\":\"" + kTestUserEmail + 326 "\", \"type\":\"account\"}]}"; 327 328 MockOAuthFetcherFactory factory; 329 factory.set_results(kDummyUserInfoResult); 330 331 GaiaOAuthClient auth(GetRequestContext()); 332 auth.GetUserEmail("access_token", 1, &delegate); 333} 334 335TEST_F(GaiaOAuthClientTest, GetUserEmailNoValidItems) { 336 MockGaiaOAuthClientDelegate delegate; 337 EXPECT_CALL(delegate, OnNetworkError(_)).Times(1); 338 339 const std::string kDummyUserInfoResult = 340 "{\"emails\": [{\"value\":\"" + kTestUserEmail + 341 "\", \"type\":\"foo\"}]}"; 342 343 MockOAuthFetcherFactory factory; 344 factory.set_results(kDummyUserInfoResult); 345 346 GaiaOAuthClient auth(GetRequestContext()); 347 auth.GetUserEmail("access_token", 1, &delegate); 348} 349 350TEST_F(GaiaOAuthClientTest, GetUserId) { 351 MockGaiaOAuthClientDelegate delegate; 352 EXPECT_CALL(delegate, OnGetUserIdResponse(kTestUserId)).Times(1); 353 354 MockOAuthFetcherFactory factory; 355 factory.set_results(kDummyUserIdResult); 356 357 GaiaOAuthClient auth(GetRequestContext()); 358 auth.GetUserId("access_token", 1, &delegate); 359} 360 361TEST_F(GaiaOAuthClientTest, GetTokenInfo) { 362 const base::DictionaryValue* captured_result; 363 364 MockGaiaOAuthClientDelegate delegate; 365 EXPECT_CALL(delegate, OnGetTokenInfoResponsePtr(_)) 366 .WillOnce(SaveArg<0>(&captured_result)); 367 368 MockOAuthFetcherFactory factory; 369 factory.set_results(kDummyTokenInfoResult); 370 371 GaiaOAuthClient auth(GetRequestContext()); 372 auth.GetTokenInfo("access_token", 1, &delegate); 373 374 std::string issued_to; 375 ASSERT_TRUE(captured_result->GetString("issued_to", &issued_to)); 376 ASSERT_EQ("1234567890.apps.googleusercontent.com", issued_to); 377} 378 379} // namespace gaia 380