| // 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 <stddef.h> |
| |
| #include <string> |
| |
| #include "base/message_loop/message_loop.h" |
| #include "base/run_loop.h" |
| #include "base/stl_util.h" |
| #include "google_apis/gaia/fake_oauth2_token_service_delegate.h" |
| #include "google_apis/gaia/gaia_constants.h" |
| #include "google_apis/gaia/gaia_urls.h" |
| #include "google_apis/gaia/google_service_auth_error.h" |
| #include "google_apis/gaia/oauth2_access_token_consumer.h" |
| #include "google_apis/gaia/oauth2_access_token_fetcher_immediate_error.h" |
| #include "google_apis/gaia/oauth2_access_token_fetcher_impl.h" |
| #include "google_apis/gaia/oauth2_token_service.h" |
| #include "google_apis/gaia/oauth2_token_service_test_util.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 "net/url_request/url_request_test_util.h" |
| #include "services/network/test/test_utils.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| // A testing consumer that retries on error. |
| class RetryingTestingOAuth2TokenServiceConsumer |
| : public TestingOAuth2TokenServiceConsumer { |
| public: |
| RetryingTestingOAuth2TokenServiceConsumer( |
| OAuth2TokenService* oauth2_service, |
| const std::string& account_id) |
| : oauth2_service_(oauth2_service), |
| account_id_(account_id) {} |
| ~RetryingTestingOAuth2TokenServiceConsumer() override {} |
| |
| void OnGetTokenFailure(const OAuth2TokenService::Request* request, |
| const GoogleServiceAuthError& error) override { |
| if (retry_counter_ <= 0) |
| return; |
| retry_counter_--; |
| TestingOAuth2TokenServiceConsumer::OnGetTokenFailure(request, error); |
| request_ = oauth2_service_->StartRequest( |
| account_id_, OAuth2TokenService::ScopeSet(), this); |
| } |
| |
| int retry_counter_ = 2; |
| OAuth2TokenService* oauth2_service_; |
| std::string account_id_; |
| std::unique_ptr<OAuth2TokenService::Request> request_; |
| }; |
| |
| class FakeOAuth2TokenServiceObserver : public OAuth2TokenService::Observer { |
| public: |
| MOCK_METHOD2(OnAuthErrorChanged, |
| void(const std::string&, const GoogleServiceAuthError&)); |
| }; |
| |
| class TestOAuth2TokenService : public OAuth2TokenService { |
| public: |
| explicit TestOAuth2TokenService( |
| std::unique_ptr<FakeOAuth2TokenServiceDelegate> delegate) |
| : OAuth2TokenService(std::move(delegate)) {} |
| |
| void CancelAllRequestsForTest() { CancelAllRequests(); } |
| |
| void CancelRequestsForAccountForTest(const std::string& account_id) { |
| CancelRequestsForAccount(account_id); |
| } |
| |
| FakeOAuth2TokenServiceDelegate* GetFakeOAuth2TokenServiceDelegate() { |
| return static_cast<FakeOAuth2TokenServiceDelegate*>(GetDelegate()); |
| } |
| }; |
| |
| // This class fakes the behaviour of a MutableProfileOAuth2TokenServiceDelegate |
| // used on Desktop. |
| class FakeOAuth2TokenServiceDelegateDesktop |
| : public FakeOAuth2TokenServiceDelegate { |
| std::string GetTokenForMultilogin( |
| const std::string& account_id) const override { |
| if (GetAuthError(account_id) == GoogleServiceAuthError::AuthErrorNone()) |
| return GetRefreshToken(account_id); |
| return std::string(); |
| } |
| |
| OAuth2AccessTokenFetcher* CreateAccessTokenFetcher( |
| const std::string& account_id, |
| scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, |
| OAuth2AccessTokenConsumer* consumer) override { |
| if (GetAuthError(account_id).IsPersistentError()) { |
| return new OAuth2AccessTokenFetcherImmediateError( |
| consumer, GetAuthError(account_id)); |
| } |
| return FakeOAuth2TokenServiceDelegate::CreateAccessTokenFetcher( |
| account_id, url_loader_factory, consumer); |
| } |
| void InvalidateTokenForMultilogin( |
| const std::string& failed_account) override { |
| UpdateAuthError(failed_account, |
| GoogleServiceAuthError( |
| GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS)); |
| } |
| }; |
| |
| class OAuth2TokenServiceTest : public testing::Test { |
| public: |
| void SetUp() override { |
| auto delegate = std::make_unique<FakeOAuth2TokenServiceDelegate>(); |
| test_url_loader_factory_ = delegate->test_url_loader_factory(); |
| oauth2_service_ = |
| std::make_unique<TestOAuth2TokenService>(std::move(delegate)); |
| account_id_ = "test_user@gmail.com"; |
| } |
| |
| void TearDown() override { |
| // Makes sure that all the clean up tasks are run. |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| void SimulateOAuthTokenResponse(const std::string& token, |
| net::HttpStatusCode status = net::HTTP_OK) { |
| test_url_loader_factory_->AddResponse( |
| GaiaUrls::GetInstance()->oauth2_token_url().spec(), token, status); |
| } |
| |
| protected: |
| base::MessageLoopForIO message_loop_; // net:: stuff needs IO message loop. |
| network::TestURLLoaderFactory* test_url_loader_factory_ = nullptr; |
| std::unique_ptr<TestOAuth2TokenService> oauth2_service_; |
| std::string account_id_; |
| TestingOAuth2TokenServiceConsumer consumer_; |
| }; |
| |
| TEST_F(OAuth2TokenServiceTest, NoOAuth2RefreshToken) { |
| std::unique_ptr<OAuth2TokenService::Request> request( |
| oauth2_service_->StartRequest(account_id_, OAuth2TokenService::ScopeSet(), |
| &consumer_)); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_EQ(0, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(1, consumer_.number_of_errors_); |
| } |
| |
| TEST_F(OAuth2TokenServiceTest, FailureShouldNotRetry) { |
| oauth2_service_->GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials( |
| account_id_, "refreshToken"); |
| std::unique_ptr<OAuth2TokenService::Request> request( |
| oauth2_service_->StartRequest(account_id_, OAuth2TokenService::ScopeSet(), |
| &consumer_)); |
| |
| EXPECT_EQ(0, consumer_.number_of_successful_tokens_); |
| SimulateOAuthTokenResponse("", net::HTTP_UNAUTHORIZED); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_EQ(0, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(1, consumer_.number_of_errors_); |
| EXPECT_EQ(0, test_url_loader_factory_->NumPending()); |
| } |
| |
| TEST_F(OAuth2TokenServiceTest, SuccessWithoutCaching) { |
| oauth2_service_->GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials( |
| account_id_, "refreshToken"); |
| std::unique_ptr<OAuth2TokenService::Request> request( |
| oauth2_service_->StartRequest(account_id_, OAuth2TokenService::ScopeSet(), |
| &consumer_)); |
| EXPECT_EQ(0, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| |
| SimulateOAuthTokenResponse(GetValidTokenResponse("token", 3600)); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_EQ(1, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| EXPECT_EQ("token", consumer_.last_token_); |
| } |
| |
| TEST_F(OAuth2TokenServiceTest, SuccessWithCaching) { |
| OAuth2TokenService::ScopeSet scopes1; |
| scopes1.insert("s1"); |
| scopes1.insert("s2"); |
| OAuth2TokenService::ScopeSet scopes1_same; |
| scopes1_same.insert("s2"); |
| scopes1_same.insert("s1"); |
| OAuth2TokenService::ScopeSet scopes2; |
| scopes2.insert("s3"); |
| |
| oauth2_service_->GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials( |
| account_id_, "refreshToken"); |
| |
| // First request. |
| SimulateOAuthTokenResponse(GetValidTokenResponse("token", 3600)); |
| std::unique_ptr<OAuth2TokenService::Request> request( |
| oauth2_service_->StartRequest(account_id_, scopes1, &consumer_)); |
| EXPECT_EQ(0, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_EQ(1, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| EXPECT_EQ("token", consumer_.last_token_); |
| |
| // Second request to the same set of scopes, should return the same token |
| // without needing a network request. |
| std::unique_ptr<OAuth2TokenService::Request> request2( |
| oauth2_service_->StartRequest(account_id_, scopes1_same, &consumer_)); |
| base::RunLoop().RunUntilIdle(); |
| |
| // No new network fetcher. |
| EXPECT_EQ(2, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| EXPECT_EQ("token", consumer_.last_token_); |
| |
| // Third request to a new set of scopes, should return another token. |
| SimulateOAuthTokenResponse(GetValidTokenResponse("token2", 3600)); |
| std::unique_ptr<OAuth2TokenService::Request> request3( |
| oauth2_service_->StartRequest(account_id_, scopes2, &consumer_)); |
| EXPECT_EQ(2, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_EQ(3, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| EXPECT_EQ("token2", consumer_.last_token_); |
| } |
| |
| TEST_F(OAuth2TokenServiceTest, SuccessAndExpirationAndFailure) { |
| oauth2_service_->GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials( |
| account_id_, "refreshToken"); |
| |
| // First request. |
| SimulateOAuthTokenResponse(GetValidTokenResponse("token", 0)); |
| std::unique_ptr<OAuth2TokenService::Request> request( |
| oauth2_service_->StartRequest(account_id_, OAuth2TokenService::ScopeSet(), |
| &consumer_)); |
| EXPECT_EQ(0, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_EQ(1, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| EXPECT_EQ("token", consumer_.last_token_); |
| |
| // Second request must try to access the network as the token has expired. |
| SimulateOAuthTokenResponse("", net::HTTP_UNAUTHORIZED); // Network failure. |
| std::unique_ptr<OAuth2TokenService::Request> request2( |
| oauth2_service_->StartRequest(account_id_, OAuth2TokenService::ScopeSet(), |
| &consumer_)); |
| EXPECT_EQ(1, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_EQ(1, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(1, consumer_.number_of_errors_); |
| } |
| |
| TEST_F(OAuth2TokenServiceTest, SuccessAndExpirationAndSuccess) { |
| oauth2_service_->GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials( |
| account_id_, "refreshToken"); |
| |
| // First request. |
| SimulateOAuthTokenResponse(GetValidTokenResponse("token", 0)); |
| std::unique_ptr<OAuth2TokenService::Request> request( |
| oauth2_service_->StartRequest(account_id_, OAuth2TokenService::ScopeSet(), |
| &consumer_)); |
| EXPECT_EQ(0, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(1, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| EXPECT_EQ("token", consumer_.last_token_); |
| |
| // Second request must try to access the network as the token has expired. |
| SimulateOAuthTokenResponse(GetValidTokenResponse("another token", 0)); |
| std::unique_ptr<OAuth2TokenService::Request> request2( |
| oauth2_service_->StartRequest(account_id_, OAuth2TokenService::ScopeSet(), |
| &consumer_)); |
| EXPECT_EQ(1, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(2, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| EXPECT_EQ("another token", consumer_.last_token_); |
| } |
| |
| TEST_F(OAuth2TokenServiceTest, RequestDeletedBeforeCompletion) { |
| oauth2_service_->GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials( |
| account_id_, "refreshToken"); |
| |
| std::unique_ptr<OAuth2TokenService::Request> request( |
| oauth2_service_->StartRequest(account_id_, OAuth2TokenService::ScopeSet(), |
| &consumer_)); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(0, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| EXPECT_EQ(1, test_url_loader_factory_->NumPending()); |
| |
| request.reset(); |
| |
| SimulateOAuthTokenResponse(GetValidTokenResponse("token", 3600)); |
| |
| EXPECT_EQ(0, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| } |
| |
| TEST_F(OAuth2TokenServiceTest, RequestDeletedAfterCompletion) { |
| oauth2_service_->GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials( |
| account_id_, "refreshToken"); |
| |
| SimulateOAuthTokenResponse(GetValidTokenResponse("token", 3600)); |
| std::unique_ptr<OAuth2TokenService::Request> request( |
| oauth2_service_->StartRequest(account_id_, OAuth2TokenService::ScopeSet(), |
| &consumer_)); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(1, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| EXPECT_EQ("token", consumer_.last_token_); |
| |
| request.reset(); |
| |
| EXPECT_EQ(1, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| EXPECT_EQ("token", consumer_.last_token_); |
| } |
| |
| TEST_F(OAuth2TokenServiceTest, MultipleRequestsForTheSameScopesWithOneDeleted) { |
| oauth2_service_->GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials( |
| account_id_, "refreshToken"); |
| |
| std::unique_ptr<OAuth2TokenService::Request> request( |
| oauth2_service_->StartRequest(account_id_, OAuth2TokenService::ScopeSet(), |
| &consumer_)); |
| base::RunLoop().RunUntilIdle(); |
| std::unique_ptr<OAuth2TokenService::Request> request2( |
| oauth2_service_->StartRequest(account_id_, OAuth2TokenService::ScopeSet(), |
| &consumer_)); |
| base::RunLoop().RunUntilIdle(); |
| |
| request.reset(); |
| |
| SimulateOAuthTokenResponse(GetValidTokenResponse("token", 3600)); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_EQ(1, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| } |
| |
| TEST_F(OAuth2TokenServiceTest, ClearedRefreshTokenFailsSubsequentRequests) { |
| // We have a valid refresh token; the first request is successful. |
| oauth2_service_->GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials( |
| account_id_, "refreshToken"); |
| std::unique_ptr<OAuth2TokenService::Request> request( |
| oauth2_service_->StartRequest(account_id_, OAuth2TokenService::ScopeSet(), |
| &consumer_)); |
| SimulateOAuthTokenResponse(GetValidTokenResponse("token", 3600)); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(1, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| EXPECT_EQ("token", consumer_.last_token_); |
| |
| // The refresh token is no longer available; subsequent requests fail. |
| oauth2_service_->GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials( |
| account_id_, ""); |
| request = oauth2_service_->StartRequest(account_id_, |
| OAuth2TokenService::ScopeSet(), &consumer_); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(1, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(1, consumer_.number_of_errors_); |
| } |
| |
| TEST_F(OAuth2TokenServiceTest, |
| ChangedRefreshTokenDoesNotAffectInFlightRequests) { |
| oauth2_service_->GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials( |
| account_id_, "first refreshToken"); |
| OAuth2TokenService::ScopeSet scopes; |
| scopes.insert("s1"); |
| scopes.insert("s2"); |
| OAuth2TokenService::ScopeSet scopes1; |
| scopes.insert("s3"); |
| scopes.insert("s4"); |
| |
| std::unique_ptr<OAuth2TokenService::Request> request( |
| oauth2_service_->StartRequest(account_id_, scopes, &consumer_)); |
| base::RunLoop().RunUntilIdle(); |
| ASSERT_EQ(1, test_url_loader_factory_->NumPending()); |
| |
| // Note |request| is still pending when the refresh token changes. |
| oauth2_service_->GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials( |
| account_id_, "second refreshToken"); |
| |
| // A 2nd request (using the new refresh token) that occurs and completes |
| // while the 1st request is in flight is successful. |
| TestingOAuth2TokenServiceConsumer consumer2; |
| std::unique_ptr<OAuth2TokenService::Request> request2( |
| oauth2_service_->StartRequest(account_id_, scopes1, &consumer2)); |
| base::RunLoop().RunUntilIdle(); |
| ASSERT_EQ(2, test_url_loader_factory_->NumPending()); |
| |
| network::URLLoaderCompletionStatus ok_status(net::OK); |
| network::ResourceResponseHead response_head = |
| network::CreateResourceResponseHead(net::HTTP_OK); |
| EXPECT_TRUE(test_url_loader_factory_->SimulateResponseForPendingRequest( |
| GaiaUrls::GetInstance()->oauth2_token_url(), ok_status, response_head, |
| GetValidTokenResponse("second token", 3600), |
| network::TestURLLoaderFactory::kMostRecentMatch)); |
| EXPECT_EQ(1, consumer2.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer2.number_of_errors_); |
| EXPECT_EQ("second token", consumer2.last_token_); |
| |
| EXPECT_TRUE(test_url_loader_factory_->SimulateResponseForPendingRequest( |
| GaiaUrls::GetInstance()->oauth2_token_url(), ok_status, response_head, |
| GetValidTokenResponse("first token", 3600), |
| network::TestURLLoaderFactory::kMostRecentMatch)); |
| EXPECT_EQ(1, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| EXPECT_EQ("first token", consumer_.last_token_); |
| } |
| |
| TEST_F(OAuth2TokenServiceTest, StartRequestForMultiloginDesktop) { |
| class MockOAuth2AccessTokenConsumer |
| : public TestingOAuth2TokenServiceConsumer { |
| public: |
| MockOAuth2AccessTokenConsumer() = default; |
| ~MockOAuth2AccessTokenConsumer() = default; |
| |
| MOCK_METHOD2( |
| OnGetTokenSuccess, |
| void(const OAuth2TokenService::Request* request, |
| const OAuth2AccessTokenConsumer::TokenResponse& token_response)); |
| |
| MOCK_METHOD2(OnGetTokenFailure, |
| void(const OAuth2TokenService::Request* request, |
| const GoogleServiceAuthError& error)); |
| |
| DISALLOW_COPY_AND_ASSIGN(MockOAuth2AccessTokenConsumer); |
| }; |
| TestOAuth2TokenService token_service( |
| std::make_unique<FakeOAuth2TokenServiceDelegateDesktop>()); |
| |
| token_service.GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials( |
| account_id_, "refreshToken"); |
| const std::string account_id_2 = "account_id_2"; |
| token_service.GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials( |
| account_id_2, "refreshToken"); |
| token_service.GetFakeOAuth2TokenServiceDelegate()->UpdateAuthError( |
| account_id_2, |
| GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS)); |
| |
| MockOAuth2AccessTokenConsumer consumer; |
| |
| EXPECT_CALL(consumer, OnGetTokenSuccess(::testing::_, ::testing::_)).Times(1); |
| EXPECT_CALL( |
| consumer, |
| OnGetTokenFailure( |
| ::testing::_, |
| GoogleServiceAuthError(GoogleServiceAuthError::USER_NOT_SIGNED_UP))) |
| .Times(1); |
| EXPECT_CALL( |
| consumer, |
| OnGetTokenFailure(::testing::_, |
| GoogleServiceAuthError( |
| GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS))) |
| .Times(1); |
| |
| std::unique_ptr<OAuth2TokenService::Request> request1( |
| token_service.StartRequestForMultilogin(account_id_, &consumer)); |
| std::unique_ptr<OAuth2TokenService::Request> request2( |
| token_service.StartRequestForMultilogin(account_id_2, &consumer)); |
| std::unique_ptr<OAuth2TokenService::Request> request3( |
| token_service.StartRequestForMultilogin("unknown_account", &consumer)); |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| TEST_F(OAuth2TokenServiceTest, StartRequestForMultiloginMobile) { |
| oauth2_service_->GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials( |
| account_id_, "refreshToken"); |
| |
| std::unique_ptr<OAuth2TokenService::Request> request( |
| oauth2_service_->StartRequestForMultilogin(account_id_, &consumer_)); |
| |
| base::RunLoop().RunUntilIdle(); |
| network::URLLoaderCompletionStatus ok_status(net::OK); |
| network::ResourceResponseHead response_head = |
| network::CreateResourceResponseHead(net::HTTP_OK); |
| EXPECT_TRUE(test_url_loader_factory_->SimulateResponseForPendingRequest( |
| GaiaUrls::GetInstance()->oauth2_token_url(), ok_status, response_head, |
| GetValidTokenResponse("second token", 3600), |
| network::TestURLLoaderFactory::kMostRecentMatch)); |
| EXPECT_EQ(1, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| } |
| |
| TEST_F(OAuth2TokenServiceTest, ServiceShutDownBeforeFetchComplete) { |
| oauth2_service_->GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials( |
| account_id_, "refreshToken"); |
| std::unique_ptr<OAuth2TokenService::Request> request( |
| oauth2_service_->StartRequest(account_id_, OAuth2TokenService::ScopeSet(), |
| &consumer_)); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(0, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| |
| // The destructor should cancel all in-flight fetchers. |
| oauth2_service_.reset(NULL); |
| |
| EXPECT_EQ(0, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(1, consumer_.number_of_errors_); |
| } |
| |
| TEST_F(OAuth2TokenServiceTest, RetryingConsumer) { |
| oauth2_service_->GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials( |
| account_id_, "refreshToken"); |
| RetryingTestingOAuth2TokenServiceConsumer consumer(oauth2_service_.get(), |
| account_id_); |
| std::unique_ptr<OAuth2TokenService::Request> request( |
| oauth2_service_->StartRequest(account_id_, OAuth2TokenService::ScopeSet(), |
| &consumer)); |
| EXPECT_EQ(0, consumer.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer.number_of_errors_); |
| |
| SimulateOAuthTokenResponse("", net::HTTP_UNAUTHORIZED); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(0, consumer.number_of_successful_tokens_); |
| EXPECT_EQ(2, consumer.number_of_errors_); |
| } |
| |
| TEST_F(OAuth2TokenServiceTest, InvalidateTokensForMultiloginDesktop) { |
| auto delegate = std::make_unique<FakeOAuth2TokenServiceDelegateDesktop>(); |
| TestOAuth2TokenService token_service(std::move(delegate)); |
| FakeOAuth2TokenServiceObserver observer; |
| token_service.GetFakeOAuth2TokenServiceDelegate()->AddObserver(&observer); |
| EXPECT_CALL( |
| observer, |
| OnAuthErrorChanged(account_id_, |
| GoogleServiceAuthError( |
| GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS))) |
| .Times(1); |
| |
| token_service.GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials( |
| account_id_, "refreshToken"); |
| const std::string account_id_2 = "account_id_2"; |
| token_service.GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials( |
| account_id_2, "refreshToken2"); |
| token_service.InvalidateTokenForMultilogin(account_id_, "refreshToken"); |
| // Check that refresh tokens for failed accounts are set in error. |
| EXPECT_EQ(token_service.GetFakeOAuth2TokenServiceDelegate() |
| ->GetAuthError(account_id_) |
| .state(), |
| GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS); |
| EXPECT_EQ(token_service.GetFakeOAuth2TokenServiceDelegate() |
| ->GetAuthError(account_id_2) |
| .state(), |
| GoogleServiceAuthError::NONE); |
| |
| token_service.GetFakeOAuth2TokenServiceDelegate()->RemoveObserver(&observer); |
| } |
| |
| TEST_F(OAuth2TokenServiceTest, InvalidateTokensForMultiloginMobile) { |
| FakeOAuth2TokenServiceObserver observer; |
| oauth2_service_->GetFakeOAuth2TokenServiceDelegate()->AddObserver(&observer); |
| EXPECT_CALL( |
| observer, |
| OnAuthErrorChanged(account_id_, |
| GoogleServiceAuthError( |
| GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS))) |
| .Times(0); |
| |
| oauth2_service_->GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials( |
| account_id_, "refreshToken"); |
| const std::string account_id_2 = "account_id_2"; |
| oauth2_service_->GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials( |
| account_id_2, "refreshToken2"); |
| ; |
| oauth2_service_->InvalidateTokenForMultilogin(account_id_, "refreshToken"); |
| // Check that refresh tokens are not affected. |
| EXPECT_EQ(oauth2_service_->GetFakeOAuth2TokenServiceDelegate() |
| ->GetAuthError(account_id_) |
| .state(), |
| GoogleServiceAuthError::NONE); |
| EXPECT_EQ(oauth2_service_->GetFakeOAuth2TokenServiceDelegate() |
| ->GetAuthError(account_id_2) |
| .state(), |
| GoogleServiceAuthError::NONE); |
| |
| oauth2_service_->GetFakeOAuth2TokenServiceDelegate()->RemoveObserver( |
| &observer); |
| } |
| |
| TEST_F(OAuth2TokenServiceTest, InvalidateToken) { |
| OAuth2TokenService::ScopeSet scopes; |
| oauth2_service_->GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials( |
| account_id_, "refreshToken"); |
| |
| // First request. |
| std::unique_ptr<OAuth2TokenService::Request> request( |
| oauth2_service_->StartRequest(account_id_, scopes, &consumer_)); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_EQ(0, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| |
| SimulateOAuthTokenResponse(GetValidTokenResponse("token", 3600)); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_EQ(1, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| EXPECT_EQ("token", consumer_.last_token_); |
| |
| // Second request, should return the same token without needing a network |
| // request. |
| std::unique_ptr<OAuth2TokenService::Request> request2( |
| oauth2_service_->StartRequest(account_id_, scopes, &consumer_)); |
| base::RunLoop().RunUntilIdle(); |
| |
| // No new network fetcher. |
| EXPECT_EQ(2, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| EXPECT_EQ("token", consumer_.last_token_); |
| |
| // Clear previous response so the token request will be pending and we can |
| // simulate a response after it started. |
| test_url_loader_factory_->ClearResponses(); |
| |
| // Invalidating the token should return a new token on the next request. |
| oauth2_service_->InvalidateAccessToken(account_id_, scopes, |
| consumer_.last_token_); |
| std::unique_ptr<OAuth2TokenService::Request> request3( |
| oauth2_service_->StartRequest(account_id_, scopes, &consumer_)); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_EQ(2, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| |
| SimulateOAuthTokenResponse(GetValidTokenResponse("token2", 3600)); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_EQ(3, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| EXPECT_EQ("token2", consumer_.last_token_); |
| } |
| |
| TEST_F(OAuth2TokenServiceTest, CancelAllRequests) { |
| oauth2_service_->GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials( |
| account_id_, "refreshToken"); |
| std::unique_ptr<OAuth2TokenService::Request> request( |
| oauth2_service_->StartRequest(account_id_, OAuth2TokenService::ScopeSet(), |
| &consumer_)); |
| |
| oauth2_service_->GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials( |
| "account_id_2", "refreshToken2"); |
| std::unique_ptr<OAuth2TokenService::Request> request2( |
| oauth2_service_->StartRequest(account_id_, OAuth2TokenService::ScopeSet(), |
| &consumer_)); |
| |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(0, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| |
| oauth2_service_->CancelAllRequestsForTest(); |
| |
| EXPECT_EQ(0, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(2, consumer_.number_of_errors_); |
| } |
| |
| TEST_F(OAuth2TokenServiceTest, CancelRequestsForAccount) { |
| OAuth2TokenService::ScopeSet scope_set_1; |
| scope_set_1.insert("scope1"); |
| scope_set_1.insert("scope2"); |
| OAuth2TokenService::ScopeSet scope_set_2(scope_set_1.begin(), |
| scope_set_1.end()); |
| scope_set_2.insert("scope3"); |
| |
| oauth2_service_->GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials( |
| account_id_, "refreshToken"); |
| std::unique_ptr<OAuth2TokenService::Request> request1( |
| oauth2_service_->StartRequest(account_id_, scope_set_1, &consumer_)); |
| std::unique_ptr<OAuth2TokenService::Request> request2( |
| oauth2_service_->StartRequest(account_id_, scope_set_2, &consumer_)); |
| |
| std::string account_id_2("account_id_2"); |
| oauth2_service_->GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials( |
| account_id_2, "refreshToken2"); |
| std::unique_ptr<OAuth2TokenService::Request> request3( |
| oauth2_service_->StartRequest(account_id_2, scope_set_1, &consumer_)); |
| |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(0, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| |
| oauth2_service_->CancelRequestsForAccountForTest(account_id_); |
| |
| EXPECT_EQ(0, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(2, consumer_.number_of_errors_); |
| |
| oauth2_service_->CancelRequestsForAccountForTest(account_id_2); |
| |
| EXPECT_EQ(0, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(3, consumer_.number_of_errors_); |
| } |
| |
| TEST_F(OAuth2TokenServiceTest, SameScopesRequestedForDifferentClients) { |
| std::string client_id_1("client1"); |
| std::string client_secret_1("secret1"); |
| std::string client_id_2("client2"); |
| std::string client_secret_2("secret2"); |
| std::set<std::string> scope_set; |
| scope_set.insert("scope1"); |
| scope_set.insert("scope2"); |
| |
| std::string refresh_token("refreshToken"); |
| oauth2_service_->GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials( |
| account_id_, refresh_token); |
| |
| std::unique_ptr<OAuth2TokenService::Request> request1( |
| oauth2_service_->StartRequestForClient( |
| account_id_, client_id_1, client_secret_1, scope_set, &consumer_)); |
| std::unique_ptr<OAuth2TokenService::Request> request2( |
| oauth2_service_->StartRequestForClient( |
| account_id_, client_id_2, client_secret_2, scope_set, &consumer_)); |
| // Start a request that should be duplicate of |request1|. |
| std::unique_ptr<OAuth2TokenService::Request> request3( |
| oauth2_service_->StartRequestForClient( |
| account_id_, client_id_1, client_secret_1, scope_set, &consumer_)); |
| base::RunLoop().RunUntilIdle(); |
| |
| ASSERT_EQ(2U, |
| oauth2_service_->GetNumPendingRequestsForTesting( |
| client_id_1, |
| account_id_, |
| scope_set)); |
| ASSERT_EQ(1U, |
| oauth2_service_->GetNumPendingRequestsForTesting( |
| client_id_2, |
| account_id_, |
| scope_set)); |
| } |
| |
| TEST_F(OAuth2TokenServiceTest, RequestParametersOrderTest) { |
| OAuth2TokenService::ScopeSet set_0; |
| OAuth2TokenService::ScopeSet set_1; |
| set_1.insert("1"); |
| |
| OAuth2TokenService::RequestParameters params[] = { |
| OAuth2TokenService::RequestParameters("0", "0", set_0), |
| OAuth2TokenService::RequestParameters("0", "0", set_1), |
| OAuth2TokenService::RequestParameters("0", "1", set_0), |
| OAuth2TokenService::RequestParameters("0", "1", set_1), |
| OAuth2TokenService::RequestParameters("1", "0", set_0), |
| OAuth2TokenService::RequestParameters("1", "0", set_1), |
| OAuth2TokenService::RequestParameters("1", "1", set_0), |
| OAuth2TokenService::RequestParameters("1", "1", set_1), |
| }; |
| |
| for (size_t i = 0; i < base::size(params); i++) { |
| for (size_t j = 0; j < base::size(params); j++) { |
| if (i == j) { |
| EXPECT_FALSE(params[i] < params[j]) << " i=" << i << ", j=" << j; |
| EXPECT_FALSE(params[j] < params[i]) << " i=" << i << ", j=" << j; |
| } else if (i < j) { |
| EXPECT_TRUE(params[i] < params[j]) << " i=" << i << ", j=" << j; |
| EXPECT_FALSE(params[j] < params[i]) << " i=" << i << ", j=" << j; |
| } else { |
| EXPECT_TRUE(params[j] < params[i]) << " i=" << i << ", j=" << j; |
| EXPECT_FALSE(params[i] < params[j]) << " i=" << i << ", j=" << j; |
| } |
| } |
| } |
| } |
| |
| TEST_F(OAuth2TokenServiceTest, UpdateClearsCache) { |
| std::string kEmail = "test@gmail.com"; |
| std::set<std::string> scope_list; |
| scope_list.insert("scope"); |
| oauth2_service_->GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials( |
| kEmail, "refreshToken"); |
| std::unique_ptr<OAuth2TokenService::Request> request( |
| oauth2_service_->StartRequest(kEmail, scope_list, &consumer_)); |
| SimulateOAuthTokenResponse(GetValidTokenResponse("token", 3600)); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_EQ(1, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| EXPECT_EQ("token", consumer_.last_token_); |
| EXPECT_EQ(1, (int)oauth2_service_->token_cache_.size()); |
| |
| oauth2_service_->ClearCache(); |
| |
| EXPECT_EQ(0, (int)oauth2_service_->token_cache_.size()); |
| oauth2_service_->GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials( |
| kEmail, "refreshToken"); |
| SimulateOAuthTokenResponse(GetValidTokenResponse("another token", 3600)); |
| request = oauth2_service_->StartRequest(kEmail, scope_list, &consumer_); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(2, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| EXPECT_EQ("another token", consumer_.last_token_); |
| EXPECT_EQ(1, (int)oauth2_service_->token_cache_.size()); |
| } |