gaia_oauth_client_unittest.cc revision 9ab5563a3196760eb381d102cbb2bc0f7abc6a50
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/message_loop/message_loop.h" 11#include "base/strings/string_number_conversions.h" 12#include "base/values.h" 13#include "google_apis/gaia/gaia_oauth_client.h" 14#include "net/base/net_errors.h" 15#include "net/http/http_status_code.h" 16#include "net/url_request/test_url_fetcher_factory.h" 17#include "net/url_request/url_fetcher_delegate.h" 18#include "net/url_request/url_request_status.h" 19#include "net/url_request/url_request_test_util.h" 20#include "testing/gmock/include/gmock/gmock.h" 21#include "testing/gtest/include/gtest/gtest.h" 22#include "url/gurl.h" 23 24using ::testing::_; 25using ::testing::Eq; 26using ::testing::HasSubstr; 27using ::testing::Pointee; 28using ::testing::SaveArg; 29 30namespace { 31 32// Responds as though OAuth returned from the server. 33class MockOAuthFetcher : public net::TestURLFetcher { 34 public: 35 MockOAuthFetcher(int response_code, 36 int max_failure_count, 37 bool complete_immediately, 38 const GURL& url, 39 const std::string& results, 40 net::URLFetcher::RequestType request_type, 41 net::URLFetcherDelegate* d) 42 : net::TestURLFetcher(0, url, d), 43 max_failure_count_(max_failure_count), 44 current_failure_count_(0), 45 complete_immediately_(complete_immediately) { 46 set_url(url); 47 set_response_code(response_code); 48 SetResponseString(results); 49 } 50 51 virtual ~MockOAuthFetcher() { } 52 53 virtual void Start() OVERRIDE { 54 if ((GetResponseCode() != net::HTTP_OK) && (max_failure_count_ != -1) && 55 (current_failure_count_ == max_failure_count_)) { 56 set_response_code(net::HTTP_OK); 57 } 58 59 net::URLRequestStatus::Status code = net::URLRequestStatus::SUCCESS; 60 if (GetResponseCode() != net::HTTP_OK) { 61 code = net::URLRequestStatus::FAILED; 62 current_failure_count_++; 63 } 64 set_status(net::URLRequestStatus(code, 0)); 65 66 if (complete_immediately_) 67 delegate()->OnURLFetchComplete(this); 68 } 69 70 void Finish() { 71 ASSERT_FALSE(complete_immediately_); 72 delegate()->OnURLFetchComplete(this); 73 } 74 75 private: 76 int max_failure_count_; 77 int current_failure_count_; 78 bool complete_immediately_; 79 DISALLOW_COPY_AND_ASSIGN(MockOAuthFetcher); 80}; 81 82class MockOAuthFetcherFactory : public net::URLFetcherFactory, 83 public net::ScopedURLFetcherFactory { 84 public: 85 MockOAuthFetcherFactory() 86 : net::ScopedURLFetcherFactory(this), 87 response_code_(net::HTTP_OK), 88 complete_immediately_(true) { 89 } 90 virtual ~MockOAuthFetcherFactory() {} 91 virtual net::URLFetcher* CreateURLFetcher( 92 int id, 93 const GURL& url, 94 net::URLFetcher::RequestType request_type, 95 net::URLFetcherDelegate* d) OVERRIDE { 96 url_fetcher_ = new MockOAuthFetcher( 97 response_code_, 98 max_failure_count_, 99 complete_immediately_, 100 url, 101 results_, 102 request_type, 103 d); 104 return url_fetcher_; 105 } 106 void set_response_code(int response_code) { 107 response_code_ = response_code; 108 } 109 void set_max_failure_count(int count) { 110 max_failure_count_ = count; 111 } 112 void set_results(const std::string& results) { 113 results_ = results; 114 } 115 MockOAuthFetcher* get_url_fetcher() { 116 return url_fetcher_; 117 } 118 void set_complete_immediately(bool complete_immediately) { 119 complete_immediately_ = complete_immediately; 120 } 121 private: 122 MockOAuthFetcher* url_fetcher_; 123 int response_code_; 124 bool complete_immediately_; 125 int max_failure_count_; 126 std::string results_; 127 DISALLOW_COPY_AND_ASSIGN(MockOAuthFetcherFactory); 128}; 129 130const std::string kTestAccessToken = "1/fFAGRNJru1FTz70BzhT3Zg"; 131const std::string kTestRefreshToken = 132 "1/6BMfW9j53gdGImsixUH6kU5RsR4zwI9lUVX-tqf8JXQ"; 133const std::string kTestUserEmail = "a_user@gmail.com"; 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 kDummyUserInfoResult = 146 "{\"email\":\"" + kTestUserEmail + "\"}"; 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 public: 159 GaiaOAuthClientTest() {} 160 virtual void SetUp() OVERRIDE { 161 client_info_.client_id = "test_client_id"; 162 client_info_.client_secret = "test_client_secret"; 163 client_info_.redirect_uri = "test_redirect_uri"; 164 }; 165 166 protected: 167 net::TestURLRequestContextGetter* GetRequestContext() { 168 if (!request_context_getter_) { 169 request_context_getter_ = new net::TestURLRequestContextGetter( 170 message_loop_.message_loop_proxy()); 171 } 172 return request_context_getter_; 173 } 174 175 base::MessageLoop message_loop_; 176 scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_; 177 OAuthClientInfo client_info_; 178}; 179 180class MockGaiaOAuthClientDelegate : public gaia::GaiaOAuthClient::Delegate { 181 public: 182 MockGaiaOAuthClientDelegate() {} 183 ~MockGaiaOAuthClientDelegate() {} 184 185 MOCK_METHOD3(OnGetTokensResponse, void(const std::string& refresh_token, 186 const std::string& access_token, 187 int expires_in_seconds)); 188 MOCK_METHOD2(OnRefreshTokenResponse, void(const std::string& access_token, 189 int expires_in_seconds)); 190 MOCK_METHOD1(OnGetUserEmailResponse, void(const std::string& user_email)); 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 DictionaryValue* token_info)); 200 virtual void OnGetTokenInfoResponse(scoped_ptr<DictionaryValue> token_info) 201 OVERRIDE { 202 token_info_.reset(token_info.release()); 203 OnGetTokenInfoResponsePtr(token_info_.get()); 204 } 205 206 private: 207 scoped_ptr<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 304 305TEST_F(GaiaOAuthClientTest, GetUserEmail) { 306 MockGaiaOAuthClientDelegate delegate; 307 EXPECT_CALL(delegate, OnGetUserEmailResponse(kTestUserEmail)).Times(1); 308 309 MockOAuthFetcherFactory factory; 310 factory.set_results(kDummyUserInfoResult); 311 312 GaiaOAuthClient auth(GetRequestContext()); 313 auth.GetUserEmail("access_token", 1, &delegate); 314} 315 316TEST_F(GaiaOAuthClientTest, GetTokenInfo) { 317 const DictionaryValue* captured_result; 318 319 MockGaiaOAuthClientDelegate delegate; 320 EXPECT_CALL(delegate, OnGetTokenInfoResponsePtr(_)) 321 .WillOnce(SaveArg<0>(&captured_result)); 322 323 MockOAuthFetcherFactory factory; 324 factory.set_results(kDummyTokenInfoResult); 325 326 GaiaOAuthClient auth(GetRequestContext()); 327 auth.GetTokenInfo("access_token", 1, &delegate); 328 329 std::string issued_to; 330 ASSERT_TRUE(captured_result->GetString("issued_to", &issued_to)); 331 ASSERT_EQ("1234567890.apps.googleusercontent.com", issued_to); 332} 333 334} // namespace gaia 335