blob: e343dae1105bc60c037b1eba15e4b2e987f4ab0d [file] [log] [blame]
// 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_access_token_fetcher.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 GaiaAccessTokenFetcher::
CreateExchangeRefreshTokenForAccessTokenInstance(
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);
}