blob: f36924cdf472f86c52c30653e0a0134841d04ad2 [file] [log] [blame]
// Copyright 2015 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 "components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h"
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/testing_pref_service.h"
#include "components/signin/core/browser/account_tracker_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/signin_pref_names.h"
#include "components/signin/core/browser/test_signin_client.h"
#include "components/signin/ios/browser/fake_profile_oauth2_token_service_ios_provider.h"
#include "google_apis/gaia/gaia_urls.h"
#include "google_apis/gaia/oauth2_access_token_consumer.h"
#include "google_apis/gaia/oauth2_token_service_test_util.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
typedef ProfileOAuth2TokenServiceIOSProvider::AccountInfo ProviderAccount;
class ProfileOAuth2TokenServiceIOSDelegateTest
: public testing::Test,
public OAuth2AccessTokenConsumer,
public OAuth2TokenService::Observer,
public SigninErrorController::Observer {
public:
ProfileOAuth2TokenServiceIOSDelegateTest()
: factory_(NULL),
client_(&prefs_),
signin_error_controller_(
SigninErrorController::AccountMode::ANY_ACCOUNT),
token_available_count_(0),
token_revoked_count_(0),
tokens_loaded_count_(0),
access_token_success_(0),
access_token_failure_(0),
error_changed_count_(0),
auth_error_changed_count_(0),
last_access_token_error_(GoogleServiceAuthError::NONE) {}
void SetUp() override {
prefs_.registry()->RegisterListPref(
AccountTrackerService::kAccountInfoPref);
prefs_.registry()->RegisterIntegerPref(
prefs::kAccountIdMigrationState,
AccountTrackerService::MIGRATION_NOT_STARTED);
account_tracker_.Initialize(&client_);
prefs_.registry()->RegisterBooleanPref(
prefs::kTokenServiceExcludeAllSecondaryAccounts, false);
prefs_.registry()->RegisterListPref(
prefs::kTokenServiceExcludedSecondaryAccounts);
fake_provider_ = new FakeProfileOAuth2TokenServiceIOSProvider();
factory_.SetFakeResponse(GaiaUrls::GetInstance()->oauth2_revoke_url(), "",
net::HTTP_OK, net::URLRequestStatus::SUCCESS);
oauth2_delegate_.reset(new ProfileOAuth2TokenServiceIOSDelegate(
&client_, base::WrapUnique(fake_provider_), &account_tracker_,
&signin_error_controller_));
oauth2_delegate_->AddObserver(this);
signin_error_controller_.AddObserver(this);
}
void TearDown() override {
signin_error_controller_.RemoveObserver(this);
oauth2_delegate_->RemoveObserver(this);
oauth2_delegate_->Shutdown();
}
// OAuth2AccessTokenConsumer implementation.
void OnGetTokenSuccess(const std::string& access_token,
const base::Time& expiration_time) override {
++access_token_success_;
}
void OnGetTokenFailure(const GoogleServiceAuthError& error) override {
++access_token_failure_;
last_access_token_error_ = 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 OnAuthErrorChanged(const std::string& account_id,
const GoogleServiceAuthError& error) override {
++auth_error_changed_count_;
}
// SigninErrorController::Observer implementation.
void OnErrorChanged() override { ++error_changed_count_; }
void ResetObserverCounts() {
token_available_count_ = 0;
token_revoked_count_ = 0;
tokens_loaded_count_ = 0;
token_available_count_ = 0;
access_token_failure_ = 0;
error_changed_count_ = 0;
auth_error_changed_count_ = 0;
}
std::string GetAccountId(const ProviderAccount& provider_account) {
return account_tracker_.PickAccountIdForAccount(provider_account.gaia,
provider_account.email);
}
protected:
base::MessageLoop message_loop_;
net::FakeURLFetcherFactory factory_;
TestingPrefServiceSimple prefs_;
TestSigninClient client_;
AccountTrackerService account_tracker_;
SigninErrorController signin_error_controller_;
FakeProfileOAuth2TokenServiceIOSProvider* fake_provider_;
std::unique_ptr<ProfileOAuth2TokenServiceIOSDelegate> oauth2_delegate_;
TestingOAuth2TokenServiceConsumer consumer_;
int token_available_count_;
int token_revoked_count_;
int tokens_loaded_count_;
int access_token_success_;
int access_token_failure_;
int error_changed_count_;
int auth_error_changed_count_;
GoogleServiceAuthError last_access_token_error_;
};
TEST_F(ProfileOAuth2TokenServiceIOSDelegateTest,
LoadRevokeCredentialsOneAccount) {
ProviderAccount account = fake_provider_->AddAccount("gaia_1", "email_1@x");
oauth2_delegate_->LoadCredentials(GetAccountId(account));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, token_available_count_);
EXPECT_EQ(1, tokens_loaded_count_);
EXPECT_EQ(0, token_revoked_count_);
EXPECT_EQ(1U, oauth2_delegate_->GetAccounts().size());
EXPECT_TRUE(oauth2_delegate_->RefreshTokenIsAvailable(GetAccountId(account)));
ResetObserverCounts();
oauth2_delegate_->RevokeAllCredentials();
EXPECT_EQ(0, token_available_count_);
EXPECT_EQ(0, tokens_loaded_count_);
EXPECT_EQ(1, token_revoked_count_);
EXPECT_EQ(0U, oauth2_delegate_->GetAccounts().size());
EXPECT_FALSE(oauth2_delegate_->RefreshTokenIsAvailable("another_account"));
}
TEST_F(ProfileOAuth2TokenServiceIOSDelegateTest,
LoadRevokeCredentialsMultipleAccounts) {
ProviderAccount account1 = fake_provider_->AddAccount("gaia_1", "email_1@x");
ProviderAccount account2 = fake_provider_->AddAccount("gaia_2", "email_2@x");
ProviderAccount account3 = fake_provider_->AddAccount("gaia_3", "email_3@x");
oauth2_delegate_->LoadCredentials(GetAccountId(account1));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(3, token_available_count_);
EXPECT_EQ(1, tokens_loaded_count_);
EXPECT_EQ(0, token_revoked_count_);
EXPECT_EQ(3U, oauth2_delegate_->GetAccounts().size());
EXPECT_TRUE(
oauth2_delegate_->RefreshTokenIsAvailable(GetAccountId(account1)));
EXPECT_TRUE(
oauth2_delegate_->RefreshTokenIsAvailable(GetAccountId(account2)));
EXPECT_TRUE(
oauth2_delegate_->RefreshTokenIsAvailable(GetAccountId(account3)));
ResetObserverCounts();
oauth2_delegate_->RevokeAllCredentials();
EXPECT_EQ(0, token_available_count_);
EXPECT_EQ(0, tokens_loaded_count_);
EXPECT_EQ(3, token_revoked_count_);
EXPECT_EQ(0U, oauth2_delegate_->GetAccounts().size());
EXPECT_FALSE(
oauth2_delegate_->RefreshTokenIsAvailable(GetAccountId(account1)));
EXPECT_FALSE(
oauth2_delegate_->RefreshTokenIsAvailable(GetAccountId(account2)));
EXPECT_FALSE(
oauth2_delegate_->RefreshTokenIsAvailable(GetAccountId(account3)));
}
TEST_F(ProfileOAuth2TokenServiceIOSDelegateTest, ReloadCredentials) {
ProviderAccount account1 = fake_provider_->AddAccount("gaia_1", "email_1@x");
ProviderAccount account2 = fake_provider_->AddAccount("gaia_2", "email_2@x");
ProviderAccount account3 = fake_provider_->AddAccount("gaia_3", "email_3@x");
oauth2_delegate_->LoadCredentials(GetAccountId(account1));
base::RunLoop().RunUntilIdle();
// Change the accounts.
ResetObserverCounts();
fake_provider_->ClearAccounts();
fake_provider_->AddAccount(account1.gaia, account1.email);
ProviderAccount account4 = fake_provider_->AddAccount("gaia_4", "email_4@x");
oauth2_delegate_->ReloadCredentials();
EXPECT_EQ(1, token_available_count_);
EXPECT_EQ(0, tokens_loaded_count_);
EXPECT_EQ(2, token_revoked_count_);
EXPECT_EQ(2U, oauth2_delegate_->GetAccounts().size());
EXPECT_TRUE(
oauth2_delegate_->RefreshTokenIsAvailable(GetAccountId(account1)));
EXPECT_FALSE(
oauth2_delegate_->RefreshTokenIsAvailable(GetAccountId(account2)));
EXPECT_FALSE(
oauth2_delegate_->RefreshTokenIsAvailable(GetAccountId(account3)));
EXPECT_TRUE(
oauth2_delegate_->RefreshTokenIsAvailable(GetAccountId(account4)));
}
TEST_F(ProfileOAuth2TokenServiceIOSDelegateTest,
ReloadCredentialsIgnoredIfNoPrimaryAccountId) {
ProviderAccount account1 = fake_provider_->AddAccount("gaia_1", "email_1@x");
ProviderAccount account2 = fake_provider_->AddAccount("gaia_2", "email_2@x");
oauth2_delegate_->ReloadCredentials();
EXPECT_EQ(0, token_available_count_);
EXPECT_EQ(0, tokens_loaded_count_);
EXPECT_EQ(0, token_revoked_count_);
EXPECT_EQ(0U, oauth2_delegate_->GetAccounts().size());
EXPECT_FALSE(
oauth2_delegate_->RefreshTokenIsAvailable(GetAccountId(account1)));
EXPECT_FALSE(
oauth2_delegate_->RefreshTokenIsAvailable(GetAccountId(account2)));
}
TEST_F(ProfileOAuth2TokenServiceIOSDelegateTest,
ReloadCredentialsWithPrimaryAccountId) {
ProviderAccount account1 = fake_provider_->AddAccount("gaia_1", "email_1@x");
ProviderAccount account2 = fake_provider_->AddAccount("gaia_2", "email_2@x");
oauth2_delegate_->ReloadCredentials(GetAccountId(account1));
EXPECT_EQ(2, token_available_count_);
EXPECT_EQ(0, tokens_loaded_count_);
EXPECT_EQ(0, token_revoked_count_);
EXPECT_EQ(2U, oauth2_delegate_->GetAccounts().size());
EXPECT_TRUE(
oauth2_delegate_->RefreshTokenIsAvailable(GetAccountId(account1)));
EXPECT_TRUE(
oauth2_delegate_->RefreshTokenIsAvailable(GetAccountId(account2)));
}
TEST_F(ProfileOAuth2TokenServiceIOSDelegateTest, StartRequestSuccess) {
ProviderAccount account1 = fake_provider_->AddAccount("gaia_1", "email_1@x");
oauth2_delegate_->LoadCredentials(GetAccountId(account1));
base::RunLoop().RunUntilIdle();
// Fetch access tokens.
ResetObserverCounts();
std::vector<std::string> scopes;
scopes.push_back("scope");
std::unique_ptr<OAuth2AccessTokenFetcher> fetcher1(
oauth2_delegate_->CreateAccessTokenFetcher(
GetAccountId(account1), oauth2_delegate_->GetURLLoaderFactory(),
this));
fetcher1->Start("foo", "bar", scopes);
EXPECT_EQ(0, access_token_success_);
EXPECT_EQ(0, access_token_failure_);
ResetObserverCounts();
fake_provider_->IssueAccessTokenForAllRequests();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, access_token_success_);
EXPECT_EQ(0, access_token_failure_);
}
TEST_F(ProfileOAuth2TokenServiceIOSDelegateTest, StartRequestFailure) {
ProviderAccount account1 = fake_provider_->AddAccount("gaia_1", "email_1@x");
oauth2_delegate_->LoadCredentials(GetAccountId(account1));
base::RunLoop().RunUntilIdle();
// Fetch access tokens.
ResetObserverCounts();
std::vector<std::string> scopes;
scopes.push_back("scope");
std::unique_ptr<OAuth2AccessTokenFetcher> fetcher1(
oauth2_delegate_->CreateAccessTokenFetcher(
GetAccountId(account1), oauth2_delegate_->GetURLLoaderFactory(),
this));
fetcher1->Start("foo", "bar", scopes);
EXPECT_EQ(0, access_token_success_);
EXPECT_EQ(0, access_token_failure_);
ResetObserverCounts();
fake_provider_->IssueAccessTokenErrorForAllRequests();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(0, access_token_success_);
EXPECT_EQ(1, access_token_failure_);
}
// Verifies that UpdateAuthError does nothing after the credentials have been
// revoked.
TEST_F(ProfileOAuth2TokenServiceIOSDelegateTest,
UpdateAuthErrorAfterRevokeCredentials) {
ProviderAccount account1 = fake_provider_->AddAccount("gaia_1", "email_1@x");
oauth2_delegate_->ReloadCredentials(GetAccountId(account1));
base::RunLoop().RunUntilIdle();
ResetObserverCounts();
GoogleServiceAuthError error(GoogleServiceAuthError::SERVICE_ERROR);
oauth2_delegate_->UpdateAuthError(GetAccountId(account1), error);
EXPECT_EQ(error, oauth2_delegate_->GetAuthError("gaia_1"));
EXPECT_EQ(1, auth_error_changed_count_);
EXPECT_EQ(1, error_changed_count_);
oauth2_delegate_->RevokeAllCredentials();
ResetObserverCounts();
oauth2_delegate_->UpdateAuthError(GetAccountId(account1), error);
EXPECT_EQ(0, auth_error_changed_count_);
EXPECT_EQ(0, error_changed_count_);
}
TEST_F(ProfileOAuth2TokenServiceIOSDelegateTest, GetAuthError) {
// Accounts have no error by default.
ProviderAccount account1 = fake_provider_->AddAccount("gaia_1", "email_1@x");
oauth2_delegate_->ReloadCredentials(GetAccountId(account1));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
oauth2_delegate_->GetAuthError("gaia_1"));
// Update the error.
GoogleServiceAuthError error =
GoogleServiceAuthError::FromInvalidGaiaCredentialsReason(
GoogleServiceAuthError::InvalidGaiaCredentialsReason::
CREDENTIALS_REJECTED_BY_SERVER);
oauth2_delegate_->UpdateAuthError("gaia_1", error);
EXPECT_EQ(error, oauth2_delegate_->GetAuthError("gaia_1"));
// Unknown account has no error.
EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
oauth2_delegate_->GetAuthError("gaia_2"));
}