| 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());
|
| +}
|
|
|