Index: chrome/browser/managed_mode/managed_user_refresh_token_fetcher_unittest.cc |
diff --git a/chrome/browser/managed_mode/managed_user_refresh_token_fetcher_unittest.cc b/chrome/browser/managed_mode/managed_user_refresh_token_fetcher_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..83c828586a6dc8f6823d42b1673d4fcb1412bb9a |
--- /dev/null |
+++ b/chrome/browser/managed_mode/managed_user_refresh_token_fetcher_unittest.cc |
@@ -0,0 +1,426 @@ |
+// Copyright 2013 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "base/bind.h" |
+#include "base/memory/scoped_ptr.h" |
+#include "base/message_loop.h" |
+#include "base/stringprintf.h" |
+#include "base/strings/utf_string_conversions.h" |
+#include "chrome/browser/managed_mode/managed_user_refresh_token_fetcher.h" |
+#include "chrome/browser/signin/oauth2_token_service.h" |
+#include "chrome/test/base/testing_profile.h" |
+#include "content/public/test/test_browser_thread.h" |
+#include "google_apis/gaia/gaia_urls.h" |
+#include "google_apis/gaia/google_service_auth_error.h" |
+#include "net/base/net_errors.h" |
+#include "net/base/url_util.h" |
+#include "net/http/http_request_headers.h" |
+#include "net/http/http_status_code.h" |
+#include "net/url_request/test_url_fetcher_factory.h" |
+#include "net/url_request/url_fetcher_delegate.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+namespace { |
+ |
+const char kManagedUserId[] = "abcdef"; |
+const char kName[] = "Homestar"; |
+const char kDeviceName[] = "Compy"; |
+ |
+const char kAccessToken[] = "accesstoken"; |
+const char kAuthorizationCode[] = "authorizationcode"; |
+const char kManagedUserToken[] = "managedusertoken"; |
+ |
+const char kIssueTokenResponseFormat[] = |
+ "{" |
+ " \"code\": \"%s\"" |
+ "}"; |
+ |
+const char kGetRefreshTokenResponseFormat[] = |
+ "{" |
+ " \"access_token\": \"<ignored>\"," |
+ " \"expires_in\": 12345," |
+ " \"refresh_token\": \"%s\"" |
+ "}"; |
+ |
+// MockOAuth2TokenService --------------------------------------------- |
+ |
+class MockOAuth2TokenService : public OAuth2TokenService { |
+ public: |
+ class Request : public OAuth2TokenService::Request { |
+ public: |
+ Request(const OAuth2TokenService::ScopeSet& scopes, |
+ OAuth2TokenService::Consumer* consumer, |
+ MockOAuth2TokenService* owner); |
+ virtual ~Request(); |
+ |
+ void Succeed(); |
+ void Fail(GoogleServiceAuthError::State error); |
+ |
+ const OAuth2TokenService::ScopeSet& scopes() const { return scopes_; } |
+ |
+ private: |
+ OAuth2TokenService::ScopeSet scopes_; |
+ |
+ OAuth2TokenService::Consumer* consumer_; |
+ |
+ MockOAuth2TokenService* owner_; |
+ }; |
+ |
+ MockOAuth2TokenService(); |
+ virtual ~MockOAuth2TokenService(); |
+ |
+ Request* request() const { return request_; } |
+ |
+ void ClearRequest(Request* request); |
+ |
+ private: |
+ // OAuth2TokenService overrides: |
+ virtual scoped_ptr<OAuth2TokenService::Request> StartRequest( |
+ const OAuth2TokenService::ScopeSet& scopes, |
+ OAuth2TokenService::Consumer* consumer) OVERRIDE; |
+ virtual std::string GetRefreshToken() OVERRIDE; |
+ |
+ Request* request_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(MockOAuth2TokenService); |
+}; |
+ |
+MockOAuth2TokenService::Request::Request( |
+ const OAuth2TokenService::ScopeSet& scopes, |
+ OAuth2TokenService::Consumer* consumer, |
+ MockOAuth2TokenService* owner) |
+ : scopes_(scopes), |
+ consumer_(consumer), |
+ owner_(owner) {} |
+ |
+MockOAuth2TokenService::Request::~Request() { |
+ owner_->ClearRequest(this); |
+} |
+ |
+void MockOAuth2TokenService::Request::Succeed() { |
+ base::Time expiration_date = base::Time::Now() + |
+ base::TimeDelta::FromHours(1); |
+ consumer_->OnGetTokenSuccess(this, kAccessToken, expiration_date); |
+} |
+ |
+void MockOAuth2TokenService::Request::Fail( |
+ GoogleServiceAuthError::State error) { |
+ consumer_->OnGetTokenFailure(this, GoogleServiceAuthError(error)); |
+} |
+ |
+MockOAuth2TokenService::MockOAuth2TokenService() |
+ : OAuth2TokenService(NULL), |
+ request_(NULL) {} |
+ |
+MockOAuth2TokenService::~MockOAuth2TokenService() { |
+ EXPECT_FALSE(request_); |
+} |
+ |
+void MockOAuth2TokenService::ClearRequest( |
+ MockOAuth2TokenService::Request* request) { |
+ if (request_ == request) |
+ request_ = NULL; |
+} |
+ |
+scoped_ptr<OAuth2TokenService::Request> MockOAuth2TokenService::StartRequest( |
+ const OAuth2TokenService::ScopeSet& scopes, |
+ OAuth2TokenService::Consumer* consumer) { |
+ scoped_ptr<Request> request(new Request(scopes, consumer, this)); |
+ request_ = request.get(); |
+ return request.PassAs<OAuth2TokenService::Request>(); |
+} |
+ |
+std::string MockOAuth2TokenService::GetRefreshToken() { |
+ NOTREACHED(); |
+ return std::string(); |
+} |
+ |
+// Utility methods -------------------------------------------------- |
+ |
+// Slightly hacky way to extract a value from a URL-encoded POST request body. |
+bool GetValueForKey(const std::string& encoded_string, |
+ const std::string& key, |
+ std::string* value) { |
+ GURL url("http://example.com/?" + encoded_string); |
+ return net::GetValueForKeyInQuery(url, key, value); |
+} |
+ |
+void SendResponse(net::TestURLFetcher* url_fetcher, |
+ const std::string& response) { |
+ url_fetcher->set_status( |
+ net::URLRequestStatus(net::URLRequestStatus::SUCCESS, 0)); |
+ url_fetcher->set_response_code(net::HTTP_OK); |
+ url_fetcher->SetResponseString(response); |
+ url_fetcher->delegate()->OnURLFetchComplete(url_fetcher); |
+} |
+ |
+void SetNetworkError(net::TestURLFetcher* url_fetcher, int error) { |
+ url_fetcher->set_status( |
+ net::URLRequestStatus(net::URLRequestStatus::FAILED, error)); |
+ url_fetcher->delegate()->OnURLFetchComplete(url_fetcher); |
+} |
+ |
+void SetHttpError(net::TestURLFetcher* url_fetcher, int error) { |
+ url_fetcher->set_status(net::URLRequestStatus()); |
+ url_fetcher->set_response_code(error); |
+ url_fetcher->delegate()->OnURLFetchComplete(url_fetcher); |
+} |
+ |
+} // namespace |
+ |
+class ManagedUserRefreshTokenFetcherTest : public testing::Test { |
+ public: |
+ ManagedUserRefreshTokenFetcherTest(); |
+ virtual ~ManagedUserRefreshTokenFetcherTest() {} |
+ |
+ protected: |
+ void StartFetching(); |
+ |
+ MockOAuth2TokenService::Request* GetOAuth2TokenServiceRequest(); |
+ net::TestURLFetcher* GetIssueTokenRequest(); |
+ net::TestURLFetcher* GetRefreshTokenRequest(); |
+ |
+ void MakeIssueTokenRequestSucceed(); |
+ void MakeRefreshTokenFetchSucceed(); |
+ |
+ void Reset(); |
+ |
+ const GoogleServiceAuthError& error() const { return error_; } |
+ const std::string& token() const { return token_; } |
+ |
+ private: |
+ void OnTokenFetched(const GoogleServiceAuthError& error, |
+ const std::string& token); |
+ |
+ base::WeakPtrFactory<ManagedUserRefreshTokenFetcherTest> weak_ptr_factory_; |
+ base::MessageLoop message_loop_; |
+ content::TestBrowserThread ui_thread_; |
+ TestingProfile profile_; |
+ MockOAuth2TokenService oauth2_token_service_; |
+ net::TestURLFetcherFactory url_fetcher_factory_; |
+ scoped_ptr<ManagedUserRefreshTokenFetcher> token_fetcher_; |
+ |
+ GoogleServiceAuthError error_; |
+ std::string token_; |
+}; |
+ |
+ManagedUserRefreshTokenFetcherTest::ManagedUserRefreshTokenFetcherTest() |
+ : weak_ptr_factory_(this), |
+ ui_thread_(content::BrowserThread::UI, &message_loop_), |
+ token_fetcher_( |
+ ManagedUserRefreshTokenFetcher::Create(&oauth2_token_service_, |
+ profile_.GetRequestContext())), |
+ error_(GoogleServiceAuthError::NONE) {} |
+ |
+void ManagedUserRefreshTokenFetcherTest::StartFetching() { |
+ token_fetcher_->Start(kManagedUserId, UTF8ToUTF16(kName), kDeviceName, |
+ base::Bind( |
+ &ManagedUserRefreshTokenFetcherTest::OnTokenFetched, |
+ weak_ptr_factory_.GetWeakPtr())); |
+} |
+ |
+MockOAuth2TokenService::Request* |
+ManagedUserRefreshTokenFetcherTest::GetOAuth2TokenServiceRequest() { |
+ MockOAuth2TokenService::Request* request = oauth2_token_service_.request(); |
+ |
+ OAuth2TokenService::ScopeSet scopes = request->scopes(); |
+ EXPECT_EQ(1u, scopes.size()); |
+ EXPECT_EQ(1u, scopes.count(GaiaUrls::GetInstance()->oauth1_login_scope())); |
+ return request; |
+} |
+ |
+net::TestURLFetcher* |
+ManagedUserRefreshTokenFetcherTest::GetIssueTokenRequest() { |
+ net::TestURLFetcher* url_fetcher = url_fetcher_factory_.GetFetcherByID(1); |
+ if (!url_fetcher) |
+ return NULL; |
+ |
+ EXPECT_EQ(GaiaUrls::GetInstance()->oauth2_issue_token_url(), |
+ url_fetcher->GetOriginalURL().spec()); |
+ std::string access_token; |
+ net::HttpRequestHeaders headers; |
+ url_fetcher->GetExtraRequestHeaders(&headers); |
+ EXPECT_TRUE(headers.GetHeader("Authorization", &access_token)); |
+ EXPECT_EQ(std::string("Bearer ") + kAccessToken, access_token); |
+ const std::string upload_data = url_fetcher->upload_data(); |
+ std::string managed_user_id; |
+ EXPECT_TRUE(GetValueForKey(upload_data, "profile_id", &managed_user_id)); |
+ EXPECT_EQ(kManagedUserId, managed_user_id); |
+ std::string name; |
+ EXPECT_TRUE(GetValueForKey(upload_data, "profile_name", &name)); |
+ EXPECT_EQ(kName, name); |
+ std::string device_name; |
+ EXPECT_TRUE(GetValueForKey(upload_data, "device_name", &device_name)); |
+ EXPECT_EQ(kDeviceName, device_name); |
+ return url_fetcher; |
+} |
+ |
+net::TestURLFetcher* |
+ManagedUserRefreshTokenFetcherTest::GetRefreshTokenRequest() { |
+ net::TestURLFetcher* url_fetcher = url_fetcher_factory_.GetFetcherByID(0); |
+ if (!url_fetcher) |
+ return NULL; |
+ |
+ EXPECT_EQ(GaiaUrls::GetInstance()->oauth2_token_url(), |
+ url_fetcher->GetOriginalURL().spec()); |
+ std::string auth_code; |
+ EXPECT_TRUE(GetValueForKey(url_fetcher->upload_data(), "code", &auth_code)); |
+ EXPECT_EQ(kAuthorizationCode, auth_code); |
+ return url_fetcher; |
+} |
+ |
+void ManagedUserRefreshTokenFetcherTest::MakeIssueTokenRequestSucceed() { |
+ SendResponse(GetIssueTokenRequest(), |
+ base::StringPrintf(kIssueTokenResponseFormat, |
+ kAuthorizationCode)); |
+} |
+ |
+void ManagedUserRefreshTokenFetcherTest::MakeRefreshTokenFetchSucceed() { |
+ SendResponse(GetRefreshTokenRequest(), |
+ base::StringPrintf(kGetRefreshTokenResponseFormat, |
+ kManagedUserToken)); |
+} |
+ |
+void ManagedUserRefreshTokenFetcherTest::Reset() { |
+ token_fetcher_.reset(); |
+} |
+ |
+void ManagedUserRefreshTokenFetcherTest::OnTokenFetched( |
+ const GoogleServiceAuthError& error, |
+ const std::string& token) { |
+ error_ = error; |
+ token_ = token; |
+} |
+ |
+// Tests -------------------------------------------------------- |
+ |
+TEST_F(ManagedUserRefreshTokenFetcherTest, Success) { |
+ StartFetching(); |
+ GetOAuth2TokenServiceRequest()->Succeed(); |
+ MakeIssueTokenRequestSucceed(); |
+ MakeRefreshTokenFetchSucceed(); |
+ |
+ EXPECT_EQ(GoogleServiceAuthError::NONE, error().state()); |
+ EXPECT_EQ(kManagedUserToken, token()); |
+} |
+ |
+TEST_F(ManagedUserRefreshTokenFetcherTest, ExpiredAccessToken) { |
+ StartFetching(); |
+ GetOAuth2TokenServiceRequest()->Succeed(); |
+ SetHttpError(GetIssueTokenRequest(), net::HTTP_UNAUTHORIZED); |
+ GetOAuth2TokenServiceRequest()->Succeed(); |
+ MakeIssueTokenRequestSucceed(); |
+ MakeRefreshTokenFetchSucceed(); |
+ |
+ EXPECT_EQ(GoogleServiceAuthError::NONE, error().state()); |
+ EXPECT_EQ(kManagedUserToken, token()); |
+} |
+ |
+TEST_F(ManagedUserRefreshTokenFetcherTest, ExpiredAccessTokenRetry) { |
+ // If we get a 401 error for the second time, we should give up instead of |
+ // retrying again. |
+ StartFetching(); |
+ GetOAuth2TokenServiceRequest()->Succeed(); |
+ SetHttpError(GetIssueTokenRequest(), net::HTTP_UNAUTHORIZED); |
+ GetOAuth2TokenServiceRequest()->Succeed(); |
+ SetHttpError(GetIssueTokenRequest(), net::HTTP_UNAUTHORIZED); |
+ |
+ EXPECT_EQ(GoogleServiceAuthError::CONNECTION_FAILED, error().state()); |
+ EXPECT_EQ(net::ERR_FAILED, error().network_error()); |
+ EXPECT_EQ(std::string(), token()); |
+} |
+ |
+TEST_F(ManagedUserRefreshTokenFetcherTest, MalformedIssueTokenResponse) { |
+ StartFetching(); |
+ GetOAuth2TokenServiceRequest()->Succeed(); |
+ SendResponse(GetIssueTokenRequest(), "choke"); |
+ |
+ EXPECT_EQ(GoogleServiceAuthError::CONNECTION_FAILED, error().state()); |
+ EXPECT_EQ(net::ERR_INVALID_RESPONSE, error().network_error()); |
+ EXPECT_EQ(std::string(), token()); |
+} |
+ |
+TEST_F(ManagedUserRefreshTokenFetcherTest, FetchAccessTokenFailure) { |
+ StartFetching(); |
+ GetOAuth2TokenServiceRequest()->Fail( |
+ GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS); |
+ |
+ EXPECT_EQ(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS, error().state()); |
+ EXPECT_EQ(std::string(), token()); |
+} |
+ |
+TEST_F(ManagedUserRefreshTokenFetcherTest, IssueTokenNetworkError) { |
+ StartFetching(); |
+ GetOAuth2TokenServiceRequest()->Succeed(); |
+ SetNetworkError(GetIssueTokenRequest(), net::ERR_SSL_PROTOCOL_ERROR); |
+ |
+ EXPECT_EQ(GoogleServiceAuthError::CONNECTION_FAILED, error().state()); |
+ EXPECT_EQ(net::ERR_SSL_PROTOCOL_ERROR, error().network_error()); |
+ EXPECT_EQ(std::string(), token()); |
+} |
+ |
+TEST_F(ManagedUserRefreshTokenFetcherTest, FetchRefreshTokenNetworkError) { |
+ StartFetching(); |
+ GetOAuth2TokenServiceRequest()->Succeed(); |
+ MakeIssueTokenRequestSucceed(); |
+ SetNetworkError(GetRefreshTokenRequest(), net::ERR_CONNECTION_REFUSED); |
+ EXPECT_EQ(GoogleServiceAuthError::NONE, error().state()); |
+ SetNetworkError(GetRefreshTokenRequest(), net::ERR_CONNECTION_REFUSED); |
+ |
+ EXPECT_EQ(GoogleServiceAuthError::CONNECTION_FAILED, error().state()); |
+ EXPECT_EQ(net::ERR_FAILED, error().network_error()); |
+ EXPECT_EQ(std::string(), token()); |
+} |
+ |
+TEST_F(ManagedUserRefreshTokenFetcherTest, |
+ FetchRefreshTokenTransientNetworkError) { |
+ StartFetching(); |
+ GetOAuth2TokenServiceRequest()->Succeed(); |
+ MakeIssueTokenRequestSucceed(); |
+ SetNetworkError(GetRefreshTokenRequest(), net::ERR_CONNECTION_REFUSED); |
+ |
+ EXPECT_EQ(GoogleServiceAuthError::NONE, error().state()); |
+ MakeRefreshTokenFetchSucceed(); |
+ |
+ EXPECT_EQ(GoogleServiceAuthError::NONE, error().state()); |
+ EXPECT_EQ(kManagedUserToken, token()); |
+} |
+ |
+TEST_F(ManagedUserRefreshTokenFetcherTest, FetchRefreshTokenBadRequest) { |
+ StartFetching(); |
+ GetOAuth2TokenServiceRequest()->Succeed(); |
+ MakeIssueTokenRequestSucceed(); |
+ SetHttpError(GetRefreshTokenRequest(), net::HTTP_BAD_REQUEST); |
+ |
+ EXPECT_EQ(GoogleServiceAuthError::CONNECTION_FAILED, error().state()); |
+ EXPECT_EQ(net::ERR_FAILED, error().network_error()); |
+ EXPECT_EQ(std::string(), token()); |
+} |
+ |
+TEST_F(ManagedUserRefreshTokenFetcherTest, CancelWhileFetchingAccessToken) { |
+ StartFetching(); |
+ Reset(); |
+ |
+ EXPECT_EQ(GoogleServiceAuthError::NONE, error().state()); |
+ EXPECT_EQ(std::string(), token()); |
+} |
+ |
+TEST_F(ManagedUserRefreshTokenFetcherTest, CancelWhileCallingIssueToken) { |
+ StartFetching(); |
+ GetOAuth2TokenServiceRequest()->Succeed(); |
+ Reset(); |
+ |
+ EXPECT_EQ(GoogleServiceAuthError::NONE, error().state()); |
+ EXPECT_EQ(std::string(), token()); |
+} |
+ |
+TEST_F(ManagedUserRefreshTokenFetcherTest, CancelWhileFetchingRefreshToken) { |
+ StartFetching(); |
+ GetOAuth2TokenServiceRequest()->Succeed(); |
+ MakeIssueTokenRequestSucceed(); |
+ Reset(); |
+ |
+ EXPECT_EQ(GoogleServiceAuthError::NONE, error().state()); |
+ EXPECT_EQ(std::string(), token()); |
+} |