blob: d75fefd879e045c0025d18f6d70443f40b0d8c7c [file] [log] [blame]
// Copyright 2017 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 "base/run_loop.h"
#include "build/build_config.h"
#include "components/signin/core/browser/account_info.h"
#include "components/signin/core/browser/account_tracker_service.h"
#include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
#include "components/signin/core/browser/fake_signin_manager.h"
#include "components/signin/core/browser/test_signin_client.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "google_apis/gaia/fake_oauth2_token_service_delegate.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "services/identity/identity_service.h"
#include "services/identity/public/cpp/account_state.h"
#include "services/identity/public/cpp/scope_set.h"
#include "services/identity/public/interfaces/constants.mojom.h"
#include "services/identity/public/interfaces/identity_manager.mojom.h"
#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/service_context.h"
#include "services/service_manager/public/cpp/service_test.h"
#include "services/service_manager/public/interfaces/service_factory.mojom.h"
namespace identity {
namespace {
#if defined(OS_CHROMEOS)
using SigninManagerForTest = FakeSigninManagerBase;
#else
using SigninManagerForTest = FakeSigninManager;
#endif // OS_CHROMEOS
const char kTestGaiaId[] = "dummyId";
const char kTestEmail[] = "me@dummy.com";
const char kSecondaryTestGaiaId[] = "secondaryDummyId";
const char kSecondaryTestEmail[] = "metoo@dummy.com";
const char kTestRefreshToken[] = "dummy-refresh-token";
const char kTestAccessToken[] = "access_token";
class ServiceTestClient : public service_manager::test::ServiceTestClient,
public service_manager::mojom::ServiceFactory {
public:
ServiceTestClient(service_manager::test::ServiceTest* test,
AccountTrackerService* account_tracker,
SigninManagerBase* signin_manager,
ProfileOAuth2TokenService* token_service)
: service_manager::test::ServiceTestClient(test),
account_tracker_(account_tracker),
signin_manager_(signin_manager),
token_service_(token_service) {
registry_.AddInterface<service_manager::mojom::ServiceFactory>(
base::BindRepeating(&ServiceTestClient::Create,
base::Unretained(this)));
}
protected:
void OnBindInterface(const service_manager::BindSourceInfo& source_info,
const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe) override {
registry_.BindInterface(interface_name, std::move(interface_pipe));
}
void CreateService(
service_manager::mojom::ServiceRequest request,
const std::string& name,
service_manager::mojom::PIDReceiverPtr pid_receiver) override {
if (name == mojom::kServiceName) {
identity_service_context_.reset(new service_manager::ServiceContext(
std::make_unique<IdentityService>(account_tracker_, signin_manager_,
token_service_),
std::move(request)));
}
}
void Create(service_manager::mojom::ServiceFactoryRequest request) {
service_factory_bindings_.AddBinding(this, std::move(request));
}
private:
AccountTrackerService* account_tracker_;
SigninManagerBase* signin_manager_;
ProfileOAuth2TokenService* token_service_;
service_manager::BinderRegistry registry_;
mojo::BindingSet<service_manager::mojom::ServiceFactory>
service_factory_bindings_;
std::unique_ptr<service_manager::ServiceContext> identity_service_context_;
};
class IdentityManagerImplTest : public service_manager::test::ServiceTest {
public:
IdentityManagerImplTest()
: ServiceTest("identity_unittests"),
signin_client_(&pref_service_),
#if defined(OS_CHROMEOS)
signin_manager_(&signin_client_, &account_tracker_) {
#else
signin_manager_(&signin_client_,
&token_service_,
&account_tracker_,
nullptr) {
#endif
AccountTrackerService::RegisterPrefs(pref_service_.registry());
SigninManagerBase::RegisterProfilePrefs(pref_service_.registry());
SigninManagerBase::RegisterPrefs(pref_service_.registry());
account_tracker_.Initialize(&signin_client_);
}
void TearDown() override {
// Shut down the SigninManager so that the IdentityManagerImpl doesn't end
// up outliving it.
signin_manager_.Shutdown();
ServiceTest::TearDown();
}
void OnReceivedPrimaryAccountInfo(
base::RepeatingClosure quit_closure,
const base::Optional<AccountInfo>& account_info,
const AccountState& account_state) {
primary_account_info_ = account_info;
primary_account_state_ = account_state;
quit_closure.Run();
}
void OnPrimaryAccountAvailable(base::RepeatingClosure quit_closure,
AccountInfo* caller_account_info,
AccountState* caller_account_state,
const AccountInfo& account_info,
const AccountState& account_state) {
*caller_account_info = account_info;
*caller_account_state = account_state;
quit_closure.Run();
}
void OnReceivedAccountInfoFromGaiaId(
base::RepeatingClosure quit_closure,
const base::Optional<AccountInfo>& account_info,
const AccountState& account_state) {
account_info_from_gaia_id_ = account_info;
account_state_from_gaia_id_ = account_state;
quit_closure.Run();
}
void OnGotAccounts(base::RepeatingClosure quit_closure,
std::vector<mojom::AccountPtr>* output,
std::vector<mojom::AccountPtr> accounts) {
*output = std::move(accounts);
quit_closure.Run();
}
void OnReceivedAccessToken(base::RepeatingClosure quit_closure,
const base::Optional<std::string>& access_token,
base::Time expiration_time,
const GoogleServiceAuthError& error) {
access_token_ = access_token;
access_token_error_ = error;
quit_closure.Run();
}
protected:
void SetUp() override { ServiceTest::SetUp(); }
mojom::IdentityManager* GetIdentityManagerImpl() {
if (!identity_manager_)
connector()->BindInterface(mojom::kServiceName, &identity_manager_);
return identity_manager_.get();
}
void ResetIdentityManagerImpl() { identity_manager_.reset(); }
void FlushIdentityManagerImplForTesting() {
GetIdentityManagerImpl();
identity_manager_.FlushForTesting();
}
void SetIdentityManagerImplConnectionErrorHandler(
base::RepeatingClosure handler) {
GetIdentityManagerImpl();
identity_manager_.set_connection_error_handler(handler);
}
// service_manager::test::ServiceTest:
std::unique_ptr<service_manager::Service> CreateService() override {
return std::make_unique<ServiceTestClient>(
this, &account_tracker_, &signin_manager_, &token_service_);
}
mojom::IdentityManagerPtr identity_manager_;
base::Optional<AccountInfo> primary_account_info_;
AccountState primary_account_state_;
base::Optional<AccountInfo> account_info_from_gaia_id_;
AccountState account_state_from_gaia_id_;
base::Optional<std::string> access_token_;
GoogleServiceAuthError access_token_error_;
AccountTrackerService* account_tracker() { return &account_tracker_; }
SigninManagerBase* signin_manager() { return &signin_manager_; }
FakeProfileOAuth2TokenService* token_service() { return &token_service_; }
private:
sync_preferences::TestingPrefServiceSyncable pref_service_;
AccountTrackerService account_tracker_;
TestSigninClient signin_client_;
SigninManagerForTest signin_manager_;
FakeProfileOAuth2TokenService token_service_;
DISALLOW_COPY_AND_ASSIGN(IdentityManagerImplTest);
};
// Tests that it is not possible to connect to the Identity Manager if
// initiated after SigninManager shutdown.
TEST_F(IdentityManagerImplTest, SigninManagerShutdownBeforeConnection) {
AccountInfo sentinel;
sentinel.account_id = "sentinel";
primary_account_info_ = sentinel;
// Ensure that the Identity Service has actually been created before
// invoking SigninManagerBase::Shutdown(), since otherwise this test will
// spin forever. Then reset the Identity Manager so that the next request
// makes a fresh connection.
FlushIdentityManagerImplForTesting();
ResetIdentityManagerImpl();
// Make a call to connect to the IdentityManagerImpl *after* SigninManager
// shutdown; it should get notified of an error when the Identity Service
// drops the connection.
signin_manager()->Shutdown();
base::RunLoop run_loop;
SetIdentityManagerImplConnectionErrorHandler(run_loop.QuitClosure());
GetIdentityManagerImpl()->GetPrimaryAccountInfo(base::BindRepeating(
&IdentityManagerImplTest::OnReceivedPrimaryAccountInfo,
base::Unretained(this), run_loop.QuitClosure()));
run_loop.Run();
// Verify that the callback to GetPrimaryAccountInfo() was not invoked.
EXPECT_TRUE(primary_account_info_);
EXPECT_EQ("sentinel", primary_account_info_->account_id);
}
// Tests that the Identity Manager destroys itself on SigninManager shutdown.
TEST_F(IdentityManagerImplTest, SigninManagerShutdownAfterConnection) {
base::RunLoop run_loop;
SetIdentityManagerImplConnectionErrorHandler(run_loop.QuitClosure());
// Ensure that the IdentityManagerImpl instance has actually been created
// before invoking SigninManagerBase::Shutdown(), since otherwise this test
// will spin forever.
FlushIdentityManagerImplForTesting();
signin_manager()->Shutdown();
run_loop.Run();
}
// Tests that the Identity Manager properly handles its own destruction in the
// case where there is an active consumer request (i.e., a pending callback from
// a Mojo call). In particular, this flow should not cause a DCHECK to fire in
// debug mode.
TEST_F(IdentityManagerImplTest, IdentityManagerImplShutdownWithActiveRequest) {
base::RunLoop run_loop;
SetIdentityManagerImplConnectionErrorHandler(run_loop.QuitClosure());
// Call a method on the IdentityManagerImpl that will cause it to store a
// pending callback. This callback will never be invoked, so just pass dummy
// arguments to it.
GetIdentityManagerImpl()->GetPrimaryAccountWhenAvailable(base::BindRepeating(
&IdentityManagerImplTest::OnPrimaryAccountAvailable,
base::Unretained(this), base::RepeatingClosure(), nullptr, nullptr));
// Ensure that the IdentityManagerImpl has received the above call before
// invoking SigninManagerBase::Shutdown(), as otherwise this test is
// pointless.
FlushIdentityManagerImplForTesting();
// This flow is what would cause a DCHECK to fire if IdentityManagerImpl is
// not properly closing its binding on shutdown.
signin_manager()->Shutdown();
run_loop.Run();
}
// Check that the primary account info is null if not signed in.
TEST_F(IdentityManagerImplTest, GetPrimaryAccountInfoNotSignedIn) {
base::RunLoop run_loop;
GetIdentityManagerImpl()->GetPrimaryAccountInfo(base::BindRepeating(
&IdentityManagerImplTest::OnReceivedPrimaryAccountInfo,
base::Unretained(this), run_loop.QuitClosure()));
run_loop.Run();
EXPECT_FALSE(primary_account_info_);
}
// Check that the primary account info has expected values if signed in without
// a refresh token available.
TEST_F(IdentityManagerImplTest, GetPrimaryAccountInfoSignedInNoRefreshToken) {
signin_manager()->SetAuthenticatedAccountInfo(kTestGaiaId, kTestEmail);
base::RunLoop run_loop;
GetIdentityManagerImpl()->GetPrimaryAccountInfo(base::BindRepeating(
&IdentityManagerImplTest::OnReceivedPrimaryAccountInfo,
base::Unretained(this), run_loop.QuitClosure()));
run_loop.Run();
EXPECT_TRUE(primary_account_info_);
EXPECT_EQ(signin_manager()->GetAuthenticatedAccountId(),
primary_account_info_->account_id);
EXPECT_EQ(kTestGaiaId, primary_account_info_->gaia);
EXPECT_EQ(kTestEmail, primary_account_info_->email);
EXPECT_FALSE(primary_account_state_.has_refresh_token);
EXPECT_TRUE(primary_account_state_.is_primary_account);
}
// Check that the primary account info has expected values if signed in with a
// refresh token available.
TEST_F(IdentityManagerImplTest, GetPrimaryAccountInfoSignedInRefreshToken) {
signin_manager()->SetAuthenticatedAccountInfo(kTestGaiaId, kTestEmail);
token_service()->UpdateCredentials(
signin_manager()->GetAuthenticatedAccountId(), kTestRefreshToken);
base::RunLoop run_loop;
GetIdentityManagerImpl()->GetPrimaryAccountInfo(base::BindRepeating(
&IdentityManagerImplTest::OnReceivedPrimaryAccountInfo,
base::Unretained(this), run_loop.QuitClosure()));
run_loop.Run();
EXPECT_TRUE(primary_account_info_);
EXPECT_EQ(signin_manager()->GetAuthenticatedAccountId(),
primary_account_info_->account_id);
EXPECT_EQ(kTestGaiaId, primary_account_info_->gaia);
EXPECT_EQ(kTestEmail, primary_account_info_->email);
EXPECT_TRUE(primary_account_state_.has_refresh_token);
EXPECT_TRUE(primary_account_state_.is_primary_account);
}
// Check that GetPrimaryAccountWhenAvailable() returns immediately in the
// case where the primary account is available when the call is received.
TEST_F(IdentityManagerImplTest, GetPrimaryAccountWhenAvailableSignedIn) {
signin_manager()->SetAuthenticatedAccountInfo(kTestGaiaId, kTestEmail);
token_service()->UpdateCredentials(
signin_manager()->GetAuthenticatedAccountId(), kTestRefreshToken);
AccountInfo account_info;
AccountState account_state;
base::RunLoop run_loop;
GetIdentityManagerImpl()->GetPrimaryAccountWhenAvailable(base::BindRepeating(
&IdentityManagerImplTest::OnPrimaryAccountAvailable,
base::Unretained(this), run_loop.QuitClosure(),
base::Unretained(&account_info), base::Unretained(&account_state)));
run_loop.Run();
EXPECT_EQ(signin_manager()->GetAuthenticatedAccountId(),
account_info.account_id);
EXPECT_EQ(kTestGaiaId, account_info.gaia);
EXPECT_EQ(kTestEmail, account_info.email);
EXPECT_TRUE(account_state.has_refresh_token);
EXPECT_TRUE(account_state.is_primary_account);
}
// Check that GetPrimaryAccountWhenAvailable() returns the expected account
// info in the case where the primary account is made available *after* the
// call is received.
TEST_F(IdentityManagerImplTest, GetPrimaryAccountWhenAvailableSignInLater) {
AccountInfo account_info;
AccountState account_state;
base::RunLoop run_loop;
GetIdentityManagerImpl()->GetPrimaryAccountWhenAvailable(base::BindRepeating(
&IdentityManagerImplTest::OnPrimaryAccountAvailable,
base::Unretained(this), run_loop.QuitClosure(),
base::Unretained(&account_info), base::Unretained(&account_state)));
// Verify that the primary account info is not currently available (this also
// serves to ensure that the preceding call has been received by the Identity
// Manager before proceeding).
base::RunLoop run_loop2;
GetIdentityManagerImpl()->GetPrimaryAccountInfo(base::BindRepeating(
&IdentityManagerImplTest::OnReceivedPrimaryAccountInfo,
base::Unretained(this), run_loop2.QuitClosure()));
run_loop2.Run();
EXPECT_FALSE(primary_account_info_);
// Make the primary account available and check that the callback is invoked
// as expected.
signin_manager()->SetAuthenticatedAccountInfo(kTestGaiaId, kTestEmail);
token_service()->UpdateCredentials(
signin_manager()->GetAuthenticatedAccountId(), kTestRefreshToken);
run_loop.Run();
EXPECT_EQ(signin_manager()->GetAuthenticatedAccountId(),
account_info.account_id);
EXPECT_EQ(kTestGaiaId, account_info.gaia);
EXPECT_EQ(kTestEmail, account_info.email);
EXPECT_TRUE(account_state.has_refresh_token);
EXPECT_TRUE(account_state.is_primary_account);
}
// Check that GetPrimaryAccountWhenAvailable() returns the expected account
// info in the case where signin is done before the call is received but the
// refresh token is made available only *after* the call is received.
TEST_F(IdentityManagerImplTest,
GetPrimaryAccountWhenAvailableTokenAvailableLater) {
AccountInfo account_info;
AccountState account_state;
// Sign in, but don't set the refresh token yet.
signin_manager()->SetAuthenticatedAccountInfo(kTestGaiaId, kTestEmail);
base::RunLoop run_loop;
GetIdentityManagerImpl()->GetPrimaryAccountWhenAvailable(base::BindRepeating(
&IdentityManagerImplTest::OnPrimaryAccountAvailable,
base::Unretained(this), run_loop.QuitClosure(),
base::Unretained(&account_info), base::Unretained(&account_state)));
// Verify that the primary account info is present, but that the primary
// account is not yet considered available (this also
// serves to ensure that the preceding call has been received by the Identity
// Manager before proceeding).
base::RunLoop run_loop2;
GetIdentityManagerImpl()->GetPrimaryAccountInfo(base::BindRepeating(
&IdentityManagerImplTest::OnReceivedPrimaryAccountInfo,
base::Unretained(this), run_loop2.QuitClosure()));
run_loop2.Run();
EXPECT_TRUE(primary_account_info_);
EXPECT_EQ(signin_manager()->GetAuthenticatedAccountId(),
primary_account_info_->account_id);
EXPECT_TRUE(account_info.account_id.empty());
// Set the refresh token and check that the callback is invoked as expected
// (i.e., the primary account is now considered available).
token_service()->UpdateCredentials(
signin_manager()->GetAuthenticatedAccountId(), kTestRefreshToken);
run_loop.Run();
EXPECT_EQ(signin_manager()->GetAuthenticatedAccountId(),
account_info.account_id);
EXPECT_EQ(kTestGaiaId, account_info.gaia);
EXPECT_EQ(kTestEmail, account_info.email);
EXPECT_TRUE(account_state.has_refresh_token);
EXPECT_TRUE(account_state.is_primary_account);
}
// Check that GetPrimaryAccountWhenAvailable() returns the expected account info
// in the case where the token is available before the call is received but the
// account is made authenticated only *after* the call is received. This test is
// relevant only on non-ChromeOS platforms, as the flow being tested here is not
// possible on ChromeOS.
#if !defined(OS_CHROMEOS)
TEST_F(IdentityManagerImplTest,
GetPrimaryAccountWhenAvailableAuthenticationAvailableLater) {
AccountInfo account_info;
AccountState account_state;
// Set the refresh token, but don't sign in yet.
std::string account_id_to_use =
account_tracker()->SeedAccountInfo(kTestGaiaId, kTestEmail);
token_service()->UpdateCredentials(account_id_to_use, kTestRefreshToken);
base::RunLoop run_loop;
GetIdentityManagerImpl()->GetPrimaryAccountWhenAvailable(base::BindRepeating(
&IdentityManagerImplTest::OnPrimaryAccountAvailable,
base::Unretained(this), run_loop.QuitClosure(),
base::Unretained(&account_info), base::Unretained(&account_state)));
// Verify that the account is present and has a refresh token, but that the
// primary account is not yet considered available (this also serves to ensure
// that the preceding call has been received by the Identity Manager before
// proceeding).
base::RunLoop run_loop2;
GetIdentityManagerImpl()->GetAccountInfoFromGaiaId(
kTestGaiaId,
base::BindRepeating(
&IdentityManagerImplTest::OnReceivedAccountInfoFromGaiaId,
base::Unretained(this), run_loop2.QuitClosure()));
run_loop2.Run();
EXPECT_TRUE(account_info_from_gaia_id_);
EXPECT_EQ(account_id_to_use, account_info_from_gaia_id_->account_id);
EXPECT_EQ(kTestGaiaId, account_info_from_gaia_id_->gaia);
EXPECT_EQ(kTestEmail, account_info_from_gaia_id_->email);
EXPECT_TRUE(account_state_from_gaia_id_.has_refresh_token);
EXPECT_FALSE(account_state_from_gaia_id_.is_primary_account);
EXPECT_TRUE(account_info.account_id.empty());
// Sign the user in and check that the callback is invoked as expected (i.e.,
// the primary account is now considered available). Note that it is necessary
// to call SignIn() here to ensure that GoogleSigninSucceeded() is fired by
// the fake signin manager.
static_cast<FakeSigninManager*>(signin_manager())
->SignIn(kTestGaiaId, kTestEmail, "password");
run_loop.Run();
EXPECT_EQ(signin_manager()->GetAuthenticatedAccountId(),
account_info.account_id);
EXPECT_EQ(kTestGaiaId, account_info.gaia);
EXPECT_EQ(kTestEmail, account_info.email);
EXPECT_TRUE(account_state.has_refresh_token);
EXPECT_TRUE(account_state.is_primary_account);
}
#endif
// Check that GetPrimaryAccountWhenAvailable() returns the expected account
// info to all callers in the case where the primary account is made available
// after multiple overlapping calls have been received.
TEST_F(IdentityManagerImplTest,
GetPrimaryAccountWhenAvailableOverlappingCalls) {
AccountInfo account_info1;
AccountState account_state1;
base::RunLoop run_loop;
GetIdentityManagerImpl()->GetPrimaryAccountWhenAvailable(base::BindRepeating(
&IdentityManagerImplTest::OnPrimaryAccountAvailable,
base::Unretained(this), run_loop.QuitClosure(),
base::Unretained(&account_info1), base::Unretained(&account_state1)));
AccountInfo account_info2;
AccountState account_state2;
base::RunLoop run_loop2;
GetIdentityManagerImpl()->GetPrimaryAccountWhenAvailable(base::BindRepeating(
&IdentityManagerImplTest::OnPrimaryAccountAvailable,
base::Unretained(this), run_loop2.QuitClosure(),
base::Unretained(&account_info2), base::Unretained(&account_state2)));
// Verify that the primary account info is not currently available (this also
// serves to ensure that the preceding call has been received by the Identity
// Manager before proceeding).
base::RunLoop run_loop3;
GetIdentityManagerImpl()->GetPrimaryAccountInfo(base::BindRepeating(
&IdentityManagerImplTest::OnReceivedPrimaryAccountInfo,
base::Unretained(this), run_loop3.QuitClosure()));
run_loop3.Run();
EXPECT_FALSE(primary_account_info_);
// Make the primary account available and check that the callbacks are invoked
// as expected.
signin_manager()->SetAuthenticatedAccountInfo(kTestGaiaId, kTestEmail);
token_service()->UpdateCredentials(
signin_manager()->GetAuthenticatedAccountId(), kTestRefreshToken);
run_loop.Run();
run_loop2.Run();
EXPECT_EQ(signin_manager()->GetAuthenticatedAccountId(),
account_info1.account_id);
EXPECT_EQ(kTestGaiaId, account_info1.gaia);
EXPECT_EQ(kTestEmail, account_info1.email);
EXPECT_TRUE(account_state1.has_refresh_token);
EXPECT_TRUE(account_state1.is_primary_account);
EXPECT_EQ(signin_manager()->GetAuthenticatedAccountId(),
account_info2.account_id);
EXPECT_EQ(kTestGaiaId, account_info2.gaia);
EXPECT_EQ(kTestEmail, account_info2.email);
EXPECT_TRUE(account_state2.has_refresh_token);
EXPECT_TRUE(account_state2.is_primary_account);
}
// Check that GetPrimaryAccountWhenAvailable() doesn't return the account as
// available if the refresh token has an auth error.
TEST_F(IdentityManagerImplTest,
GetPrimaryAccountWhenAvailableRefreshTokenHasAuthError) {
signin_manager()->SetAuthenticatedAccountInfo(kTestGaiaId, kTestEmail);
token_service()->UpdateCredentials(
signin_manager()->GetAuthenticatedAccountId(), kTestRefreshToken);
FakeOAuth2TokenServiceDelegate* delegate =
static_cast<FakeOAuth2TokenServiceDelegate*>(
token_service()->GetDelegate());
delegate->SetLastErrorForAccount(
signin_manager()->GetAuthenticatedAccountId(),
GoogleServiceAuthError(
GoogleServiceAuthError::State::INVALID_GAIA_CREDENTIALS));
AccountInfo account_info;
AccountState account_state;
base::RunLoop run_loop;
GetIdentityManagerImpl()->GetPrimaryAccountWhenAvailable(base::BindRepeating(
&IdentityManagerImplTest::OnPrimaryAccountAvailable,
base::Unretained(this), run_loop.QuitClosure(),
base::Unretained(&account_info), base::Unretained(&account_state)));
// Flush the Identity Manager and check that the callback didn't fire.
FlushIdentityManagerImplForTesting();
EXPECT_TRUE(account_info.account_id.empty());
// Clear the auth error, update credentials, and check that the callback
// fires.
delegate->SetLastErrorForAccount(
signin_manager()->GetAuthenticatedAccountId(), GoogleServiceAuthError());
token_service()->UpdateCredentials(
signin_manager()->GetAuthenticatedAccountId(), kTestRefreshToken);
run_loop.Run();
EXPECT_EQ(signin_manager()->GetAuthenticatedAccountId(),
account_info.account_id);
EXPECT_EQ(kTestGaiaId, account_info.gaia);
EXPECT_EQ(kTestEmail, account_info.email);
EXPECT_TRUE(account_state.has_refresh_token);
EXPECT_TRUE(account_state.is_primary_account);
}
// Check that the account info for a given GAIA ID is null if that GAIA ID is
// unknown.
TEST_F(IdentityManagerImplTest, GetAccountInfoForUnknownGaiaID) {
base::RunLoop run_loop;
GetIdentityManagerImpl()->GetAccountInfoFromGaiaId(
kTestGaiaId,
base::BindRepeating(
&IdentityManagerImplTest::OnReceivedAccountInfoFromGaiaId,
base::Unretained(this), run_loop.QuitClosure()));
run_loop.Run();
EXPECT_FALSE(account_info_from_gaia_id_);
}
// Check that the account info for a given GAIA ID has expected values if that
// GAIA ID is known and there is no refresh token available for it.
TEST_F(IdentityManagerImplTest, GetAccountInfoForKnownGaiaIdNoRefreshToken) {
std::string account_id =
account_tracker()->SeedAccountInfo(kTestGaiaId, kTestEmail);
base::RunLoop run_loop;
GetIdentityManagerImpl()->GetAccountInfoFromGaiaId(
kTestGaiaId,
base::BindRepeating(
&IdentityManagerImplTest::OnReceivedAccountInfoFromGaiaId,
base::Unretained(this), run_loop.QuitClosure()));
run_loop.Run();
EXPECT_TRUE(account_info_from_gaia_id_);
EXPECT_EQ(account_id, account_info_from_gaia_id_->account_id);
EXPECT_EQ(kTestGaiaId, account_info_from_gaia_id_->gaia);
EXPECT_EQ(kTestEmail, account_info_from_gaia_id_->email);
EXPECT_FALSE(account_state_from_gaia_id_.has_refresh_token);
EXPECT_FALSE(account_state_from_gaia_id_.is_primary_account);
}
// Check that the account info for a given GAIA ID has expected values if that
// GAIA ID is known and has a refresh token available.
TEST_F(IdentityManagerImplTest, GetAccountInfoForKnownGaiaIdRefreshToken) {
std::string account_id =
account_tracker()->SeedAccountInfo(kTestGaiaId, kTestEmail);
token_service()->UpdateCredentials(account_id, kTestRefreshToken);
base::RunLoop run_loop;
GetIdentityManagerImpl()->GetAccountInfoFromGaiaId(
kTestGaiaId,
base::BindRepeating(
&IdentityManagerImplTest::OnReceivedAccountInfoFromGaiaId,
base::Unretained(this), run_loop.QuitClosure()));
run_loop.Run();
EXPECT_TRUE(account_info_from_gaia_id_);
EXPECT_EQ(account_id, account_info_from_gaia_id_->account_id);
EXPECT_EQ(kTestGaiaId, account_info_from_gaia_id_->gaia);
EXPECT_EQ(kTestEmail, account_info_from_gaia_id_->email);
EXPECT_TRUE(account_state_from_gaia_id_.has_refresh_token);
EXPECT_FALSE(account_state_from_gaia_id_.is_primary_account);
}
// Check the implementation of GetAccounts() when there are no accounts.
TEST_F(IdentityManagerImplTest, GetAccountsNoAccount) {
token_service()->LoadCredentials("dummy");
std::vector<mojom::AccountPtr> accounts;
// Check that an empty list is returned when there are no accounts.
base::RunLoop run_loop;
GetIdentityManagerImpl()->GetAccounts(base::BindRepeating(
&IdentityManagerImplTest::OnGotAccounts, base::Unretained(this),
run_loop.QuitClosure(), &accounts));
run_loop.Run();
EXPECT_EQ(0u, accounts.size());
}
// Check the implementation of GetAccounts() when there is a single account,
// which is the primary account.
TEST_F(IdentityManagerImplTest, GetAccountsPrimaryAccount) {
token_service()->LoadCredentials("dummy");
std::vector<mojom::AccountPtr> accounts;
// Add a primary account.
signin_manager()->SetAuthenticatedAccountInfo(kTestGaiaId, kTestEmail);
token_service()->UpdateCredentials(
signin_manager()->GetAuthenticatedAccountId(), kTestRefreshToken);
base::RunLoop run_loop;
GetIdentityManagerImpl()->GetAccounts(base::BindRepeating(
&IdentityManagerImplTest::OnGotAccounts, base::Unretained(this),
run_loop.QuitClosure(), &accounts));
run_loop.Run();
// Verify that |accounts| contains the primary account.
EXPECT_EQ(1u, accounts.size());
const mojom::AccountPtr& primary_account = accounts[0];
EXPECT_EQ(signin_manager()->GetAuthenticatedAccountId(),
primary_account->info.account_id);
EXPECT_EQ(kTestGaiaId, primary_account->info.gaia);
EXPECT_EQ(kTestEmail, primary_account->info.email);
EXPECT_TRUE(primary_account->state.has_refresh_token);
EXPECT_TRUE(primary_account->state.is_primary_account);
}
// Check the implementation of GetAccounts() when there are multiple accounts,
// in particular that ProfileOAuth2TokenService is the source of truth for
// whether an account is present.
TEST_F(IdentityManagerImplTest, GetAccountsMultipleAccounts) {
token_service()->LoadCredentials("dummy");
std::vector<mojom::AccountPtr> accounts;
// Add a primary account.
signin_manager()->SetAuthenticatedAccountInfo(kTestGaiaId, kTestEmail);
token_service()->UpdateCredentials(
signin_manager()->GetAuthenticatedAccountId(), kTestRefreshToken);
// Add a secondary account with AccountTrackerService, but don't yet make
// ProfileOAuth2TokenService aware of it.
std::string secondary_account_id = account_tracker()->SeedAccountInfo(
kSecondaryTestGaiaId, kSecondaryTestEmail);
base::RunLoop run_loop;
GetIdentityManagerImpl()->GetAccounts(base::BindRepeating(
&IdentityManagerImplTest::OnGotAccounts, base::Unretained(this),
run_loop.QuitClosure(), &accounts));
run_loop.Run();
// Verify that |accounts| contains only the primary account at this time.
EXPECT_EQ(1u, accounts.size());
const mojom::AccountPtr& primary_account = accounts[0];
EXPECT_EQ(signin_manager()->GetAuthenticatedAccountId(),
primary_account->info.account_id);
EXPECT_EQ(kTestGaiaId, primary_account->info.gaia);
EXPECT_EQ(kTestEmail, primary_account->info.email);
EXPECT_TRUE(primary_account->state.has_refresh_token);
EXPECT_TRUE(primary_account->state.is_primary_account);
// Make PO2TS aware of the secondary account.
token_service()->UpdateCredentials(secondary_account_id, kTestRefreshToken);
base::RunLoop run_loop2;
GetIdentityManagerImpl()->GetAccounts(base::BindRepeating(
&IdentityManagerImplTest::OnGotAccounts, base::Unretained(this),
run_loop2.QuitClosure(), &accounts));
run_loop2.Run();
// Verify that |accounts| contains both accounts, with the primary account
// being first and having the same information as previously.
EXPECT_EQ(2u, accounts.size());
const mojom::AccountPtr& primary_account_redux = accounts[0];
EXPECT_EQ(signin_manager()->GetAuthenticatedAccountId(),
primary_account_redux->info.account_id);
EXPECT_EQ(kTestGaiaId, primary_account_redux->info.gaia);
EXPECT_EQ(kTestEmail, primary_account_redux->info.email);
EXPECT_TRUE(primary_account_redux->state.has_refresh_token);
EXPECT_TRUE(primary_account_redux->state.is_primary_account);
const mojom::AccountPtr& secondary_account = accounts[1];
EXPECT_EQ(secondary_account_id, secondary_account->info.account_id);
EXPECT_EQ(kSecondaryTestGaiaId, secondary_account->info.gaia);
EXPECT_EQ(kSecondaryTestEmail, secondary_account->info.email);
EXPECT_TRUE(secondary_account->state.has_refresh_token);
EXPECT_FALSE(secondary_account->state.is_primary_account);
}
// Check that the expected error is received if requesting an access token when
// not signed in.
TEST_F(IdentityManagerImplTest, GetAccessTokenNotSignedIn) {
base::RunLoop run_loop;
GetIdentityManagerImpl()->GetAccessToken(
kTestGaiaId, ScopeSet(), "dummy_consumer",
base::BindRepeating(&IdentityManagerImplTest::OnReceivedAccessToken,
base::Unretained(this), run_loop.QuitClosure()));
run_loop.Run();
EXPECT_FALSE(access_token_);
EXPECT_EQ(GoogleServiceAuthError::State::USER_NOT_SIGNED_UP,
access_token_error_.state());
}
// Check that the expected access token is received if requesting an access
// token when signed in.
TEST_F(IdentityManagerImplTest, GetAccessTokenSignedIn) {
signin_manager()->SetAuthenticatedAccountInfo(kTestGaiaId, kTestEmail);
std::string account_id = signin_manager()->GetAuthenticatedAccountId();
token_service()->UpdateCredentials(account_id, kTestRefreshToken);
token_service()->set_auto_post_fetch_response_on_message_loop(true);
base::RunLoop run_loop;
GetIdentityManagerImpl()->GetAccessToken(
account_id, ScopeSet(), "dummy_consumer",
base::BindRepeating(&IdentityManagerImplTest::OnReceivedAccessToken,
base::Unretained(this), run_loop.QuitClosure()));
run_loop.Run();
EXPECT_TRUE(access_token_);
EXPECT_EQ(kTestAccessToken, access_token_.value());
EXPECT_EQ(GoogleServiceAuthError::State::NONE, access_token_error_.state());
}
} // namespace
} // namespace identity