blob: dced8e429a2174b9761ad818c78353c48921e1fd [file] [log] [blame]
// Copyright 2014 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 "chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.h"
#include <map>
#include <string>
#include <utility>
#include <vector>
#include "base/command_line.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "build/build_config.h"
#include "components/os_crypt/os_crypt_mocker.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/scoped_user_pref_update.h"
#include "components/prefs/testing_pref_service.h"
#include "components/signin/core/browser/profile_oauth2_token_service.h"
#include "components/signin/core/browser/signin_error_controller.h"
#include "components/signin/core/browser/test_signin_client.h"
#include "components/signin/core/browser/webdata/token_web_data.h"
#include "components/signin/core/common/profile_management_switches.h"
#include "components/signin/core/common/signin_pref_names.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_token_service_test_util.h"
#include "net/http/http_status_code.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
// Defining constant here to handle backward compatiblity tests, but this
// constant is no longer used in current versions of chrome.
static const char kLSOService[] = "lso";
static const char kEmail[] = "user@gmail.com";
class MutableProfileOAuth2TokenServiceDelegateTest
: public testing::Test,
public OAuth2AccessTokenConsumer,
public OAuth2TokenService::Observer {
public:
MutableProfileOAuth2TokenServiceDelegateTest()
: factory_(NULL),
access_token_success_count_(0),
access_token_failure_count_(0),
access_token_failure_(GoogleServiceAuthError::NONE),
token_available_count_(0),
token_revoked_count_(0),
tokens_loaded_count_(0),
start_batch_changes_(0),
end_batch_changes_(0) {}
void SetUp() override {
OSCryptMocker::SetUpWithSingleton();
factory_.SetFakeResponse(GaiaUrls::GetInstance()->oauth2_revoke_url(), "",
net::HTTP_OK, net::URLRequestStatus::SUCCESS);
pref_service_.registry()->RegisterListPref(
AccountTrackerService::kAccountInfoPref);
pref_service_.registry()->RegisterIntegerPref(
prefs::kAccountIdMigrationState,
AccountTrackerService::MIGRATION_NOT_STARTED);
client_.reset(new TestSigninClient(&pref_service_));
client_->SetURLRequestContext(new net::TestURLRequestContextGetter(
base::ThreadTaskRunnerHandle::Get()));
client_->LoadTokenDatabase();
account_tracker_service_.Initialize(client_.get());
oauth2_service_delegate_.reset(new MutableProfileOAuth2TokenServiceDelegate(
client_.get(), &signin_error_controller_, &account_tracker_service_));
// Make sure PO2TS has a chance to load itself before continuing.
base::RunLoop().RunUntilIdle();
oauth2_service_delegate_->AddObserver(this);
}
void TearDown() override {
oauth2_service_delegate_->RemoveObserver(this);
oauth2_service_delegate_->Shutdown();
OSCryptMocker::TearDown();
}
void AddAuthTokenManually(const std::string& service,
const std::string& value) {
scoped_refptr<TokenWebData> token_web_data = client_->GetDatabase();
if (token_web_data.get())
token_web_data->SetTokenForService(service, value);
}
// OAuth2AccessTokenConusmer implementation
void OnGetTokenSuccess(const std::string& access_token,
const base::Time& expiration_time) override {
++access_token_success_count_;
}
void OnGetTokenFailure(const GoogleServiceAuthError& error) override {
++access_token_failure_count_;
access_token_failure_ = error;
}
// OAuth2TokenService::Observer implementation.
void OnRefreshTokenAvailable(const std::string& account_id) override {
++token_available_count_;
}
void OnRefreshTokenRevoked(const std::string& account_id) override {
++token_revoked_count_;
}
void OnRefreshTokensLoaded() override { ++tokens_loaded_count_; }
void OnStartBatchChanges() override { ++start_batch_changes_; }
void OnEndBatchChanges() override { ++end_batch_changes_; }
void ResetObserverCounts() {
token_available_count_ = 0;
token_revoked_count_ = 0;
tokens_loaded_count_ = 0;
start_batch_changes_ = 0;
end_batch_changes_ = 0;
}
void ExpectNoNotifications() {
EXPECT_EQ(0, token_available_count_);
EXPECT_EQ(0, token_revoked_count_);
EXPECT_EQ(0, tokens_loaded_count_);
ResetObserverCounts();
}
void ExpectOneTokenAvailableNotification() {
EXPECT_EQ(1, token_available_count_);
EXPECT_EQ(0, token_revoked_count_);
EXPECT_EQ(0, tokens_loaded_count_);
ResetObserverCounts();
}
void ExpectOneTokenRevokedNotification() {
EXPECT_EQ(0, token_available_count_);
EXPECT_EQ(1, token_revoked_count_);
EXPECT_EQ(0, tokens_loaded_count_);
ResetObserverCounts();
}
void ExpectOneTokensLoadedNotification() {
EXPECT_EQ(0, token_available_count_);
EXPECT_EQ(0, token_revoked_count_);
EXPECT_EQ(1, tokens_loaded_count_);
ResetObserverCounts();
}
protected:
base::MessageLoop message_loop_;
net::FakeURLFetcherFactory factory_;
std::unique_ptr<TestSigninClient> client_;
std::unique_ptr<MutableProfileOAuth2TokenServiceDelegate>
oauth2_service_delegate_;
TestingOAuth2TokenServiceConsumer consumer_;
SigninErrorController signin_error_controller_;
TestingPrefServiceSimple pref_service_;
AccountTrackerService account_tracker_service_;
int access_token_success_count_;
int access_token_failure_count_;
GoogleServiceAuthError access_token_failure_;
int token_available_count_;
int token_revoked_count_;
int tokens_loaded_count_;
int start_batch_changes_;
int end_batch_changes_;
};
TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, PersistenceDBUpgrade) {
std::string main_account_id(kEmail);
std::string main_refresh_token("old_refresh_token");
// Populate DB with legacy tokens.
AddAuthTokenManually(GaiaConstants::kSyncService, "syncServiceToken");
AddAuthTokenManually(kLSOService, "lsoToken");
AddAuthTokenManually(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
main_refresh_token);
switches::EnableAccountConsistencyForTesting(
base::CommandLine::ForCurrentProcess());
// Force LoadCredentials.
oauth2_service_delegate_->LoadCredentials(main_account_id);
base::RunLoop().RunUntilIdle();
// Legacy tokens get discarded, but the old refresh token is kept.
EXPECT_EQ(1, tokens_loaded_count_);
EXPECT_EQ(1, token_available_count_);
EXPECT_EQ(1, start_batch_changes_);
EXPECT_EQ(1, end_batch_changes_);
EXPECT_TRUE(
oauth2_service_delegate_->RefreshTokenIsAvailable(main_account_id));
EXPECT_EQ(1U, oauth2_service_delegate_->refresh_tokens_.size());
EXPECT_EQ(main_refresh_token,
oauth2_service_delegate_->refresh_tokens_[main_account_id]
->refresh_token());
// Add an old legacy token to the DB, to ensure it will not overwrite existing
// credentials for main account.
AddAuthTokenManually(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
"secondOldRefreshToken");
// Add some other legacy token. (Expected to get discarded).
AddAuthTokenManually(kLSOService, "lsoToken");
// Also add a token using PO2TS.UpdateCredentials and make sure upgrade does
// not wipe it.
std::string other_account_id("other_account_id");
std::string other_refresh_token("other_refresh_token");
oauth2_service_delegate_->UpdateCredentials(other_account_id,
other_refresh_token);
ResetObserverCounts();
// Force LoadCredentials.
oauth2_service_delegate_->LoadCredentials(main_account_id);
base::RunLoop().RunUntilIdle();
// Again legacy tokens get discarded, but since the main porfile account
// token is present it is not overwritten.
EXPECT_EQ(2, token_available_count_);
EXPECT_EQ(1, tokens_loaded_count_);
EXPECT_EQ(1, start_batch_changes_);
EXPECT_EQ(1, end_batch_changes_);
EXPECT_EQ(main_refresh_token,
oauth2_service_delegate_->GetRefreshToken(main_account_id));
EXPECT_TRUE(
oauth2_service_delegate_->RefreshTokenIsAvailable(main_account_id));
// TODO(fgorski): cover both using RefreshTokenIsAvailable() and then get the
// tokens using GetRefreshToken()
EXPECT_EQ(2U, oauth2_service_delegate_->refresh_tokens_.size());
EXPECT_EQ(main_refresh_token,
oauth2_service_delegate_->refresh_tokens_[main_account_id]
->refresh_token());
EXPECT_EQ(other_refresh_token,
oauth2_service_delegate_->refresh_tokens_[other_account_id]
->refresh_token());
oauth2_service_delegate_->RevokeAllCredentials();
EXPECT_EQ(2, start_batch_changes_);
EXPECT_EQ(2, end_batch_changes_);
}
TEST_F(MutableProfileOAuth2TokenServiceDelegateTest,
PersistenceRevokeCredentials) {
std::string account_id_1 = "account_id_1";
std::string refresh_token_1 = "refresh_token_1";
std::string account_id_2 = "account_id_2";
std::string refresh_token_2 = "refresh_token_2";
// TODO(fgorski): Enable below when implemented:
// EXPECT_FALSE(oauth2_servive_->RefreshTokenIsAvailable(account_id_1));
// EXPECT_FALSE(oauth2_servive_->RefreshTokenIsAvailable(account_id_2));
oauth2_service_delegate_->UpdateCredentials(account_id_1, refresh_token_1);
oauth2_service_delegate_->UpdateCredentials(account_id_2, refresh_token_2);
EXPECT_EQ(2, start_batch_changes_);
EXPECT_EQ(2, end_batch_changes_);
// TODO(fgorski): Enable below when implemented:
// EXPECT_TRUE(oauth2_servive_->RefreshTokenIsAvailable(account_id_1));
EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable(account_id_2));
ResetObserverCounts();
oauth2_service_delegate_->RevokeCredentials(account_id_1);
EXPECT_EQ(1, start_batch_changes_);
EXPECT_EQ(1, end_batch_changes_);
ExpectOneTokenRevokedNotification();
// TODO(fgorski): Enable below when implemented:
// EXPECT_FALSE(oauth2_servive_->RefreshTokenIsAvailable(account_id_1));
EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable(account_id_2));
oauth2_service_delegate_->RevokeAllCredentials();
EXPECT_EQ(0, token_available_count_);
EXPECT_EQ(1, token_revoked_count_);
EXPECT_EQ(0, tokens_loaded_count_);
EXPECT_EQ(1, start_batch_changes_);
EXPECT_EQ(1, end_batch_changes_);
ResetObserverCounts();
}
TEST_F(MutableProfileOAuth2TokenServiceDelegateTest,
PersistenceLoadCredentials) {
switches::EnableAccountConsistencyForTesting(
base::CommandLine::ForCurrentProcess());
// Ensure DB is clean.
oauth2_service_delegate_->RevokeAllCredentials();
ResetObserverCounts();
// Perform a load from an empty DB.
oauth2_service_delegate_->LoadCredentials("account_id");
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, start_batch_changes_);
EXPECT_EQ(1, end_batch_changes_);
ExpectOneTokensLoadedNotification();
// LoadCredentials() guarantees that the account given to it as argument
// is in the refresh_token map.
EXPECT_EQ(1U, oauth2_service_delegate_->refresh_tokens_.size());
EXPECT_TRUE(oauth2_service_delegate_->refresh_tokens_["account_id"]
->refresh_token()
.empty());
// Setup a DB with tokens that don't require upgrade and clear memory.
oauth2_service_delegate_->UpdateCredentials("account_id", "refresh_token");
oauth2_service_delegate_->UpdateCredentials("account_id2", "refresh_token2");
oauth2_service_delegate_->refresh_tokens_.clear();
EXPECT_EQ(2, start_batch_changes_);
EXPECT_EQ(2, end_batch_changes_);
ResetObserverCounts();
oauth2_service_delegate_->LoadCredentials("account_id");
base::RunLoop().RunUntilIdle();
EXPECT_EQ(2, token_available_count_);
EXPECT_EQ(0, token_revoked_count_);
EXPECT_EQ(1, tokens_loaded_count_);
EXPECT_EQ(1, start_batch_changes_);
EXPECT_EQ(1, end_batch_changes_);
ResetObserverCounts();
// TODO(fgorski): Enable below when implemented:
// EXPECT_TRUE(oauth2_servive_->RefreshTokenIsAvailable("account_id"));
EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable("account_id2"));
oauth2_service_delegate_->RevokeAllCredentials();
EXPECT_EQ(0, token_available_count_);
EXPECT_EQ(2, token_revoked_count_);
EXPECT_EQ(0, tokens_loaded_count_);
EXPECT_EQ(1, start_batch_changes_);
EXPECT_EQ(1, end_batch_changes_);
ResetObserverCounts();
}
TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, PersistanceNotifications) {
oauth2_service_delegate_->UpdateCredentials("account_id", "refresh_token");
ExpectOneTokenAvailableNotification();
oauth2_service_delegate_->UpdateCredentials("account_id", "refresh_token");
ExpectNoNotifications();
oauth2_service_delegate_->UpdateCredentials("account_id", "refresh_token2");
ExpectOneTokenAvailableNotification();
oauth2_service_delegate_->RevokeCredentials("account_id");
ExpectOneTokenRevokedNotification();
oauth2_service_delegate_->UpdateCredentials("account_id", "refresh_token2");
ExpectOneTokenAvailableNotification();
oauth2_service_delegate_->RevokeAllCredentials();
ResetObserverCounts();
}
TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, GetAccounts) {
EXPECT_TRUE(oauth2_service_delegate_->GetAccounts().empty());
oauth2_service_delegate_->UpdateCredentials("account_id1", "refresh_token1");
oauth2_service_delegate_->UpdateCredentials("account_id2", "refresh_token2");
std::vector<std::string> accounts = oauth2_service_delegate_->GetAccounts();
EXPECT_EQ(2u, accounts.size());
EXPECT_EQ(1, count(accounts.begin(), accounts.end(), "account_id1"));
EXPECT_EQ(1, count(accounts.begin(), accounts.end(), "account_id2"));
oauth2_service_delegate_->RevokeCredentials("account_id2");
accounts = oauth2_service_delegate_->GetAccounts();
EXPECT_EQ(1u, oauth2_service_delegate_->GetAccounts().size());
EXPECT_EQ(1, count(accounts.begin(), accounts.end(), "account_id1"));
}
TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, FetchPersistentError) {
oauth2_service_delegate_->UpdateCredentials(kEmail, "refreshToken");
EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
signin_error_controller_.auth_error());
GoogleServiceAuthError authfail(GoogleServiceAuthError::ACCOUNT_DELETED);
oauth2_service_delegate_->UpdateAuthError(kEmail, authfail);
EXPECT_NE(GoogleServiceAuthError::AuthErrorNone(),
signin_error_controller_.auth_error());
// Create a "success" fetch we don't expect to get called.
factory_.SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_url(),
GetValidTokenResponse("token", 3600), net::HTTP_OK,
net::URLRequestStatus::SUCCESS);
EXPECT_EQ(0, access_token_success_count_);
EXPECT_EQ(0, access_token_failure_count_);
std::vector<std::string> scope_list;
scope_list.push_back("scope");
std::unique_ptr<OAuth2AccessTokenFetcher> fetcher(
oauth2_service_delegate_->CreateAccessTokenFetcher(
kEmail, oauth2_service_delegate_->GetRequestContext(), this));
fetcher->Start("foo", "bar", scope_list);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(0, access_token_success_count_);
EXPECT_EQ(1, access_token_failure_count_);
}
TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, RetryBackoff) {
oauth2_service_delegate_->UpdateCredentials(kEmail, "refreshToken");
EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
signin_error_controller_.auth_error());
GoogleServiceAuthError authfail(GoogleServiceAuthError::SERVICE_UNAVAILABLE);
oauth2_service_delegate_->UpdateAuthError(kEmail, authfail);
EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
signin_error_controller_.auth_error());
// Create a "success" fetch we don't expect to get called just yet.
factory_.SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_url(),
GetValidTokenResponse("token", 3600), net::HTTP_OK,
net::URLRequestStatus::SUCCESS);
// Transient error will repeat until backoff period expires.
EXPECT_EQ(0, access_token_success_count_);
EXPECT_EQ(0, access_token_failure_count_);
std::vector<std::string> scope_list;
scope_list.push_back("scope");
std::unique_ptr<OAuth2AccessTokenFetcher> fetcher1(
oauth2_service_delegate_->CreateAccessTokenFetcher(
kEmail, oauth2_service_delegate_->GetRequestContext(), this));
fetcher1->Start("foo", "bar", scope_list);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(0, access_token_success_count_);
EXPECT_EQ(1, access_token_failure_count_);
// Expect a positive backoff time.
EXPECT_GT(oauth2_service_delegate_->backoff_entry_.GetTimeUntilRelease(),
TimeDelta());
// Pretend that backoff has expired and try again.
oauth2_service_delegate_->backoff_entry_.SetCustomReleaseTime(
base::TimeTicks());
std::unique_ptr<OAuth2AccessTokenFetcher> fetcher2(
oauth2_service_delegate_->CreateAccessTokenFetcher(
kEmail, oauth2_service_delegate_->GetRequestContext(), this));
fetcher2->Start("foo", "bar", scope_list);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, access_token_success_count_);
EXPECT_EQ(1, access_token_failure_count_);
}
TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, ResetBackoff) {
oauth2_service_delegate_->UpdateCredentials(kEmail, "refreshToken");
EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
signin_error_controller_.auth_error());
GoogleServiceAuthError authfail(GoogleServiceAuthError::SERVICE_UNAVAILABLE);
oauth2_service_delegate_->UpdateAuthError(kEmail, authfail);
EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
signin_error_controller_.auth_error());
// Create a "success" fetch we don't expect to get called just yet.
factory_.SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_url(),
GetValidTokenResponse("token", 3600), net::HTTP_OK,
net::URLRequestStatus::SUCCESS);
// Transient error will repeat until backoff period expires.
EXPECT_EQ(0, access_token_success_count_);
EXPECT_EQ(0, access_token_failure_count_);
std::vector<std::string> scope_list;
scope_list.push_back("scope");
std::unique_ptr<OAuth2AccessTokenFetcher> fetcher1(
oauth2_service_delegate_->CreateAccessTokenFetcher(
kEmail, oauth2_service_delegate_->GetRequestContext(), this));
fetcher1->Start("foo", "bar", scope_list);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(0, access_token_success_count_);
EXPECT_EQ(1, access_token_failure_count_);
// Notify of network change and ensure that request now runs.
oauth2_service_delegate_->OnNetworkChanged(
net::NetworkChangeNotifier::CONNECTION_WIFI);
std::unique_ptr<OAuth2AccessTokenFetcher> fetcher2(
oauth2_service_delegate_->CreateAccessTokenFetcher(
kEmail, oauth2_service_delegate_->GetRequestContext(), this));
fetcher2->Start("foo", "bar", scope_list);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, access_token_success_count_);
EXPECT_EQ(1, access_token_failure_count_);
}
TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, CanonicalizeAccountId) {
std::map<std::string, std::string> tokens;
tokens["AccountId-user@gmail.com"] = "refresh_token";
tokens["AccountId-Foo.Bar@gmail.com"] = "refresh_token";
tokens["AccountId-12345"] = "refresh_token";
switches::EnableAccountConsistencyForTesting(
base::CommandLine::ForCurrentProcess());
oauth2_service_delegate_->LoadAllCredentialsIntoMemory(tokens);
EXPECT_TRUE(
oauth2_service_delegate_->RefreshTokenIsAvailable("user@gmail.com"));
EXPECT_TRUE(
oauth2_service_delegate_->RefreshTokenIsAvailable("foobar@gmail.com"));
EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable("12345"));
}
TEST_F(MutableProfileOAuth2TokenServiceDelegateTest,
CanonAndNonCanonAccountId) {
std::map<std::string, std::string> tokens;
tokens["AccountId-Foo.Bar@gmail.com"] = "bad_token";
tokens["AccountId-foobar@gmail.com"] = "good_token";
switches::EnableAccountConsistencyForTesting(
base::CommandLine::ForCurrentProcess());
oauth2_service_delegate_->LoadAllCredentialsIntoMemory(tokens);
EXPECT_EQ(1u, oauth2_service_delegate_->GetAccounts().size());
EXPECT_TRUE(
oauth2_service_delegate_->RefreshTokenIsAvailable("foobar@gmail.com"));
EXPECT_STREQ(
"good_token",
oauth2_service_delegate_->GetRefreshToken("foobar@gmail.com").c_str());
}
TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, ShutdownService) {
switches::EnableAccountConsistencyForTesting(
base::CommandLine::ForCurrentProcess());
EXPECT_TRUE(oauth2_service_delegate_->GetAccounts().empty());
oauth2_service_delegate_->UpdateCredentials("account_id1", "refresh_token1");
oauth2_service_delegate_->UpdateCredentials("account_id2", "refresh_token2");
std::vector<std::string> accounts = oauth2_service_delegate_->GetAccounts();
EXPECT_EQ(2u, accounts.size());
EXPECT_EQ(1, count(accounts.begin(), accounts.end(), "account_id1"));
EXPECT_EQ(1, count(accounts.begin(), accounts.end(), "account_id2"));
oauth2_service_delegate_->LoadCredentials("account_id1");
oauth2_service_delegate_->UpdateCredentials("account_id1", "refresh_token3");
oauth2_service_delegate_->Shutdown();
EXPECT_TRUE(oauth2_service_delegate_->server_revokes_.empty());
EXPECT_TRUE(oauth2_service_delegate_->refresh_tokens_.empty());
EXPECT_EQ(0, oauth2_service_delegate_->web_data_service_request_);
}
TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, GaiaIdMigration) {
if (account_tracker_service_.GetMigrationState() !=
AccountTrackerService::MIGRATION_NOT_STARTED) {
std::string email = "foo@gmail.com";
std::string gaia_id = "foo's gaia id";
switches::EnableAccountConsistencyForTesting(
base::CommandLine::ForCurrentProcess());
pref_service_.SetInteger(prefs::kAccountIdMigrationState,
AccountTrackerService::MIGRATION_NOT_STARTED);
ListPrefUpdate update(&pref_service_,
AccountTrackerService::kAccountInfoPref);
update->Clear();
auto dict = base::MakeUnique<base::DictionaryValue>();
dict->SetString("account_id", base::UTF8ToUTF16(email));
dict->SetString("email", base::UTF8ToUTF16(email));
dict->SetString("gaia", base::UTF8ToUTF16(gaia_id));
update->Append(std::move(dict));
account_tracker_service_.Shutdown();
account_tracker_service_.Initialize(client_.get());
AddAuthTokenManually("AccountId-" + email, "refresh_token");
oauth2_service_delegate_->LoadCredentials(gaia_id);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, tokens_loaded_count_);
EXPECT_EQ(1, token_available_count_);
EXPECT_EQ(1, start_batch_changes_);
EXPECT_EQ(1, end_batch_changes_);
std::vector<std::string> accounts = oauth2_service_delegate_->GetAccounts();
EXPECT_EQ(1u, accounts.size());
EXPECT_FALSE(oauth2_service_delegate_->RefreshTokenIsAvailable(email));
EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable(gaia_id));
account_tracker_service_.SetMigrationDone();
oauth2_service_delegate_->Shutdown();
ResetObserverCounts();
oauth2_service_delegate_->LoadCredentials(gaia_id);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, tokens_loaded_count_);
EXPECT_EQ(1, token_available_count_);
EXPECT_EQ(1, start_batch_changes_);
EXPECT_EQ(1, end_batch_changes_);
EXPECT_FALSE(oauth2_service_delegate_->RefreshTokenIsAvailable(email));
EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable(gaia_id));
accounts = oauth2_service_delegate_->GetAccounts();
EXPECT_EQ(1u, accounts.size());
}
}
TEST_F(MutableProfileOAuth2TokenServiceDelegateTest,
GaiaIdMigrationCrashInTheMiddle) {
if (account_tracker_service_.GetMigrationState() !=
AccountTrackerService::MIGRATION_NOT_STARTED) {
std::string email1 = "foo@gmail.com";
std::string gaia_id1 = "foo's gaia id";
std::string email2 = "bar@gmail.com";
std::string gaia_id2 = "bar's gaia id";
switches::EnableAccountConsistencyForTesting(
base::CommandLine::ForCurrentProcess());
pref_service_.SetInteger(prefs::kAccountIdMigrationState,
AccountTrackerService::MIGRATION_NOT_STARTED);
ListPrefUpdate update(&pref_service_,
AccountTrackerService::kAccountInfoPref);
update->Clear();
auto dict = base::MakeUnique<base::DictionaryValue>();
dict->SetString("account_id", base::UTF8ToUTF16(email1));
dict->SetString("email", base::UTF8ToUTF16(email1));
dict->SetString("gaia", base::UTF8ToUTF16(gaia_id1));
update->Append(std::move(dict));
dict = base::MakeUnique<base::DictionaryValue>();
dict->SetString("account_id", base::UTF8ToUTF16(email2));
dict->SetString("email", base::UTF8ToUTF16(email2));
dict->SetString("gaia", base::UTF8ToUTF16(gaia_id2));
update->Append(std::move(dict));
account_tracker_service_.Shutdown();
account_tracker_service_.Initialize(client_.get());
AddAuthTokenManually("AccountId-" + email1, "refresh_token");
AddAuthTokenManually("AccountId-" + email2, "refresh_token");
AddAuthTokenManually("AccountId-" + gaia_id1, "refresh_token");
oauth2_service_delegate_->LoadCredentials(gaia_id1);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, tokens_loaded_count_);
EXPECT_EQ(2, token_available_count_);
EXPECT_EQ(1, start_batch_changes_);
EXPECT_EQ(1, end_batch_changes_);
std::vector<std::string> accounts = oauth2_service_delegate_->GetAccounts();
EXPECT_EQ(2u, accounts.size());
EXPECT_FALSE(oauth2_service_delegate_->RefreshTokenIsAvailable(email1));
EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable(gaia_id1));
EXPECT_FALSE(oauth2_service_delegate_->RefreshTokenIsAvailable(email2));
EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable(gaia_id2));
account_tracker_service_.SetMigrationDone();
oauth2_service_delegate_->Shutdown();
ResetObserverCounts();
oauth2_service_delegate_->LoadCredentials(gaia_id1);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, tokens_loaded_count_);
EXPECT_EQ(2, token_available_count_);
EXPECT_EQ(1, start_batch_changes_);
EXPECT_EQ(1, end_batch_changes_);
EXPECT_FALSE(oauth2_service_delegate_->RefreshTokenIsAvailable(email1));
EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable(gaia_id1));
EXPECT_FALSE(oauth2_service_delegate_->RefreshTokenIsAvailable(email2));
EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable(gaia_id2));
accounts = oauth2_service_delegate_->GetAccounts();
EXPECT_EQ(2u, accounts.size());
}
}
TEST_F(MutableProfileOAuth2TokenServiceDelegateTest,
LoadPrimaryAccountOnlyWhenAccountConsistencyDisabled) {
std::string primary_account = "primaryaccount";
std::string secondary_account = "secondaryaccount";
oauth2_service_delegate_->RevokeAllCredentials();
ResetObserverCounts();
AddAuthTokenManually("AccountId-" + primary_account, "refresh_token");
AddAuthTokenManually("AccountId-" + secondary_account, "refresh_token");
oauth2_service_delegate_->LoadCredentials(primary_account);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, tokens_loaded_count_);
EXPECT_EQ(1, token_available_count_);
EXPECT_EQ(1, token_revoked_count_);
EXPECT_EQ(1, start_batch_changes_);
EXPECT_EQ(1, end_batch_changes_);
EXPECT_TRUE(
oauth2_service_delegate_->RefreshTokenIsAvailable(primary_account));
EXPECT_FALSE(
oauth2_service_delegate_->RefreshTokenIsAvailable(secondary_account));
oauth2_service_delegate_->RevokeAllCredentials();
ResetObserverCounts();
AddAuthTokenManually("AccountId-" + primary_account, "refresh_token");
AddAuthTokenManually("AccountId-" + secondary_account, "refresh_token");
switches::EnableAccountConsistencyForTesting(
base::CommandLine::ForCurrentProcess());
oauth2_service_delegate_->LoadCredentials(primary_account);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, tokens_loaded_count_);
EXPECT_EQ(2, token_available_count_);
EXPECT_EQ(0, token_revoked_count_);
EXPECT_EQ(1, start_batch_changes_);
EXPECT_EQ(1, end_batch_changes_);
EXPECT_TRUE(
oauth2_service_delegate_->RefreshTokenIsAvailable(primary_account));
EXPECT_TRUE(
oauth2_service_delegate_->RefreshTokenIsAvailable(secondary_account));
}