| // Copyright 2019 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 "google_apis/gaia/oauth2_access_token_manager.h" |
| |
| #include "base/memory/ref_counted.h" |
| #include "base/test/task_environment.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_fetcher_impl.h" |
| #include "google_apis/gaia/oauth2_access_token_manager_test_util.h" |
| #include "net/http/http_status_code.h" |
| #include "services/network/public/cpp/shared_url_loader_factory.h" |
| #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" |
| #include "services/network/test/test_url_loader_factory.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace { |
| |
| constexpr char kTestAccountId[] = "test_user@gmail.com"; |
| |
| class FakeOAuth2AccessTokenManagerDelegate |
| : public OAuth2AccessTokenManager::Delegate { |
| public: |
| FakeOAuth2AccessTokenManagerDelegate( |
| network::TestURLLoaderFactory* test_url_loader_factory) |
| : shared_factory_( |
| base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( |
| test_url_loader_factory)) {} |
| ~FakeOAuth2AccessTokenManagerDelegate() override = default; |
| |
| // OAuth2AccessTokenManager::Delegate: |
| std::unique_ptr<OAuth2AccessTokenFetcher> CreateAccessTokenFetcher( |
| const CoreAccountId& account_id, |
| scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, |
| OAuth2AccessTokenConsumer* consumer) override { |
| EXPECT_NE(account_ids_to_refresh_tokens_.find(account_id), |
| account_ids_to_refresh_tokens_.end()); |
| return std::make_unique<OAuth2AccessTokenFetcherImpl>( |
| consumer, url_loader_factory, |
| account_ids_to_refresh_tokens_[account_id]); |
| } |
| |
| bool HasRefreshToken(const CoreAccountId& account_id) const override { |
| return account_ids_to_refresh_tokens_.find(account_id) != |
| account_ids_to_refresh_tokens_.end(); |
| } |
| |
| scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() |
| const override { |
| return shared_factory_; |
| } |
| |
| bool HandleAccessTokenFetch( |
| OAuth2AccessTokenManager::RequestImpl* request, |
| const CoreAccountId& account_id, |
| scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, |
| const std::string& client_id, |
| const std::string& client_secret, |
| const OAuth2AccessTokenManager::ScopeSet& scopes) override { |
| if (access_token_fetch_closure_) { |
| std::move(access_token_fetch_closure_).Run(); |
| return true; |
| } |
| return false; |
| } |
| |
| void OnAccessTokenInvalidated( |
| const CoreAccountId& account_id, |
| const std::string& client_id, |
| const OAuth2AccessTokenManager::ScopeSet& scopes, |
| const std::string& access_token) override { |
| if (!on_access_token_invalidated_callback_) |
| return; |
| |
| EXPECT_EQ(access_token_invalidated_account_id_, account_id); |
| EXPECT_EQ(access_token_invalidated_client_id_, client_id); |
| EXPECT_EQ(access_token_invalidated_scopes_, scopes); |
| EXPECT_EQ(access_token_invalidated_access_token_, access_token); |
| std::move(on_access_token_invalidated_callback_).Run(); |
| } |
| |
| void OnAccessTokenFetched(const CoreAccountId& account_id, |
| const GoogleServiceAuthError& error) override { |
| if (!access_token_fetched_callback_) |
| return; |
| |
| EXPECT_EQ(access_token_fetched_account_id_, account_id); |
| EXPECT_EQ(access_token_fetched_error_, error); |
| std::move(access_token_fetched_callback_).Run(); |
| } |
| |
| void AddAccount(CoreAccountId id, std::string refresh_token) { |
| account_ids_to_refresh_tokens_[id] = refresh_token; |
| } |
| |
| void SetAccessTokenHandleClosure(base::OnceClosure closure) { |
| access_token_fetch_closure_ = std::move(closure); |
| } |
| |
| void SetOnAccessTokenInvalidated( |
| const CoreAccountId& account_id, |
| const std::string& client_id, |
| const OAuth2AccessTokenManager::ScopeSet& scopes, |
| const std::string& access_token, |
| base::OnceClosure callback) { |
| access_token_invalidated_account_id_ = account_id; |
| access_token_invalidated_client_id_ = client_id; |
| access_token_invalidated_scopes_ = scopes; |
| access_token_invalidated_access_token_ = access_token; |
| on_access_token_invalidated_callback_ = std::move(callback); |
| } |
| |
| void SetOnAccessTokenFetched(const CoreAccountId& account_id, |
| const GoogleServiceAuthError& error, |
| base::OnceClosure callback) { |
| access_token_fetched_account_id_ = account_id; |
| access_token_fetched_error_ = error; |
| access_token_fetched_callback_ = std::move(callback); |
| } |
| |
| private: |
| scoped_refptr<network::SharedURLLoaderFactory> shared_factory_; |
| std::map<CoreAccountId, std::string> account_ids_to_refresh_tokens_; |
| base::OnceClosure access_token_fetch_closure_; |
| CoreAccountId access_token_invalidated_account_id_; |
| std::string access_token_invalidated_client_id_; |
| OAuth2AccessTokenManager::ScopeSet access_token_invalidated_scopes_; |
| std::string access_token_invalidated_access_token_; |
| base::OnceClosure on_access_token_invalidated_callback_; |
| CoreAccountId access_token_fetched_account_id_; |
| GoogleServiceAuthError access_token_fetched_error_; |
| base::OnceClosure access_token_fetched_callback_; |
| }; |
| |
| class FakeOAuth2AccessTokenManagerConsumer |
| : public TestingOAuth2AccessTokenManagerConsumer { |
| public: |
| FakeOAuth2AccessTokenManagerConsumer() = default; |
| ~FakeOAuth2AccessTokenManagerConsumer() override = default; |
| |
| // TestingOAuth2AccessTokenManagerConsumer overrides. |
| void OnGetTokenSuccess( |
| const OAuth2AccessTokenManager::Request* request, |
| const OAuth2AccessTokenConsumer::TokenResponse& token_response) override { |
| TestingOAuth2AccessTokenManagerConsumer::OnGetTokenSuccess(request, |
| token_response); |
| if (closure_) |
| std::move(closure_).Run(); |
| } |
| |
| void OnGetTokenFailure(const OAuth2AccessTokenManager::Request* request, |
| const GoogleServiceAuthError& error) override { |
| TestingOAuth2AccessTokenManagerConsumer::OnGetTokenFailure(request, error); |
| if (closure_) |
| std::move(closure_).Run(); |
| } |
| |
| void SetResponseCompletedClosure(base::OnceClosure closure) { |
| closure_ = std::move(closure); |
| } |
| |
| private: |
| base::OnceClosure closure_; |
| }; |
| |
| class DiagnosticsObserverForTesting |
| : public OAuth2AccessTokenManager::DiagnosticsObserver { |
| public: |
| // OAuth2AccessTokenManager::DiagnosticsObserver: |
| void OnAccessTokenRequested( |
| const CoreAccountId& account_id, |
| const std::string& consumer_id, |
| const OAuth2AccessTokenManager::ScopeSet& scopes) override { |
| if (!access_token_requested_callback_) |
| return; |
| EXPECT_EQ(access_token_requested_account_id_, account_id); |
| EXPECT_EQ(access_token_requested_consumer_id_, consumer_id); |
| EXPECT_EQ(access_token_requested_scopes_, scopes); |
| std::move(access_token_requested_callback_).Run(); |
| } |
| void OnFetchAccessTokenComplete( |
| const CoreAccountId& account_id, |
| const std::string& consumer_id, |
| const OAuth2AccessTokenManager::ScopeSet& scopes, |
| GoogleServiceAuthError error, |
| base::Time expiration_time) override { |
| if (!fetch_access_token_completed_callback_) |
| return; |
| EXPECT_EQ(fetch_access_token_completed_account_id_, account_id); |
| EXPECT_EQ(fetch_access_token_completed_consumer_id_, consumer_id); |
| EXPECT_EQ(fetch_access_token_completed_scopes_, scopes); |
| EXPECT_EQ(fetch_access_token_completed_error_, error); |
| std::move(fetch_access_token_completed_callback_).Run(); |
| } |
| void OnAccessTokenRemoved( |
| const CoreAccountId& account_id, |
| const OAuth2AccessTokenManager::ScopeSet& scopes) override { |
| if (!access_token_removed_callback_) |
| return; |
| auto iterator = access_token_removed_account_to_scopes_.find(account_id); |
| EXPECT_NE(iterator, access_token_removed_account_to_scopes_.end()); |
| EXPECT_EQ(iterator->second, scopes); |
| access_token_removed_account_to_scopes_.erase(iterator); |
| |
| if (access_token_removed_account_to_scopes_.empty()) |
| std::move(access_token_removed_callback_).Run(); |
| } |
| |
| void SetOnAccessTokenRequested( |
| const CoreAccountId& account_id, |
| const std::string& consumer_id, |
| const OAuth2AccessTokenManager::ScopeSet& scopes, |
| base::OnceClosure callback) { |
| access_token_requested_account_id_ = account_id; |
| access_token_requested_consumer_id_ = consumer_id; |
| access_token_requested_scopes_ = scopes; |
| access_token_requested_callback_ = std::move(callback); |
| } |
| void SetOnFetchAccessTokenComplete( |
| const CoreAccountId& account_id, |
| const std::string& consumer_id, |
| const OAuth2AccessTokenManager::ScopeSet& scopes, |
| GoogleServiceAuthError error, |
| base::OnceClosure callback) { |
| fetch_access_token_completed_account_id_ = account_id; |
| fetch_access_token_completed_consumer_id_ = consumer_id; |
| fetch_access_token_completed_scopes_ = scopes; |
| fetch_access_token_completed_error_ = error; |
| fetch_access_token_completed_callback_ = std::move(callback); |
| } |
| |
| typedef std::map<CoreAccountId, OAuth2AccessTokenManager::ScopeSet> |
| AccountToScopeSet; |
| // OnAccessTokenRemoved() can be invoked multiple times as part of a given |
| // test expectation (e.g., when clearing the cache of multiple tokens). To |
| // support this, this method takes in a map of account IDs to scopesets, and |
| // OnAccessTokenRemoved() invokes |callback| only once invocations of it have |
| // occurred for all of the (account_id, scopeset) pairs in |
| // |account_to_scopeset|. |
| void SetOnAccessTokenRemoved(const AccountToScopeSet& account_to_scopeset, |
| base::OnceClosure callback) { |
| access_token_removed_account_to_scopes_ = account_to_scopeset; |
| access_token_removed_callback_ = std::move(callback); |
| } |
| |
| private: |
| CoreAccountId access_token_requested_account_id_; |
| std::string access_token_requested_consumer_id_; |
| OAuth2AccessTokenManager::ScopeSet access_token_requested_scopes_; |
| base::OnceClosure access_token_requested_callback_; |
| CoreAccountId fetch_access_token_completed_account_id_; |
| std::string fetch_access_token_completed_consumer_id_; |
| OAuth2AccessTokenManager::ScopeSet fetch_access_token_completed_scopes_; |
| GoogleServiceAuthError fetch_access_token_completed_error_; |
| base::OnceClosure fetch_access_token_completed_callback_; |
| AccountToScopeSet access_token_removed_account_to_scopes_; |
| base::OnceClosure access_token_removed_callback_; |
| }; |
| |
| } // namespace |
| |
| // Any public API surfaces that are wrapped by ProfileOAuth2TokenService are |
| // unittested as part of the unittests of that class. |
| |
| class OAuth2AccessTokenManagerTest : public testing::Test { |
| public: |
| OAuth2AccessTokenManagerTest() |
| : delegate_(&test_url_loader_factory_), token_manager_(&delegate_) {} |
| |
| void SetUp() override { |
| account_id_ = CoreAccountId(kTestAccountId); |
| delegate_.AddAccount(account_id_, "fake_refresh_token"); |
| } |
| |
| void TearDown() override { |
| // Makes sure that all the clean up tasks are run. It's required because of |
| // cleaning up OAuth2AccessTokenManager::Fetcher on |
| // InformWaitingRequestsAndDelete(). |
| 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); |
| } |
| |
| void CreateRequestAndBlockUntilComplete( |
| const CoreAccountId& account, |
| const OAuth2AccessTokenManager::ScopeSet& scopeset) { |
| base::RunLoop run_loop; |
| consumer_.SetResponseCompletedClosure(run_loop.QuitClosure()); |
| std::unique_ptr<OAuth2AccessTokenManager::Request> request( |
| token_manager_.StartRequest(account, scopeset, &consumer_)); |
| run_loop.Run(); |
| } |
| |
| protected: |
| base::test::TaskEnvironment task_environment_; |
| CoreAccountId account_id_; |
| network::TestURLLoaderFactory test_url_loader_factory_; |
| FakeOAuth2AccessTokenManagerDelegate delegate_; |
| OAuth2AccessTokenManager token_manager_; |
| FakeOAuth2AccessTokenManagerConsumer consumer_; |
| }; |
| |
| // Test that StartRequest gets a response properly. |
| TEST_F(OAuth2AccessTokenManagerTest, StartRequest) { |
| base::RunLoop run_loop; |
| consumer_.SetResponseCompletedClosure(run_loop.QuitClosure()); |
| std::unique_ptr<OAuth2AccessTokenManager::Request> request( |
| token_manager_.StartRequest( |
| account_id_, OAuth2AccessTokenManager::ScopeSet(), &consumer_)); |
| SimulateOAuthTokenResponse(GetValidTokenResponse("token", 3600)); |
| run_loop.Run(); |
| |
| EXPECT_EQ(1, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| } |
| |
| // Test that CancelAllRequests triggers OnGetTokenFailure. |
| TEST_F(OAuth2AccessTokenManagerTest, CancelAllRequests) { |
| std::unique_ptr<OAuth2AccessTokenManager::Request> request( |
| token_manager_.StartRequest( |
| account_id_, OAuth2AccessTokenManager::ScopeSet(), &consumer_)); |
| const CoreAccountId account_id_2("account_id_2"); |
| delegate_.AddAccount(account_id_2, "refreshToken2"); |
| std::unique_ptr<OAuth2AccessTokenManager::Request> request2( |
| token_manager_.StartRequest( |
| account_id_2, OAuth2AccessTokenManager::ScopeSet(), &consumer_)); |
| |
| EXPECT_EQ(0, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| |
| token_manager_.CancelAllRequests(); |
| |
| EXPECT_EQ(0, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(2, consumer_.number_of_errors_); |
| } |
| |
| // Test that CancelRequestsForAccount cancels requests for the specific account. |
| TEST_F(OAuth2AccessTokenManagerTest, CancelRequestsForAccount) { |
| OAuth2AccessTokenManager::ScopeSet scope_set_1; |
| scope_set_1.insert("scope1"); |
| scope_set_1.insert("scope2"); |
| OAuth2AccessTokenManager::ScopeSet scope_set_2(scope_set_1.begin(), |
| scope_set_1.end()); |
| scope_set_2.insert("scope3"); |
| |
| std::unique_ptr<OAuth2AccessTokenManager::Request> request1( |
| token_manager_.StartRequest(account_id_, scope_set_1, &consumer_)); |
| std::unique_ptr<OAuth2AccessTokenManager::Request> request2( |
| token_manager_.StartRequest(account_id_, scope_set_2, &consumer_)); |
| |
| const CoreAccountId account_id_2("account_id_2"); |
| delegate_.AddAccount(account_id_2, "refreshToken2"); |
| std::unique_ptr<OAuth2AccessTokenManager::Request> request3( |
| token_manager_.StartRequest(account_id_2, scope_set_1, &consumer_)); |
| |
| EXPECT_EQ(0, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| |
| token_manager_.CancelRequestsForAccount(account_id_); |
| |
| EXPECT_EQ(0, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(2, consumer_.number_of_errors_); |
| |
| token_manager_.CancelRequestsForAccount(account_id_2); |
| |
| EXPECT_EQ(0, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(3, consumer_.number_of_errors_); |
| } |
| |
| // Test that StartRequest fetches a network request after ClearCache. |
| TEST_F(OAuth2AccessTokenManagerTest, ClearCache) { |
| base::RunLoop run_loop1; |
| consumer_.SetResponseCompletedClosure(run_loop1.QuitClosure()); |
| |
| std::set<std::string> scope_list; |
| scope_list.insert("scope"); |
| std::unique_ptr<OAuth2AccessTokenManager::Request> request( |
| token_manager_.StartRequest(account_id_, scope_list, &consumer_)); |
| SimulateOAuthTokenResponse(GetValidTokenResponse("token", 3600)); |
| run_loop1.Run(); |
| |
| EXPECT_EQ(1, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| EXPECT_EQ("token", consumer_.last_token_); |
| EXPECT_EQ(1U, token_manager_.token_cache().size()); |
| |
| token_manager_.ClearCache(); |
| |
| EXPECT_EQ(0U, token_manager_.token_cache().size()); |
| base::RunLoop run_loop2; |
| consumer_.SetResponseCompletedClosure(run_loop2.QuitClosure()); |
| |
| SimulateOAuthTokenResponse(GetValidTokenResponse("another token", 3600)); |
| request = token_manager_.StartRequest(account_id_, scope_list, &consumer_); |
| run_loop2.Run(); |
| EXPECT_EQ(2, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| EXPECT_EQ("another token", consumer_.last_token_); |
| EXPECT_EQ(1U, token_manager_.token_cache().size()); |
| } |
| |
| // Test that ClearCacheForAccount clears caches for the specific account. |
| TEST_F(OAuth2AccessTokenManagerTest, ClearCacheForAccount) { |
| base::RunLoop run_loop1; |
| consumer_.SetResponseCompletedClosure(run_loop1.QuitClosure()); |
| |
| std::unique_ptr<OAuth2AccessTokenManager::Request> request1( |
| token_manager_.StartRequest( |
| account_id_, OAuth2AccessTokenManager::ScopeSet(), &consumer_)); |
| SimulateOAuthTokenResponse(GetValidTokenResponse("token", 3600)); |
| run_loop1.Run(); |
| |
| EXPECT_EQ(1, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| EXPECT_EQ("token", consumer_.last_token_); |
| EXPECT_EQ(1U, token_manager_.token_cache().size()); |
| |
| base::RunLoop run_loop2; |
| consumer_.SetResponseCompletedClosure(run_loop2.QuitClosure()); |
| const CoreAccountId account_id_2("account_id_2"); |
| delegate_.AddAccount(account_id_2, "refreshToken2"); |
| // Makes a request for |account_id_2|. |
| std::unique_ptr<OAuth2AccessTokenManager::Request> request2( |
| token_manager_.StartRequest( |
| account_id_2, OAuth2AccessTokenManager::ScopeSet(), &consumer_)); |
| run_loop2.Run(); |
| |
| EXPECT_EQ(2, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| EXPECT_EQ("token", consumer_.last_token_); |
| EXPECT_EQ(2U, token_manager_.token_cache().size()); |
| |
| // Clears caches for |account_id_|. |
| token_manager_.ClearCacheForAccount(account_id_); |
| EXPECT_EQ(1U, token_manager_.token_cache().size()); |
| |
| base::RunLoop run_loop3; |
| consumer_.SetResponseCompletedClosure(run_loop3.QuitClosure()); |
| SimulateOAuthTokenResponse(GetValidTokenResponse("another token", 3600)); |
| // Makes a request for |account_id_| again. |
| std::unique_ptr<OAuth2AccessTokenManager::Request> request3( |
| token_manager_.StartRequest( |
| account_id_, OAuth2AccessTokenManager::ScopeSet(), &consumer_)); |
| run_loop3.Run(); |
| |
| EXPECT_EQ(3, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| EXPECT_EQ("another token", consumer_.last_token_); |
| EXPECT_EQ(2U, token_manager_.token_cache().size()); |
| |
| // Clears caches for |account_id_|. |
| token_manager_.ClearCacheForAccount(account_id_); |
| EXPECT_EQ(1U, token_manager_.token_cache().size()); |
| |
| // Clears caches for |account_id_2|. |
| token_manager_.ClearCacheForAccount(account_id_2); |
| EXPECT_EQ(0U, token_manager_.token_cache().size()); |
| } |
| |
| // Test that StartRequest checks HandleAccessTokenFetch() from |delegate_| |
| // before FetchOAuth2Token. |
| TEST_F(OAuth2AccessTokenManagerTest, HandleAccessTokenFetch) { |
| base::RunLoop run_loop; |
| delegate_.SetAccessTokenHandleClosure(run_loop.QuitClosure()); |
| std::unique_ptr<OAuth2AccessTokenManager::Request> request( |
| token_manager_.StartRequest( |
| account_id_, OAuth2AccessTokenManager::ScopeSet(), &consumer_)); |
| SimulateOAuthTokenResponse(GetValidTokenResponse("token", 3600)); |
| run_loop.Run(); |
| |
| EXPECT_EQ(0, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| EXPECT_EQ(0U, token_manager_.GetNumPendingRequestsForTesting( |
| GaiaUrls::GetInstance()->oauth2_chrome_client_id(), |
| account_id_, OAuth2AccessTokenManager::ScopeSet())); |
| } |
| |
| // Test that InvalidateAccessToken triggers OnAccessTokenInvalidated. |
| TEST_F(OAuth2AccessTokenManagerTest, OnAccessTokenInvalidated) { |
| base::RunLoop run_loop; |
| OAuth2AccessTokenManager::ScopeSet scope_set; |
| scope_set.insert("scope"); |
| std::string access_token("access_token"); |
| delegate_.SetOnAccessTokenInvalidated( |
| account_id_, GaiaUrls::GetInstance()->oauth2_chrome_client_id(), |
| scope_set, access_token, run_loop.QuitClosure()); |
| token_manager_.InvalidateAccessToken(account_id_, scope_set, access_token); |
| run_loop.Run(); |
| } |
| |
| // Test that OnAccessTokenFetched is invoked when a request is canceled. |
| TEST_F(OAuth2AccessTokenManagerTest, OnAccessTokenFetchedOnRequestCanceled) { |
| base::RunLoop run_loop; |
| GoogleServiceAuthError error(GoogleServiceAuthError::REQUEST_CANCELED); |
| delegate_.SetOnAccessTokenFetched(account_id_, error, run_loop.QuitClosure()); |
| std::unique_ptr<OAuth2AccessTokenManager::Request> request( |
| token_manager_.StartRequest( |
| account_id_, OAuth2AccessTokenManager::ScopeSet(), &consumer_)); |
| token_manager_.CancelAllRequests(); |
| run_loop.Run(); |
| } |
| |
| // Test that OnAccessTokenFetched is invoked when a request is completed. |
| TEST_F(OAuth2AccessTokenManagerTest, OnAccessTokenFetchedOnRequestCompleted) { |
| base::RunLoop run_loop; |
| GoogleServiceAuthError error(GoogleServiceAuthError::NONE); |
| delegate_.SetOnAccessTokenFetched(account_id_, error, run_loop.QuitClosure()); |
| std::unique_ptr<OAuth2AccessTokenManager::Request> request( |
| token_manager_.StartRequest( |
| account_id_, OAuth2AccessTokenManager::ScopeSet(), &consumer_)); |
| SimulateOAuthTokenResponse(GetValidTokenResponse("token", 3600)); |
| run_loop.Run(); |
| } |
| |
| // Test that StartRequest triggers DiagnosticsObserver::OnAccessTokenRequested. |
| TEST_F(OAuth2AccessTokenManagerTest, OnAccessTokenRequested) { |
| DiagnosticsObserverForTesting observer; |
| OAuth2AccessTokenManager::ScopeSet scopeset; |
| scopeset.insert("scope"); |
| base::RunLoop run_loop; |
| observer.SetOnAccessTokenRequested(account_id_, consumer_.id(), scopeset, |
| run_loop.QuitClosure()); |
| token_manager_.AddDiagnosticsObserver(&observer); |
| |
| std::unique_ptr<OAuth2AccessTokenManager::Request> request( |
| token_manager_.StartRequest(account_id_, scopeset, &consumer_)); |
| run_loop.Run(); |
| token_manager_.RemoveDiagnosticsObserver(&observer); |
| } |
| |
| // Test that DiagnosticsObserver::OnFetchAccessTokenComplete is invoked when a |
| // request is completed. |
| TEST_F(OAuth2AccessTokenManagerTest, |
| OnFetchAccessTokenCompleteOnRequestCompleted) { |
| DiagnosticsObserverForTesting observer; |
| OAuth2AccessTokenManager::ScopeSet scopeset; |
| scopeset.insert("scope"); |
| base::RunLoop run_loop; |
| GoogleServiceAuthError error(GoogleServiceAuthError::NONE); |
| observer.SetOnFetchAccessTokenComplete(account_id_, consumer_.id(), scopeset, |
| error, run_loop.QuitClosure()); |
| token_manager_.AddDiagnosticsObserver(&observer); |
| SimulateOAuthTokenResponse(GetValidTokenResponse("token", 3600)); |
| |
| std::unique_ptr<OAuth2AccessTokenManager::Request> request( |
| token_manager_.StartRequest(account_id_, scopeset, &consumer_)); |
| run_loop.Run(); |
| token_manager_.RemoveDiagnosticsObserver(&observer); |
| } |
| |
| // Test that DiagnosticsObserver::OnFetchAccessTokenComplete is invoked when |
| // StartRequest is called for an account without a refresh token. |
| TEST_F(OAuth2AccessTokenManagerTest, |
| OnFetchAccessTokenCompleteOnRequestWithoutRefreshToken) { |
| DiagnosticsObserverForTesting observer; |
| OAuth2AccessTokenManager::ScopeSet scopeset; |
| scopeset.insert("scope"); |
| base::RunLoop run_loop; |
| // |account_id| doesn't have a refresh token, OnFetchAccessTokenComplete |
| // should report GoogleServiceAuthError::USER_NOT_SIGNED_UP. |
| GoogleServiceAuthError error(GoogleServiceAuthError::USER_NOT_SIGNED_UP); |
| const CoreAccountId account_id("new_account_id"); |
| observer.SetOnFetchAccessTokenComplete(account_id, consumer_.id(), scopeset, |
| error, run_loop.QuitClosure()); |
| token_manager_.AddDiagnosticsObserver(&observer); |
| |
| std::unique_ptr<OAuth2AccessTokenManager::Request> request( |
| token_manager_.StartRequest(account_id, scopeset, &consumer_)); |
| run_loop.Run(); |
| token_manager_.RemoveDiagnosticsObserver(&observer); |
| } |
| |
| // Test that DiagnosticsObserver::OnAccessTokenRemoved is called when a token is |
| // removed from the token cache. |
| TEST_F(OAuth2AccessTokenManagerTest, OnAccessTokenRemoved) { |
| const std::string access_token("token"); |
| SimulateOAuthTokenResponse(GetValidTokenResponse(access_token, 3600)); |
| |
| // First populate the cache with access tokens for four accounts. |
| OAuth2AccessTokenManager::ScopeSet scopeset1; |
| scopeset1.insert("scope1"); |
| CreateRequestAndBlockUntilComplete(account_id_, scopeset1); |
| |
| OAuth2AccessTokenManager::ScopeSet scopeset2; |
| scopeset2.insert("scope2"); |
| CoreAccountId account_id_2("account_id_2"); |
| delegate_.AddAccount(account_id_2, "refreshToken2"); |
| CreateRequestAndBlockUntilComplete(account_id_2, scopeset2); |
| |
| OAuth2AccessTokenManager::ScopeSet scopeset3; |
| scopeset3.insert("scope3"); |
| CoreAccountId account_id_3("account_id_3"); |
| delegate_.AddAccount(account_id_3, "refreshToken3"); |
| CreateRequestAndBlockUntilComplete(account_id_3, scopeset3); |
| |
| OAuth2AccessTokenManager::ScopeSet scopeset4; |
| scopeset4.insert("scope4"); |
| CoreAccountId account_id_4("account_id_4"); |
| delegate_.AddAccount(account_id_4, "refreshToken4"); |
| CreateRequestAndBlockUntilComplete(account_id_4, scopeset4); |
| |
| EXPECT_EQ(4, consumer_.number_of_successful_tokens_); |
| EXPECT_EQ(0, consumer_.number_of_errors_); |
| EXPECT_EQ("token", consumer_.last_token_); |
| EXPECT_EQ(4U, token_manager_.token_cache().size()); |
| |
| DiagnosticsObserverForTesting observer; |
| token_manager_.AddDiagnosticsObserver(&observer); |
| |
| DiagnosticsObserverForTesting::AccountToScopeSet account_to_scopeset; |
| |
| // ClearCacheForAccount should call OnAccessTokenRemoved. |
| base::RunLoop run_loop1; |
| account_to_scopeset[account_id_] = scopeset1; |
| observer.SetOnAccessTokenRemoved(account_to_scopeset, |
| run_loop1.QuitClosure()); |
| token_manager_.ClearCacheForAccount(account_id_); |
| run_loop1.Run(); |
| EXPECT_EQ(3U, token_manager_.token_cache().size()); |
| |
| // InvalidateAccessToken should call OnAccessTokenRemoved for the cached |
| // token. |
| base::RunLoop run_loop2; |
| account_to_scopeset.clear(); |
| account_to_scopeset[account_id_2] = scopeset2; |
| observer.SetOnAccessTokenRemoved(account_to_scopeset, |
| run_loop2.QuitClosure()); |
| token_manager_.InvalidateAccessToken(account_id_2, scopeset2, access_token); |
| run_loop2.Run(); |
| EXPECT_EQ(2U, token_manager_.token_cache().size()); |
| |
| // ClearCache should call OnAccessTokenRemoved for all of the cached tokens. |
| base::RunLoop run_loop3; |
| account_to_scopeset.clear(); |
| account_to_scopeset[account_id_3] = scopeset3; |
| account_to_scopeset[account_id_4] = scopeset4; |
| observer.SetOnAccessTokenRemoved(account_to_scopeset, |
| run_loop3.QuitClosure()); |
| token_manager_.ClearCache(); |
| run_loop3.Run(); |
| EXPECT_EQ(0U, token_manager_.token_cache().size()); |
| |
| token_manager_.RemoveDiagnosticsObserver(&observer); |
| } |