| // 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 "components/signin/public/identity_manager/identity_manager.h" |
| |
| #include <memory> |
| #include <set> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/bind.h" |
| #include "base/command_line.h" |
| #include "base/containers/flat_set.h" |
| #include "base/files/scoped_temp_dir.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/run_loop.h" |
| #include "base/scoped_observation.h" |
| #include "base/test/bind.h" |
| #include "base/test/task_environment.h" |
| #include "build/build_config.h" |
| #include "build/chromeos_buildflags.h" |
| #include "components/image_fetcher/core/fake_image_decoder.h" |
| #include "components/signin/internal/identity_manager/account_fetcher_service.h" |
| #include "components/signin/internal/identity_manager/account_tracker_service.h" |
| #include "components/signin/internal/identity_manager/accounts_cookie_mutator_impl.h" |
| #include "components/signin/internal/identity_manager/accounts_mutator_impl.h" |
| #include "components/signin/internal/identity_manager/device_accounts_synchronizer_impl.h" |
| #include "components/signin/internal/identity_manager/diagnostics_provider_impl.h" |
| #include "components/signin/internal/identity_manager/fake_profile_oauth2_token_service.h" |
| #include "components/signin/internal/identity_manager/gaia_cookie_manager_service.h" |
| #include "components/signin/internal/identity_manager/primary_account_manager.h" |
| #include "components/signin/internal/identity_manager/primary_account_mutator_impl.h" |
| #include "components/signin/internal/identity_manager/profile_oauth2_token_service_delegate.h" |
| #include "components/signin/public/base/account_consistency_method.h" |
| #include "components/signin/public/base/consent_level.h" |
| #include "components/signin/public/base/list_accounts_test_utils.h" |
| #include "components/signin/public/base/signin_switches.h" |
| #include "components/signin/public/base/test_signin_client.h" |
| #include "components/signin/public/identity_manager/access_token_info.h" |
| #include "components/signin/public/identity_manager/accounts_cookie_mutator.h" |
| #include "components/signin/public/identity_manager/device_accounts_synchronizer.h" |
| #include "components/signin/public/identity_manager/identity_test_utils.h" |
| #include "components/signin/public/identity_manager/scope_set.h" |
| #include "components/signin/public/identity_manager/set_accounts_in_cookie_result.h" |
| #include "components/signin/public/identity_manager/test_identity_manager_observer.h" |
| #include "components/sync_preferences/testing_pref_service_syncable.h" |
| #include "google_apis/gaia/core_account_id.h" |
| #include "google_apis/gaia/gaia_auth_fetcher.h" |
| #include "google_apis/gaia/google_service_auth_error.h" |
| #include "net/cookies/cookie_change_dispatcher.h" |
| #include "net/cookies/cookie_constants.h" |
| #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" |
| #include "services/network/test/test_cookie_manager.h" |
| #include "services/network/test/test_url_loader_factory.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| #if defined(OS_ANDROID) |
| #include "components/signin/internal/identity_manager/child_account_info_fetcher_android.h" |
| #endif |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| #include "ash/components/account_manager/account_manager_factory.h" |
| #include "components/account_manager_core/account.h" |
| #include "components/account_manager_core/account_manager_facade_impl.h" |
| #include "components/account_manager_core/chromeos/account_manager.h" |
| #include "components/account_manager_core/chromeos/account_manager_mojo_service.h" |
| #include "components/signin/internal/identity_manager/test_profile_oauth2_token_service_delegate_chromeos.h" |
| #endif |
| |
| namespace signin { |
| namespace { |
| |
| const char kTestConsumerId[] = "dummy_consumer"; |
| const char kTestConsumerId2[] = "dummy_consumer 2"; |
| const char kTestGaiaId[] = "dummyId"; |
| const char kTestGaiaId2[] = "dummyId2"; |
| const char kTestGaiaId3[] = "dummyId3"; |
| const char kTestEmail[] = "me@gmail.com"; |
| const char kTestEmail2[] = "me2@gmail.com"; |
| const char kTestEmail3[] = "me3@gmail.com"; |
| |
| const char kTestHostedDomain[] = "example.com"; |
| const char kTestFullName[] = "full_name"; |
| const char kTestGivenName[] = "given_name"; |
| const char kTestLocale[] = "locale"; |
| const char kTestPictureUrl[] = "http://picture.example.com/picture.jpg"; |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| const char kTestEmailWithPeriod[] = "m.e@gmail.com"; |
| #endif |
| |
| // Subclass of FakeOAuth2AccessTokenManager with bespoke behavior. |
| class CustomFakeOAuth2AccessTokenManager : public FakeOAuth2AccessTokenManager { |
| public: |
| CustomFakeOAuth2AccessTokenManager( |
| OAuth2AccessTokenManager::Delegate* delegate) |
| : FakeOAuth2AccessTokenManager(delegate) {} |
| |
| void set_on_access_token_invalidated_info( |
| CoreAccountId expected_account_id_to_invalidate, |
| std::set<std::string> expected_scopes_to_invalidate, |
| std::string expected_access_token_to_invalidate, |
| base::OnceClosure callback) { |
| expected_account_id_to_invalidate_ = expected_account_id_to_invalidate; |
| expected_scopes_to_invalidate_ = expected_scopes_to_invalidate; |
| expected_access_token_to_invalidate_ = expected_access_token_to_invalidate; |
| on_access_token_invalidated_callback_ = std::move(callback); |
| } |
| |
| private: |
| friend class CustomFakeProfileOAuth2TokenService; |
| // OAuth2AccessTokenManager: |
| void InvalidateAccessTokenImpl(const CoreAccountId& account_id, |
| const std::string& client_id, |
| const ScopeSet& scopes, |
| const std::string& access_token) override { |
| if (on_access_token_invalidated_callback_) { |
| EXPECT_EQ(expected_account_id_to_invalidate_, account_id); |
| EXPECT_EQ(expected_scopes_to_invalidate_, scopes); |
| EXPECT_EQ(expected_access_token_to_invalidate_, access_token); |
| |
| // It should trigger OnAccessTokenRemovedFromCache from |
| // IdentityManager::DiagnosticsObserver. |
| for (auto& observer : GetDiagnosticsObserversForTesting()) |
| observer.OnAccessTokenRemoved(account_id, scopes); |
| |
| std::move(on_access_token_invalidated_callback_).Run(); |
| } |
| } |
| |
| CoreAccountId expected_account_id_to_invalidate_; |
| std::set<std::string> expected_scopes_to_invalidate_; |
| std::string expected_access_token_to_invalidate_; |
| base::OnceClosure on_access_token_invalidated_callback_; |
| }; |
| |
| // Subclass of FakeProfileOAuth2TokenService with bespoke behavior. |
| class CustomFakeProfileOAuth2TokenService |
| : public FakeProfileOAuth2TokenService { |
| public: |
| explicit CustomFakeProfileOAuth2TokenService(PrefService* user_prefs) |
| : FakeProfileOAuth2TokenService(user_prefs) { |
| OverrideAccessTokenManagerForTesting( |
| std::make_unique<CustomFakeOAuth2AccessTokenManager>( |
| this /* OAuth2AccessTokenManager::Delegate* */)); |
| } |
| |
| CustomFakeProfileOAuth2TokenService( |
| PrefService* user_prefs, |
| std::unique_ptr<ProfileOAuth2TokenServiceDelegate> delegate) |
| : FakeProfileOAuth2TokenService(user_prefs, std::move(delegate)) { |
| OverrideAccessTokenManagerForTesting( |
| std::make_unique<CustomFakeOAuth2AccessTokenManager>( |
| this /* OAuth2AccessTokenManager::Delegate* */)); |
| } |
| |
| void set_on_access_token_invalidated_info( |
| CoreAccountId expected_account_id_to_invalidate, |
| std::set<std::string> expected_scopes_to_invalidate, |
| std::string expected_access_token_to_invalidate, |
| base::OnceClosure callback) { |
| GetCustomAccessTokenManager()->set_on_access_token_invalidated_info( |
| expected_account_id_to_invalidate, expected_scopes_to_invalidate, |
| expected_access_token_to_invalidate, std::move(callback)); |
| } |
| |
| private: |
| CustomFakeOAuth2AccessTokenManager* GetCustomAccessTokenManager() { |
| return static_cast<CustomFakeOAuth2AccessTokenManager*>( |
| GetAccessTokenManager()); |
| } |
| }; |
| |
| class TestIdentityManagerDiagnosticsObserver |
| : IdentityManager::DiagnosticsObserver { |
| public: |
| explicit TestIdentityManagerDiagnosticsObserver( |
| IdentityManager* identity_manager) |
| : identity_manager_(identity_manager) { |
| identity_manager_->AddDiagnosticsObserver(this); |
| } |
| ~TestIdentityManagerDiagnosticsObserver() override { |
| identity_manager_->RemoveDiagnosticsObserver(this); |
| } |
| |
| void set_on_access_token_requested_callback(base::OnceClosure callback) { |
| on_access_token_requested_callback_ = std::move(callback); |
| } |
| |
| void set_on_access_token_request_completed_callback( |
| base::OnceClosure callback) { |
| on_access_token_request_completed_callback_ = std::move(callback); |
| } |
| |
| const CoreAccountId& token_requestor_account_id() { |
| return token_requestor_account_id_; |
| } |
| const std::string& token_requestor_consumer_id() { |
| return token_requestor_consumer_id_; |
| } |
| const ScopeSet& token_requestor_scopes() { return token_requestor_scopes_; } |
| const CoreAccountId& token_remover_account_id() { |
| return token_remover_account_id_; |
| } |
| const ScopeSet& token_remover_scopes() { return token_remover_scopes_; } |
| const CoreAccountId& on_access_token_request_completed_account_id() { |
| return access_token_request_completed_account_id_; |
| } |
| const std::string& on_access_token_request_completed_consumer_id() { |
| return access_token_request_completed_consumer_id_; |
| } |
| const ScopeSet& on_access_token_request_completed_scopes() { |
| return access_token_request_completed_scopes_; |
| } |
| const GoogleServiceAuthError& on_access_token_request_completed_error() { |
| return access_token_request_completed_error_; |
| } |
| |
| private: |
| // IdentityManager::DiagnosticsObserver: |
| void OnAccessTokenRequested(const CoreAccountId& account_id, |
| const std::string& consumer_id, |
| const ScopeSet& scopes) override { |
| token_requestor_account_id_ = account_id; |
| token_requestor_consumer_id_ = consumer_id; |
| token_requestor_scopes_ = scopes; |
| |
| if (on_access_token_requested_callback_) |
| std::move(on_access_token_requested_callback_).Run(); |
| } |
| |
| void OnAccessTokenRemovedFromCache(const CoreAccountId& account_id, |
| const ScopeSet& scopes) override { |
| token_remover_account_id_ = account_id; |
| token_remover_scopes_ = scopes; |
| } |
| |
| void OnAccessTokenRequestCompleted(const CoreAccountId& account_id, |
| const std::string& consumer_id, |
| const ScopeSet& scopes, |
| GoogleServiceAuthError error, |
| base::Time expiration_time) override { |
| access_token_request_completed_account_id_ = account_id; |
| access_token_request_completed_consumer_id_ = consumer_id; |
| access_token_request_completed_scopes_ = scopes; |
| access_token_request_completed_error_ = error; |
| |
| if (on_access_token_request_completed_callback_) |
| std::move(on_access_token_request_completed_callback_).Run(); |
| } |
| |
| raw_ptr<IdentityManager> identity_manager_; |
| base::OnceClosure on_access_token_requested_callback_; |
| base::OnceClosure on_access_token_request_completed_callback_; |
| CoreAccountId token_requestor_account_id_; |
| std::string token_requestor_consumer_id_; |
| CoreAccountId token_remover_account_id_; |
| ScopeSet token_requestor_scopes_; |
| ScopeSet token_remover_scopes_; |
| CoreAccountId access_token_request_completed_account_id_; |
| std::string access_token_request_completed_consumer_id_; |
| ScopeSet access_token_request_completed_scopes_; |
| GoogleServiceAuthError access_token_request_completed_error_; |
| }; |
| |
| } // namespace |
| |
| class IdentityManagerTest : public testing::Test { |
| public: |
| IdentityManagerTest(const IdentityManagerTest&) = delete; |
| IdentityManagerTest& operator=(const IdentityManagerTest&) = delete; |
| |
| protected: |
| IdentityManagerTest() |
| : signin_client_(&pref_service_, &test_url_loader_factory_) { |
| IdentityManager::RegisterProfilePrefs(pref_service_.registry()); |
| IdentityManager::RegisterLocalStatePrefs(pref_service_.registry()); |
| |
| RecreateIdentityManager( |
| AccountConsistencyMethod::kDisabled, |
| PrimaryAccountManagerSetup::kWithAuthenticatedAccout); |
| primary_account_id_ = |
| identity_manager_->PickAccountIdForAccount(kTestGaiaId, kTestEmail); |
| } |
| |
| ~IdentityManagerTest() override { |
| identity_manager_->Shutdown(); |
| signin_client_.Shutdown(); |
| } |
| |
| IdentityManager* identity_manager() { return identity_manager_.get(); } |
| |
| TestIdentityManagerObserver* identity_manager_observer() { |
| return identity_manager_observer_.get(); |
| } |
| |
| TestIdentityManagerDiagnosticsObserver* |
| identity_manager_diagnostics_observer() { |
| return identity_manager_diagnostics_observer_.get(); |
| } |
| |
| AccountTrackerService* account_tracker() { |
| return identity_manager()->GetAccountTrackerService(); |
| } |
| |
| CustomFakeProfileOAuth2TokenService* token_service() { |
| return static_cast<CustomFakeProfileOAuth2TokenService*>( |
| identity_manager()->GetTokenService()); |
| } |
| |
| // See RecreateIdentityManager. |
| enum class PrimaryAccountManagerSetup { |
| kWithAuthenticatedAccout, |
| kNoAuthenticatedAccount |
| }; |
| |
| // Used by some tests that need to re-instantiate IdentityManager after |
| // performing some other setup. |
| void RecreateIdentityManager() { |
| RecreateIdentityManager( |
| AccountConsistencyMethod::kDisabled, |
| PrimaryAccountManagerSetup::kNoAuthenticatedAccount); |
| } |
| |
| // Recreates IdentityManager with given |account_consistency| and optionally |
| // seeds with an authenticated account depending on |
| // |primary_account_manager_setup|. This process destroys any existing |
| // IdentityManager and its dependencies, then remakes them. Dependencies that |
| // outlive PrimaryAccountManager (e.g. SigninClient) will be reused. |
| void RecreateIdentityManager( |
| AccountConsistencyMethod account_consistency, |
| PrimaryAccountManagerSetup primary_account_manager_setup) { |
| // Remove observers first, otherwise IdentityManager destruction might |
| // trigger a DCHECK because there are still living observers. |
| identity_manager_observer_.reset(); |
| identity_manager_diagnostics_observer_.reset(); |
| if (identity_manager_) |
| identity_manager_->Shutdown(); |
| identity_manager_.reset(); |
| |
| if (temp_profile_dir_.IsValid()) { |
| // We are actually re-creating everything. Delete the previously used |
| // directory. |
| ASSERT_TRUE(temp_profile_dir_.Delete()); |
| } |
| |
| ASSERT_TRUE(temp_profile_dir_.CreateUniqueTempDir()); |
| |
| auto account_tracker_service = std::make_unique<AccountTrackerService>(); |
| account_tracker_service->Initialize(&pref_service_, |
| temp_profile_dir_.GetPath()); |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| account_manager::AccountManager::RegisterPrefs(pref_service_.registry()); |
| auto* ash_account_manager = GetAccountManagerFactory()->GetAccountManager( |
| temp_profile_dir_.GetPath().value()); |
| ash_account_manager->InitializeInEphemeralMode( |
| base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( |
| &test_url_loader_factory_)); |
| ash_account_manager->SetPrefService(&pref_service_); |
| |
| auto* ash_account_manager_mojo_service = |
| GetAccountManagerFactory()->GetAccountManagerMojoService( |
| temp_profile_dir_.GetPath().value()); |
| |
| mojo::Remote<crosapi::mojom::AccountManager> remote; |
| ash_account_manager_mojo_service->BindReceiver( |
| remote.BindNewPipeAndPassReceiver()); |
| account_manager_facade_ = |
| std::make_unique<account_manager::AccountManagerFacadeImpl>( |
| std::move(remote), |
| /*remote_version=*/std::numeric_limits<uint32_t>::max(), |
| /*account_manager_for_tests=*/ |
| ash_account_manager); |
| |
| auto token_service = std::make_unique<CustomFakeProfileOAuth2TokenService>( |
| &pref_service_, |
| std::make_unique<TestProfileOAuth2TokenServiceDelegateChromeOS>( |
| account_tracker_service.get(), ash_account_manager_mojo_service, |
| /*is_regular_profile=*/true)); |
| #else |
| auto token_service = |
| std::make_unique<CustomFakeProfileOAuth2TokenService>(&pref_service_); |
| #endif |
| |
| auto gaia_cookie_manager_service = |
| std::make_unique<GaiaCookieManagerService>(token_service.get(), |
| &signin_client_); |
| |
| auto account_fetcher_service = std::make_unique<AccountFetcherService>(); |
| account_fetcher_service->Initialize( |
| &signin_client_, token_service.get(), account_tracker_service.get(), |
| std::make_unique<image_fetcher::FakeImageDecoder>()); |
| |
| DCHECK_EQ(account_consistency, AccountConsistencyMethod::kDisabled) |
| << "AccountConsistency is not used by PrimaryAccountManager"; |
| auto primary_account_manager = std::make_unique<PrimaryAccountManager>( |
| &signin_client_, token_service.get(), account_tracker_service.get()); |
| |
| // Passing this switch ensures that the new PrimaryAccountManager starts |
| // with a clean slate. Otherwise PrimaryAccountManager::Initialize will use |
| // the account id stored in prefs::kGoogleServicesAccountId. |
| base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); |
| cmd_line->AppendSwitch(switches::kClearTokenService); |
| |
| primary_account_manager->Initialize(&pref_service_); |
| |
| if (primary_account_manager_setup == |
| PrimaryAccountManagerSetup::kWithAuthenticatedAccout) { |
| CoreAccountId account_id = |
| account_tracker_service->SeedAccountInfo(kTestGaiaId, kTestEmail); |
| primary_account_manager->SetPrimaryAccountInfo( |
| account_tracker_service->GetAccountInfo(account_id), |
| ConsentLevel::kSync); |
| } |
| |
| IdentityManager::InitParameters init_params; |
| |
| init_params.accounts_cookie_mutator = |
| std::make_unique<AccountsCookieMutatorImpl>( |
| &signin_client_, token_service.get(), |
| gaia_cookie_manager_service.get(), account_tracker_service.get()); |
| |
| init_params.diagnostics_provider = |
| std::make_unique<DiagnosticsProviderImpl>( |
| token_service.get(), gaia_cookie_manager_service.get()); |
| |
| init_params.primary_account_mutator = |
| std::make_unique<PrimaryAccountMutatorImpl>( |
| account_tracker_service.get(), token_service.get(), |
| primary_account_manager.get(), &pref_service_, account_consistency); |
| |
| #if defined(OS_ANDROID) || defined(OS_IOS) |
| init_params.device_accounts_synchronizer = |
| std::make_unique<DeviceAccountsSynchronizerImpl>( |
| token_service->GetDelegate()); |
| #else |
| init_params.accounts_mutator = std::make_unique<AccountsMutatorImpl>( |
| token_service.get(), account_tracker_service.get(), |
| primary_account_manager.get(), &pref_service_); |
| #endif |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| init_params.account_manager_facade = account_manager_facade_.get(); |
| #endif |
| #if BUILDFLAG(IS_CHROMEOS_LACROS) |
| init_params.signin_client = &signin_client_; |
| #endif |
| init_params.account_fetcher_service = std::move(account_fetcher_service); |
| init_params.account_tracker_service = std::move(account_tracker_service); |
| init_params.gaia_cookie_manager_service = |
| std::move(gaia_cookie_manager_service); |
| init_params.primary_account_manager = std::move(primary_account_manager); |
| init_params.token_service = std::move(token_service); |
| |
| identity_manager_ = |
| std::make_unique<IdentityManager>(std::move(init_params)); |
| identity_manager_observer_ = |
| std::make_unique<TestIdentityManagerObserver>(identity_manager_.get()); |
| identity_manager_diagnostics_observer_ = |
| std::make_unique<TestIdentityManagerDiagnosticsObserver>( |
| identity_manager_.get()); |
| |
| // CustomFakeProfileOAuth2TokenService loads credentials immediately, so |
| // several tests (for example, `AreRefreshTokensLoaded`) expect this |
| // behavior from all platforms, even from ones where tokens are loaded |
| // asynchronously (e.g., ChromeOS). Wait for loading to finish to meet these |
| // expectations. |
| // TODO(https://crbug.com/1195170): Move waiting to tests that need it. |
| signin::WaitForRefreshTokensLoaded(identity_manager()); |
| } |
| |
| void SimulateAdditionOfAccountToCookieSuccess(GaiaAuthConsumer* consumer, |
| const std::string& data) { |
| consumer->OnMergeSessionSuccess(data); |
| } |
| |
| void SimulateAdditionOfAccountToCookieSuccessFailure( |
| GaiaAuthConsumer* consumer, |
| const GoogleServiceAuthError& error) { |
| consumer->OnMergeSessionFailure(error); |
| } |
| |
| void SimulateCookieDeletedByUser( |
| network::mojom::CookieChangeListener* listener, |
| const net::CanonicalCookie& cookie) { |
| listener->OnCookieChange(net::CookieChangeInfo( |
| cookie, net::CookieAccessResult(), net::CookieChangeCause::EXPLICIT)); |
| } |
| |
| void SimulateOAuthMultiloginFinished(GaiaCookieManagerService* manager, |
| SetAccountsInCookieResult error) { |
| manager->OnSetAccountsFinished(error); |
| } |
| |
| const CoreAccountId& primary_account_id() const { |
| return primary_account_id_; |
| } |
| |
| TestSigninClient* signin_client() { return &signin_client_; } |
| |
| network::TestURLLoaderFactory* test_url_loader_factory() { |
| return &test_url_loader_factory_; |
| } |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| ash::AccountManagerFactory* GetAccountManagerFactory() { |
| return &account_manager_factory_; |
| } |
| #endif |
| |
| private: |
| base::ScopedTempDir temp_profile_dir_; |
| base::test::TaskEnvironment task_environment_; |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| ash::AccountManagerFactory account_manager_factory_; |
| std::unique_ptr<account_manager::AccountManagerFacadeImpl> |
| account_manager_facade_; |
| #endif |
| sync_preferences::TestingPrefServiceSyncable pref_service_; |
| network::TestURLLoaderFactory test_url_loader_factory_; |
| TestSigninClient signin_client_; |
| std::unique_ptr<IdentityManager> identity_manager_; |
| std::unique_ptr<TestIdentityManagerObserver> identity_manager_observer_; |
| std::unique_ptr<TestIdentityManagerDiagnosticsObserver> |
| identity_manager_diagnostics_observer_; |
| CoreAccountId primary_account_id_; |
| }; |
| |
| // Test that IdentityManager's constructor properly sets all passed parameters. |
| TEST_F(IdentityManagerTest, Construct) { |
| EXPECT_NE(identity_manager()->GetAccountTrackerService(), nullptr); |
| EXPECT_NE(identity_manager()->GetTokenService(), nullptr); |
| EXPECT_NE(identity_manager()->GetGaiaCookieManagerService(), nullptr); |
| EXPECT_NE(identity_manager()->GetPrimaryAccountManager(), nullptr); |
| EXPECT_NE(identity_manager()->GetAccountFetcherService(), nullptr); |
| EXPECT_NE(identity_manager()->GetPrimaryAccountMutator(), nullptr); |
| EXPECT_NE(identity_manager()->GetAccountsCookieMutator(), nullptr); |
| EXPECT_NE(identity_manager()->GetDiagnosticsProvider(), nullptr); |
| #if defined(OS_ANDROID) || defined(OS_IOS) |
| EXPECT_EQ(identity_manager()->GetAccountsMutator(), nullptr); |
| EXPECT_NE(identity_manager()->GetDeviceAccountsSynchronizer(), nullptr); |
| #else |
| EXPECT_NE(identity_manager()->GetAccountsMutator(), nullptr); |
| EXPECT_EQ(identity_manager()->GetDeviceAccountsSynchronizer(), nullptr); |
| #endif |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| EXPECT_NE(identity_manager()->GetAccountManagerFacade(), nullptr); |
| #endif |
| } |
| |
| // Test that IdentityManager starts off with the information in |
| // PrimaryAccountManager. |
| TEST_F(IdentityManagerTest, PrimaryAccountInfoAtStartup) { |
| CoreAccountInfo primary_account_info = |
| identity_manager()->GetPrimaryAccountInfo(signin::ConsentLevel::kSync); |
| EXPECT_EQ(kTestGaiaId, primary_account_info.gaia); |
| EXPECT_EQ(kTestEmail, primary_account_info.email); |
| |
| // Primary account is by definition also unconsented primary account. |
| EXPECT_EQ(primary_account_info, |
| identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSignin)); |
| // There is no guarantee that this will be notified via callback on startup. |
| } |
| |
| // Signin/signout tests aren't relevant and cannot build on ChromeOS, which |
| // doesn't support signin/signout. |
| #if !BUILDFLAG(IS_CHROMEOS_ASH) |
| // Test that the user signing in results in firing of the IdentityManager |
| // observer callback and the IdentityManager's state being updated. |
| TEST_F(IdentityManagerTest, PrimaryAccountInfoAfterSignin) { |
| ClearPrimaryAccount(identity_manager()); |
| |
| SetPrimaryAccount(identity_manager(), kTestEmail, ConsentLevel::kSync); |
| auto event = identity_manager_observer()->GetPrimaryAccountChangedEvent(); |
| EXPECT_EQ(PrimaryAccountChangeEvent::Type::kSet, |
| event.GetEventTypeFor(ConsentLevel::kSync)); |
| EXPECT_EQ(PrimaryAccountChangeEvent::Type::kSet, |
| event.GetEventTypeFor(ConsentLevel::kSignin)); |
| |
| CoreAccountInfo primary_account_from_set_callback = |
| event.GetCurrentState().primary_account; |
| EXPECT_EQ(kTestGaiaId, primary_account_from_set_callback.gaia); |
| EXPECT_EQ(kTestEmail, primary_account_from_set_callback.email); |
| |
| CoreAccountInfo primary_account_info = |
| identity_manager()->GetPrimaryAccountInfo(signin::ConsentLevel::kSync); |
| EXPECT_EQ(kTestGaiaId, primary_account_info.gaia); |
| EXPECT_EQ(kTestEmail, primary_account_info.email); |
| |
| // Primary account is by definition also unconsented primary account. |
| EXPECT_EQ(primary_account_info, |
| identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSignin)); |
| |
| CoreAccountId primary_account_id = |
| identity_manager()->GetPrimaryAccountId(signin::ConsentLevel::kSync); |
| EXPECT_EQ(primary_account_id, CoreAccountId(kTestGaiaId)); |
| EXPECT_EQ(primary_account_id, primary_account_info.account_id); |
| |
| EXPECT_EQ(primary_account_id, identity_manager()->GetPrimaryAccountId( |
| signin::ConsentLevel::kSignin)); |
| } |
| |
| // Test that the user signing out results in firing of the IdentityManager |
| // observer callback and the IdentityManager's state being updated. |
| TEST_F(IdentityManagerTest, PrimaryAccountInfoAfterSigninAndSignout) { |
| ClearPrimaryAccount(identity_manager()); |
| // First ensure that the user is signed in from the POV of the |
| // IdentityManager. |
| SetPrimaryAccount(identity_manager(), kTestEmail, ConsentLevel::kSync); |
| |
| // Sign the user out and check that the IdentityManager responds |
| // appropriately. |
| ClearPrimaryAccount(identity_manager()); |
| auto event = identity_manager_observer()->GetPrimaryAccountChangedEvent(); |
| EXPECT_EQ(PrimaryAccountChangeEvent::Type::kCleared, |
| event.GetEventTypeFor(ConsentLevel::kSync)); |
| EXPECT_EQ(PrimaryAccountChangeEvent::Type::kCleared, |
| event.GetEventTypeFor(ConsentLevel::kSignin)); |
| |
| CoreAccountInfo primary_account_from_cleared_callback = |
| event.GetPreviousState().primary_account; |
| EXPECT_EQ(kTestGaiaId, primary_account_from_cleared_callback.gaia); |
| EXPECT_EQ(kTestEmail, primary_account_from_cleared_callback.email); |
| |
| // After the sign-out, there is no unconsented primary account. |
| EXPECT_TRUE(identity_manager() |
| ->GetPrimaryAccountInfo(ConsentLevel::kSignin) |
| .IsEmpty()); |
| |
| CoreAccountInfo primary_account_info = |
| identity_manager()->GetPrimaryAccountInfo(signin::ConsentLevel::kSync); |
| EXPECT_EQ("", primary_account_info.gaia); |
| EXPECT_EQ("", primary_account_info.email); |
| EXPECT_EQ(primary_account_info, |
| identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSignin)); |
| |
| CoreAccountId primary_account_id = |
| identity_manager()->GetPrimaryAccountId(signin::ConsentLevel::kSync); |
| EXPECT_TRUE(primary_account_id.empty()); |
| EXPECT_EQ(primary_account_id, primary_account_info.account_id); |
| EXPECT_EQ(primary_account_id, identity_manager()->GetPrimaryAccountId( |
| signin::ConsentLevel::kSignin)); |
| } |
| |
| // Test that the primary account's core info remains tracked by the |
| // IdentityManager after signing in even after having removed the refresh token |
| // without signing out. |
| TEST_F(IdentityManagerTest, |
| PrimaryAccountInfoAfterSigninAndRefreshTokenRemoval) { |
| ClearPrimaryAccount(identity_manager()); |
| // First ensure that the user is signed in from the POV of the |
| // IdentityManager. |
| SetPrimaryAccount(identity_manager(), kTestEmail, ConsentLevel::kSync); |
| |
| identity_manager()->account_fetcher_service_->EnableAccountRemovalForTest(); |
| // Revoke the primary's account credentials from the token service and |
| // check that the returned CoreAccountInfo is still valid since the |
| // identity_manager stores it. |
| token_service()->RevokeCredentials( |
| identity_manager()->GetPrimaryAccountId(signin::ConsentLevel::kSync)); |
| |
| CoreAccountInfo primary_account_info = |
| identity_manager()->GetPrimaryAccountInfo(signin::ConsentLevel::kSync); |
| EXPECT_EQ(kTestGaiaId, primary_account_info.gaia); |
| EXPECT_EQ(kTestEmail, primary_account_info.email); |
| EXPECT_EQ(CoreAccountId(kTestGaiaId), primary_account_info.account_id); |
| EXPECT_EQ(primary_account_info, |
| identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSignin)); |
| |
| CoreAccountId primary_account_id = |
| identity_manager()->GetPrimaryAccountId(signin::ConsentLevel::kSync); |
| EXPECT_EQ(primary_account_id, CoreAccountId(kTestGaiaId)); |
| EXPECT_EQ(primary_account_id, |
| identity_manager()->GetPrimaryAccountId(ConsentLevel::kSignin)); |
| } |
| #endif // !BUILDFLAG(IS_CHROMEOS_ASH) |
| |
| TEST_F(IdentityManagerTest, HasPrimaryAccount) { |
| EXPECT_TRUE( |
| identity_manager()->HasPrimaryAccount(signin::ConsentLevel::kSync)); |
| EXPECT_TRUE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); |
| |
| // Removing the account from the AccountTrackerService should not cause |
| // IdentityManager to think that there is no longer a primary account. |
| account_tracker()->RemoveAccount( |
| identity_manager()->GetPrimaryAccountId(signin::ConsentLevel::kSync)); |
| EXPECT_TRUE( |
| identity_manager()->HasPrimaryAccount(signin::ConsentLevel::kSync)); |
| EXPECT_TRUE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); |
| |
| #if !BUILDFLAG(IS_CHROMEOS_ASH) |
| // Signing out should cause IdentityManager to recognize that there is no |
| // longer a primary account. |
| ClearPrimaryAccount(identity_manager()); |
| EXPECT_FALSE( |
| identity_manager()->HasPrimaryAccount(signin::ConsentLevel::kSync)); |
| EXPECT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); |
| EXPECT_FALSE(identity_manager_observer() |
| ->GetPrimaryAccountChangedEvent() |
| .GetPreviousState() |
| .primary_account.IsEmpty()); |
| #endif |
| } |
| |
| TEST_F(IdentityManagerTest, GetAccountsInteractionWithPrimaryAccount) { |
| // Should not have any refresh tokens at initialization. |
| EXPECT_TRUE(identity_manager()->GetAccountsWithRefreshTokens().empty()); |
| |
| // Add a refresh token for the primary account and check that it shows up in |
| // GetAccountsWithRefreshTokens(). |
| SetRefreshTokenForPrimaryAccount(identity_manager()); |
| |
| std::vector<CoreAccountInfo> accounts_after_update = |
| identity_manager()->GetAccountsWithRefreshTokens(); |
| |
| EXPECT_EQ(1u, accounts_after_update.size()); |
| EXPECT_EQ(accounts_after_update[0].account_id, primary_account_id()); |
| EXPECT_EQ(accounts_after_update[0].gaia, kTestGaiaId); |
| EXPECT_EQ(accounts_after_update[0].email, kTestEmail); |
| |
| // Update the token and check that it doesn't change the state (or blow up). |
| SetRefreshTokenForPrimaryAccount(identity_manager()); |
| |
| std::vector<CoreAccountInfo> accounts_after_second_update = |
| identity_manager()->GetAccountsWithRefreshTokens(); |
| |
| EXPECT_EQ(1u, accounts_after_second_update.size()); |
| EXPECT_EQ(accounts_after_second_update[0].account_id, primary_account_id()); |
| EXPECT_EQ(accounts_after_second_update[0].gaia, kTestGaiaId); |
| EXPECT_EQ(accounts_after_second_update[0].email, kTestEmail); |
| |
| // Remove the token for the primary account and check that this is likewise |
| // reflected. |
| RemoveRefreshTokenForPrimaryAccount(identity_manager()); |
| |
| EXPECT_TRUE(identity_manager()->GetAccountsWithRefreshTokens().empty()); |
| } |
| |
| TEST_F(IdentityManagerTest, |
| QueryingOfRefreshTokensInteractionWithPrimaryAccount) { |
| CoreAccountInfo account_info = |
| identity_manager()->GetPrimaryAccountInfo(signin::ConsentLevel::kSync); |
| |
| // Should not have a refresh token for the primary account at initialization. |
| EXPECT_FALSE( |
| identity_manager()->HasAccountWithRefreshToken(account_info.account_id)); |
| EXPECT_FALSE(identity_manager()->HasPrimaryAccountWithRefreshToken( |
| signin::ConsentLevel::kSync)); |
| |
| // Add a refresh token for the primary account and check that it affects this |
| // state. |
| SetRefreshTokenForPrimaryAccount(identity_manager()); |
| |
| EXPECT_TRUE( |
| identity_manager()->HasAccountWithRefreshToken(account_info.account_id)); |
| EXPECT_TRUE(identity_manager()->HasPrimaryAccountWithRefreshToken( |
| signin::ConsentLevel::kSync)); |
| |
| // Update the token and check that it doesn't change the state (or blow up). |
| SetRefreshTokenForPrimaryAccount(identity_manager()); |
| |
| EXPECT_TRUE( |
| identity_manager()->HasAccountWithRefreshToken(account_info.account_id)); |
| EXPECT_TRUE(identity_manager()->HasPrimaryAccountWithRefreshToken( |
| signin::ConsentLevel::kSync)); |
| |
| // Remove the token for the primary account and check that this is likewise |
| // reflected. |
| RemoveRefreshTokenForPrimaryAccount(identity_manager()); |
| |
| EXPECT_FALSE( |
| identity_manager()->HasAccountWithRefreshToken(account_info.account_id)); |
| EXPECT_FALSE(identity_manager()->HasPrimaryAccountWithRefreshToken( |
| signin::ConsentLevel::kSync)); |
| } |
| |
| TEST_F(IdentityManagerTest, QueryingOfRefreshTokensReflectsEmptyInitialState) { |
| CoreAccountInfo account_info = |
| identity_manager()->GetPrimaryAccountInfo(signin::ConsentLevel::kSync); |
| CoreAccountId account_id = account_info.account_id; |
| |
| EXPECT_FALSE( |
| identity_manager()->HasAccountWithRefreshToken(account_info.account_id)); |
| EXPECT_FALSE(identity_manager()->HasPrimaryAccountWithRefreshToken( |
| signin::ConsentLevel::kSync)); |
| |
| SetRefreshTokenForPrimaryAccount(identity_manager()); |
| |
| EXPECT_TRUE( |
| identity_manager()->HasAccountWithRefreshToken(account_info.account_id)); |
| EXPECT_TRUE(identity_manager()->HasPrimaryAccountWithRefreshToken( |
| signin::ConsentLevel::kSync)); |
| } |
| |
| TEST_F(IdentityManagerTest, GetAccountsInteractionWithSecondaryAccounts) { |
| // Should not have any refresh tokens at initialization. |
| EXPECT_TRUE(identity_manager()->GetAccountsWithRefreshTokens().empty()); |
| |
| // Add a refresh token for a secondary account and check that it shows up in |
| // GetAccountsWithRefreshTokens(). |
| account_tracker()->SeedAccountInfo(kTestGaiaId2, kTestEmail2); |
| CoreAccountId account_id2 = |
| account_tracker()->FindAccountInfoByGaiaId(kTestGaiaId2).account_id; |
| SetRefreshTokenForAccount(identity_manager(), account_id2); |
| |
| std::vector<CoreAccountInfo> accounts_after_update = |
| identity_manager()->GetAccountsWithRefreshTokens(); |
| |
| EXPECT_EQ(1u, accounts_after_update.size()); |
| EXPECT_EQ(accounts_after_update[0].account_id, account_id2); |
| EXPECT_EQ(accounts_after_update[0].gaia, kTestGaiaId2); |
| EXPECT_EQ(accounts_after_update[0].email, kTestEmail2); |
| |
| // Add a refresh token for a different secondary account and check that it |
| // also shows up in GetAccountsWithRefreshTokens(). |
| account_tracker()->SeedAccountInfo(kTestGaiaId3, kTestEmail3); |
| CoreAccountId account_id3 = |
| account_tracker()->FindAccountInfoByGaiaId(kTestGaiaId3).account_id; |
| SetRefreshTokenForAccount(identity_manager(), account_id3); |
| |
| std::vector<CoreAccountInfo> accounts_after_second_update = |
| identity_manager()->GetAccountsWithRefreshTokens(); |
| EXPECT_EQ(2u, accounts_after_second_update.size()); |
| |
| for (CoreAccountInfo account_info : accounts_after_second_update) { |
| if (account_info.account_id == account_id2) { |
| EXPECT_EQ(account_info.gaia, kTestGaiaId2); |
| EXPECT_EQ(account_info.email, kTestEmail2); |
| } else { |
| EXPECT_EQ(account_info.gaia, kTestGaiaId3); |
| EXPECT_EQ(account_info.email, kTestEmail3); |
| } |
| } |
| |
| // Remove the token for account2 and check that account3 is still present. |
| RemoveRefreshTokenForAccount(identity_manager(), account_id2); |
| |
| std::vector<CoreAccountInfo> accounts_after_third_update = |
| identity_manager()->GetAccountsWithRefreshTokens(); |
| |
| EXPECT_EQ(1u, accounts_after_third_update.size()); |
| EXPECT_EQ(accounts_after_third_update[0].account_id, account_id3); |
| EXPECT_EQ(accounts_after_third_update[0].gaia, kTestGaiaId3); |
| EXPECT_EQ(accounts_after_third_update[0].email, kTestEmail3); |
| } |
| |
| TEST_F(IdentityManagerTest, |
| HasPrimaryAccountWithRefreshTokenInteractionWithSecondaryAccounts) { |
| EXPECT_FALSE(identity_manager()->HasPrimaryAccountWithRefreshToken( |
| signin::ConsentLevel::kSync)); |
| |
| // Adding a refresh token for a secondary account shouldn't change anything |
| // about the primary account |
| account_tracker()->SeedAccountInfo(kTestGaiaId2, kTestEmail2); |
| CoreAccountId account_id2 = |
| account_tracker()->FindAccountInfoByGaiaId(kTestGaiaId2).account_id; |
| SetRefreshTokenForAccount(identity_manager(), account_id2); |
| |
| EXPECT_FALSE(identity_manager()->HasPrimaryAccountWithRefreshToken( |
| signin::ConsentLevel::kSync)); |
| |
| // Adding a refresh token for a different secondary account should not do so |
| // either. |
| account_tracker()->SeedAccountInfo(kTestGaiaId3, kTestEmail3); |
| CoreAccountId account_id3 = |
| account_tracker()->FindAccountInfoByGaiaId(kTestGaiaId3).account_id; |
| SetRefreshTokenForAccount(identity_manager(), account_id3); |
| |
| EXPECT_FALSE(identity_manager()->HasPrimaryAccountWithRefreshToken( |
| signin::ConsentLevel::kSync)); |
| |
| // Removing the token for account2 should have no effect. |
| RemoveRefreshTokenForAccount(identity_manager(), account_id2); |
| |
| EXPECT_FALSE(identity_manager()->HasPrimaryAccountWithRefreshToken( |
| signin::ConsentLevel::kSync)); |
| } |
| |
| TEST_F(IdentityManagerTest, |
| HasAccountWithRefreshTokenInteractionWithSecondaryAccounts) { |
| account_tracker()->SeedAccountInfo(kTestGaiaId2, kTestEmail2); |
| AccountInfo account_info2 = |
| account_tracker()->FindAccountInfoByGaiaId(kTestGaiaId2); |
| CoreAccountId account_id2 = account_info2.account_id; |
| |
| EXPECT_FALSE( |
| identity_manager()->HasAccountWithRefreshToken(account_info2.account_id)); |
| |
| // Add a refresh token for account_info2 and check that this is reflected by |
| // HasAccountWithRefreshToken(.account_id). |
| SetRefreshTokenForAccount(identity_manager(), account_id2); |
| |
| EXPECT_TRUE( |
| identity_manager()->HasAccountWithRefreshToken(account_info2.account_id)); |
| |
| // Go through the same process for a different secondary account. |
| account_tracker()->SeedAccountInfo(kTestGaiaId3, kTestEmail3); |
| AccountInfo account_info3 = |
| account_tracker()->FindAccountInfoByGaiaId(kTestGaiaId3); |
| CoreAccountId account_id3 = account_info3.account_id; |
| |
| EXPECT_TRUE( |
| identity_manager()->HasAccountWithRefreshToken(account_info2.account_id)); |
| EXPECT_FALSE( |
| identity_manager()->HasAccountWithRefreshToken(account_info3.account_id)); |
| |
| SetRefreshTokenForAccount(identity_manager(), account_id3); |
| |
| EXPECT_TRUE( |
| identity_manager()->HasAccountWithRefreshToken(account_info2.account_id)); |
| EXPECT_TRUE( |
| identity_manager()->HasAccountWithRefreshToken(account_info3.account_id)); |
| |
| // Remove the token for account2. |
| RemoveRefreshTokenForAccount(identity_manager(), account_id2); |
| |
| EXPECT_FALSE( |
| identity_manager()->HasAccountWithRefreshToken(account_info2.account_id)); |
| EXPECT_TRUE( |
| identity_manager()->HasAccountWithRefreshToken(account_info3.account_id)); |
| } |
| |
| TEST_F(IdentityManagerTest, |
| GetAccountsInteractionBetweenPrimaryAndSecondaryAccounts) { |
| // Should not have any refresh tokens at initialization. |
| EXPECT_TRUE(identity_manager()->GetAccountsWithRefreshTokens().empty()); |
| EXPECT_FALSE(identity_manager()->HasPrimaryAccountWithRefreshToken( |
| signin::ConsentLevel::kSync)); |
| |
| // Add a refresh token for a secondary account and check that it shows up in |
| // GetAccountsWithRefreshTokens(). |
| account_tracker()->SeedAccountInfo(kTestGaiaId2, kTestEmail2); |
| CoreAccountId account_id2 = |
| account_tracker()->FindAccountInfoByGaiaId(kTestGaiaId2).account_id; |
| SetRefreshTokenForAccount(identity_manager(), account_id2); |
| |
| std::vector<CoreAccountInfo> accounts_after_update = |
| identity_manager()->GetAccountsWithRefreshTokens(); |
| |
| EXPECT_EQ(1u, accounts_after_update.size()); |
| EXPECT_EQ(accounts_after_update[0].account_id, account_id2); |
| EXPECT_EQ(accounts_after_update[0].gaia, kTestGaiaId2); |
| EXPECT_EQ(accounts_after_update[0].email, kTestEmail2); |
| |
| EXPECT_FALSE(identity_manager()->HasPrimaryAccountWithRefreshToken( |
| signin::ConsentLevel::kSync)); |
| |
| // The user still has a primary account. |
| EXPECT_EQ(identity_manager() |
| ->GetPrimaryAccountInfo(signin::ConsentLevel::kSync) |
| .email, |
| kTestEmail); |
| EXPECT_EQ( |
| identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSignin).email, |
| kTestEmail); |
| |
| // Add a refresh token for the primary account and check that it |
| // also shows up in GetAccountsWithRefreshTokens(). |
| SetRefreshTokenForPrimaryAccount(identity_manager()); |
| |
| std::vector<CoreAccountInfo> accounts_after_second_update = |
| identity_manager()->GetAccountsWithRefreshTokens(); |
| EXPECT_EQ(2u, accounts_after_second_update.size()); |
| |
| for (const CoreAccountInfo& account_info : accounts_after_second_update) { |
| if (account_info.account_id == account_id2) { |
| EXPECT_EQ(account_info.gaia, kTestGaiaId2); |
| EXPECT_EQ(account_info.email, kTestEmail2); |
| } else { |
| EXPECT_EQ(account_info.gaia, kTestGaiaId); |
| EXPECT_EQ(account_info.email, kTestEmail); |
| } |
| } |
| |
| EXPECT_TRUE(identity_manager()->HasPrimaryAccountWithRefreshToken( |
| signin::ConsentLevel::kSync)); |
| EXPECT_EQ(identity_manager() |
| ->GetPrimaryAccountInfo(signin::ConsentLevel::kSync) |
| .email, |
| kTestEmail); |
| EXPECT_EQ( |
| identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSignin).email, |
| kTestEmail); |
| |
| // Remove the token for the primary account and check that account2 is still |
| // present. |
| RemoveRefreshTokenForPrimaryAccount(identity_manager()); |
| |
| std::vector<CoreAccountInfo> accounts_after_third_update = |
| identity_manager()->GetAccountsWithRefreshTokens(); |
| |
| EXPECT_EQ(1u, accounts_after_third_update.size()); |
| EXPECT_EQ(accounts_after_update[0].account_id, account_id2); |
| EXPECT_EQ(accounts_after_update[0].gaia, kTestGaiaId2); |
| EXPECT_EQ(accounts_after_update[0].email, kTestEmail2); |
| |
| EXPECT_FALSE(identity_manager()->HasPrimaryAccountWithRefreshToken( |
| signin::ConsentLevel::kSync)); |
| // The user still has a primary account. |
| EXPECT_EQ(identity_manager() |
| ->GetPrimaryAccountInfo(signin::ConsentLevel::kSync) |
| .email, |
| kTestEmail); |
| EXPECT_EQ( |
| identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSignin).email, |
| kTestEmail); |
| } |
| |
| TEST_F( |
| IdentityManagerTest, |
| HasPrimaryAccountWithRefreshTokenInteractionBetweenPrimaryAndSecondaryAccounts) { |
| EXPECT_FALSE(identity_manager()->HasPrimaryAccountWithRefreshToken( |
| signin::ConsentLevel::kSync)); |
| EXPECT_TRUE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); |
| |
| // Add a refresh token for a secondary account and check that it doesn't |
| // impact the above state. |
| account_tracker()->SeedAccountInfo(kTestGaiaId2, kTestEmail2); |
| CoreAccountId account_id2 = |
| account_tracker()->FindAccountInfoByGaiaId(kTestGaiaId2).account_id; |
| SetRefreshTokenForAccount(identity_manager(), account_id2); |
| |
| EXPECT_FALSE(identity_manager()->HasPrimaryAccountWithRefreshToken( |
| signin::ConsentLevel::kSync)); |
| EXPECT_TRUE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); |
| |
| // Add a refresh token for the primary account and check that it |
| // *does* impact the stsate of |
| // HasPrimaryAccountWithRefreshToken(signin::ConsentLevel::kSync). |
| SetRefreshTokenForPrimaryAccount(identity_manager()); |
| |
| EXPECT_TRUE(identity_manager()->HasPrimaryAccountWithRefreshToken( |
| signin::ConsentLevel::kSync)); |
| EXPECT_TRUE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); |
| |
| // Remove the token for the secondary account and check that this doesn't flip |
| // the state. |
| RemoveRefreshTokenForAccount(identity_manager(), account_id2); |
| |
| EXPECT_TRUE(identity_manager()->HasPrimaryAccountWithRefreshToken( |
| signin::ConsentLevel::kSync)); |
| EXPECT_TRUE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); |
| |
| // Remove the token for the primary account and check that this flips the |
| // state. |
| RemoveRefreshTokenForPrimaryAccount(identity_manager()); |
| |
| EXPECT_FALSE(identity_manager()->HasPrimaryAccountWithRefreshToken( |
| signin::ConsentLevel::kSync)); |
| EXPECT_TRUE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); |
| } |
| |
| TEST_F( |
| IdentityManagerTest, |
| HasAccountWithRefreshTokenInteractionBetweenPrimaryAndSecondaryAccounts) { |
| CoreAccountInfo primary_account_info = |
| identity_manager()->GetPrimaryAccountInfo(signin::ConsentLevel::kSync); |
| CoreAccountId primary_account_id = primary_account_info.account_id; |
| |
| account_tracker()->SeedAccountInfo(kTestGaiaId2, kTestEmail2); |
| AccountInfo account_info2 = |
| account_tracker()->FindAccountInfoByGaiaId(kTestGaiaId2); |
| CoreAccountId account_id2 = account_info2.account_id; |
| |
| EXPECT_FALSE(identity_manager()->HasAccountWithRefreshToken( |
| primary_account_info.account_id)); |
| EXPECT_FALSE( |
| identity_manager()->HasAccountWithRefreshToken(account_info2.account_id)); |
| |
| // Add a refresh token for account_info2 and check that this is reflected by |
| // HasAccountWithRefreshToken(.account_id). |
| SetRefreshTokenForAccount(identity_manager(), account_id2); |
| |
| EXPECT_FALSE(identity_manager()->HasAccountWithRefreshToken( |
| primary_account_info.account_id)); |
| EXPECT_TRUE( |
| identity_manager()->HasAccountWithRefreshToken(account_info2.account_id)); |
| |
| // Go through the same process for the primary account. |
| SetRefreshTokenForPrimaryAccount(identity_manager()); |
| |
| EXPECT_TRUE(identity_manager()->HasAccountWithRefreshToken( |
| primary_account_info.account_id)); |
| EXPECT_TRUE( |
| identity_manager()->HasAccountWithRefreshToken(account_info2.account_id)); |
| |
| // Remove the token for account2. |
| RemoveRefreshTokenForAccount(identity_manager(), account_id2); |
| |
| EXPECT_TRUE(identity_manager()->HasAccountWithRefreshToken( |
| primary_account_info.account_id)); |
| EXPECT_FALSE( |
| identity_manager()->HasAccountWithRefreshToken(account_info2.account_id)); |
| } |
| |
| TEST_F(IdentityManagerTest, |
| CallbackSentOnUpdateToErrorStateOfRefreshTokenForAccount) { |
| CoreAccountInfo primary_account_info = |
| identity_manager()->GetPrimaryAccountInfo(signin::ConsentLevel::kSync); |
| CoreAccountId primary_account_id = primary_account_info.account_id; |
| SetRefreshTokenForPrimaryAccount(identity_manager()); |
| |
| account_tracker()->SeedAccountInfo(kTestGaiaId2, kTestEmail2); |
| AccountInfo account_info2 = |
| account_tracker()->FindAccountInfoByGaiaId(kTestGaiaId2); |
| CoreAccountId account_id2 = account_info2.account_id; |
| SetRefreshTokenForAccount(identity_manager(), account_id2); |
| |
| GoogleServiceAuthError user_not_signed_up_error = |
| GoogleServiceAuthError(GoogleServiceAuthError::State::USER_NOT_SIGNED_UP); |
| GoogleServiceAuthError invalid_gaia_credentials_error = |
| GoogleServiceAuthError( |
| GoogleServiceAuthError::State::INVALID_GAIA_CREDENTIALS); |
| GoogleServiceAuthError transient_error = GoogleServiceAuthError( |
| GoogleServiceAuthError::State::SERVICE_UNAVAILABLE); |
| |
| // Set a persistent error for |account_id2| and check that it's reflected. |
| token_service()->UpdateAuthErrorForTesting(account_id2, |
| user_not_signed_up_error); |
| EXPECT_EQ(account_id2, |
| identity_manager_observer() |
| ->AccountFromErrorStateOfRefreshTokenUpdatedCallback() |
| .account_id); |
| EXPECT_EQ(user_not_signed_up_error, |
| identity_manager_observer() |
| ->ErrorFromErrorStateOfRefreshTokenUpdatedCallback()); |
| |
| // A transient error should not cause a callback. |
| token_service()->UpdateAuthErrorForTesting(primary_account_id, |
| transient_error); |
| EXPECT_EQ(account_id2, |
| identity_manager_observer() |
| ->AccountFromErrorStateOfRefreshTokenUpdatedCallback() |
| .account_id); |
| EXPECT_EQ(user_not_signed_up_error, |
| identity_manager_observer() |
| ->ErrorFromErrorStateOfRefreshTokenUpdatedCallback()); |
| |
| // Set a different persistent error for the primary account and check that |
| // it's reflected. |
| token_service()->UpdateAuthErrorForTesting(primary_account_id, |
| invalid_gaia_credentials_error); |
| EXPECT_EQ(primary_account_id, |
| identity_manager_observer() |
| ->AccountFromErrorStateOfRefreshTokenUpdatedCallback() |
| .account_id); |
| EXPECT_EQ(invalid_gaia_credentials_error, |
| identity_manager_observer() |
| ->ErrorFromErrorStateOfRefreshTokenUpdatedCallback()); |
| } |
| |
| TEST_F(IdentityManagerTest, GetErrorStateOfRefreshTokenForAccount) { |
| CoreAccountInfo primary_account_info = |
| identity_manager()->GetPrimaryAccountInfo(signin::ConsentLevel::kSync); |
| CoreAccountId primary_account_id = primary_account_info.account_id; |
| |
| // A primary account without a refresh token should not be in an error |
| // state, and setting a refresh token should not affect that. |
| EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(), |
| identity_manager()->GetErrorStateOfRefreshTokenForAccount( |
| primary_account_id)); |
| EXPECT_FALSE( |
| identity_manager()->HasAccountWithRefreshTokenInPersistentErrorState( |
| primary_account_id)); |
| |
| SetRefreshTokenForPrimaryAccount(identity_manager()); |
| EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(), |
| identity_manager()->GetErrorStateOfRefreshTokenForAccount( |
| primary_account_id)); |
| EXPECT_FALSE( |
| identity_manager()->HasAccountWithRefreshTokenInPersistentErrorState( |
| primary_account_id)); |
| |
| // A secondary account without a refresh token should not be in an error |
| // state, and setting a refresh token should not affect that. |
| account_tracker()->SeedAccountInfo(kTestGaiaId2, kTestEmail2); |
| AccountInfo account_info2 = |
| account_tracker()->FindAccountInfoByGaiaId(kTestGaiaId2); |
| CoreAccountId account_id2 = account_info2.account_id; |
| EXPECT_EQ( |
| GoogleServiceAuthError::AuthErrorNone(), |
| identity_manager()->GetErrorStateOfRefreshTokenForAccount(account_id2)); |
| EXPECT_FALSE( |
| identity_manager()->HasAccountWithRefreshTokenInPersistentErrorState( |
| account_id2)); |
| |
| SetRefreshTokenForAccount(identity_manager(), account_id2); |
| EXPECT_EQ( |
| GoogleServiceAuthError::AuthErrorNone(), |
| identity_manager()->GetErrorStateOfRefreshTokenForAccount(account_id2)); |
| EXPECT_FALSE( |
| identity_manager()->HasAccountWithRefreshTokenInPersistentErrorState( |
| account_id2)); |
| |
| GoogleServiceAuthError user_not_signed_up_error = |
| GoogleServiceAuthError(GoogleServiceAuthError::State::USER_NOT_SIGNED_UP); |
| GoogleServiceAuthError invalid_gaia_credentials_error = |
| GoogleServiceAuthError( |
| GoogleServiceAuthError::State::INVALID_GAIA_CREDENTIALS); |
| GoogleServiceAuthError transient_error = GoogleServiceAuthError( |
| GoogleServiceAuthError::State::SERVICE_UNAVAILABLE); |
| |
| // Set a persistent error for |account_id2| and check that it's reflected. |
| token_service()->UpdateAuthErrorForTesting(account_id2, |
| user_not_signed_up_error); |
| EXPECT_EQ( |
| user_not_signed_up_error, |
| identity_manager()->GetErrorStateOfRefreshTokenForAccount(account_id2)); |
| EXPECT_TRUE( |
| identity_manager()->HasAccountWithRefreshTokenInPersistentErrorState( |
| account_id2)); |
| EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(), |
| identity_manager()->GetErrorStateOfRefreshTokenForAccount( |
| primary_account_id)); |
| EXPECT_FALSE( |
| identity_manager()->HasAccountWithRefreshTokenInPersistentErrorState( |
| primary_account_id)); |
| |
| // A transient error should cause no change in the error state. |
| token_service()->UpdateAuthErrorForTesting(primary_account_id, |
| transient_error); |
| EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(), |
| identity_manager()->GetErrorStateOfRefreshTokenForAccount( |
| primary_account_id)); |
| EXPECT_FALSE( |
| identity_manager()->HasAccountWithRefreshTokenInPersistentErrorState( |
| primary_account_id)); |
| |
| // Set a different persistent error for the primary account and check that |
| // it's reflected. |
| token_service()->UpdateAuthErrorForTesting(primary_account_id, |
| invalid_gaia_credentials_error); |
| EXPECT_EQ( |
| user_not_signed_up_error, |
| identity_manager()->GetErrorStateOfRefreshTokenForAccount(account_id2)); |
| EXPECT_TRUE( |
| identity_manager()->HasAccountWithRefreshTokenInPersistentErrorState( |
| account_id2)); |
| EXPECT_EQ(invalid_gaia_credentials_error, |
| identity_manager()->GetErrorStateOfRefreshTokenForAccount( |
| primary_account_id)); |
| EXPECT_TRUE( |
| identity_manager()->HasAccountWithRefreshTokenInPersistentErrorState( |
| primary_account_id)); |
| |
| // Remove the token for account2 and check that it goes back to having no |
| // error. |
| RemoveRefreshTokenForAccount(identity_manager(), account_id2); |
| EXPECT_EQ( |
| GoogleServiceAuthError::AuthErrorNone(), |
| identity_manager()->GetErrorStateOfRefreshTokenForAccount(account_id2)); |
| EXPECT_FALSE( |
| identity_manager()->HasAccountWithRefreshTokenInPersistentErrorState( |
| account_id2)); |
| EXPECT_EQ(invalid_gaia_credentials_error, |
| identity_manager()->GetErrorStateOfRefreshTokenForAccount( |
| primary_account_id)); |
| EXPECT_TRUE( |
| identity_manager()->HasAccountWithRefreshTokenInPersistentErrorState( |
| primary_account_id)); |
| } |
| |
| TEST_F(IdentityManagerTest, RemoveAccessTokenFromCache) { |
| std::set<std::string> scopes{"scope"}; |
| std::string access_token = "access_token"; |
| |
| identity_manager()->GetAccountTrackerService()->SeedAccountInfo(kTestGaiaId, |
| kTestEmail); |
| identity_manager()->GetPrimaryAccountMutator()->SetPrimaryAccount( |
| primary_account_id(), ConsentLevel::kSync); |
| SetRefreshTokenForAccount(identity_manager(), primary_account_id(), |
| "refresh_token"); |
| |
| base::RunLoop run_loop; |
| token_service()->set_on_access_token_invalidated_info( |
| primary_account_id(), scopes, access_token, run_loop.QuitClosure()); |
| |
| identity_manager()->RemoveAccessTokenFromCache(primary_account_id(), scopes, |
| access_token); |
| |
| run_loop.Run(); |
| |
| // RemoveAccessTokenFromCache should lead to OnAccessTokenRemovedFromCache |
| // from IdentityManager::DiagnosticsObserver. |
| EXPECT_EQ( |
| primary_account_id(), |
| identity_manager_diagnostics_observer()->token_remover_account_id()); |
| EXPECT_EQ(scopes, |
| identity_manager_diagnostics_observer()->token_remover_scopes()); |
| } |
| |
| TEST_F(IdentityManagerTest, CreateAccessTokenFetcher) { |
| std::set<std::string> scopes{"scope"}; |
| AccessTokenFetcher::TokenCallback callback = base::BindOnce( |
| [](GoogleServiceAuthError error, AccessTokenInfo access_token_info) {}); |
| std::unique_ptr<AccessTokenFetcher> token_fetcher = |
| identity_manager()->CreateAccessTokenFetcherForAccount( |
| identity_manager()->GetPrimaryAccountId(signin::ConsentLevel::kSync), |
| kTestConsumerId, scopes, std::move(callback), |
| AccessTokenFetcher::Mode::kImmediate); |
| EXPECT_TRUE(token_fetcher); |
| } |
| |
| TEST_F(IdentityManagerTest, |
| CreateAccessTokenFetcherWithCustomURLLoaderFactory) { |
| base::RunLoop run_loop; |
| identity_manager_diagnostics_observer() |
| ->set_on_access_token_requested_callback(run_loop.QuitClosure()); |
| |
| identity_manager()->GetAccountTrackerService()->SeedAccountInfo(kTestGaiaId, |
| kTestEmail); |
| identity_manager()->GetPrimaryAccountMutator()->SetPrimaryAccount( |
| primary_account_id(), ConsentLevel::kSync); |
| SetRefreshTokenForAccount(identity_manager(), primary_account_id(), |
| "refresh_token"); |
| |
| std::set<std::string> scopes{"scope"}; |
| AccessTokenFetcher::TokenCallback callback = base::BindOnce( |
| [](GoogleServiceAuthError error, AccessTokenInfo access_token_info) {}); |
| |
| // We first create and AccessTokenFetcher with a custom URLLoaderFactory, |
| // to check that such factory is actually used in the requests generated. |
| network::TestURLLoaderFactory test_url_loader_factory; |
| scoped_refptr<network::SharedURLLoaderFactory> test_shared_url_loader_factory( |
| base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( |
| &test_url_loader_factory)); |
| std::unique_ptr<AccessTokenFetcher> token_fetcher = |
| identity_manager()->CreateAccessTokenFetcherForAccount( |
| primary_account_id(), kTestConsumerId, test_shared_url_loader_factory, |
| scopes, std::move(callback), AccessTokenFetcher::Mode::kImmediate); |
| |
| run_loop.Run(); |
| |
| // The URLLoaderFactory present in the pending request should match |
| // the one we specified when creating the AccessTokenFetcher. |
| std::vector<FakeOAuth2AccessTokenManager::PendingRequest> pending_requests = |
| token_service()->GetPendingRequests(); |
| EXPECT_EQ(pending_requests.size(), 1U); |
| EXPECT_EQ(pending_requests[0].url_loader_factory, |
| test_shared_url_loader_factory); |
| |
| // The account ID and consumer's name should match the data passed as well. |
| EXPECT_EQ( |
| primary_account_id(), |
| identity_manager_diagnostics_observer()->token_requestor_account_id()); |
| EXPECT_EQ( |
| kTestConsumerId, |
| identity_manager_diagnostics_observer()->token_requestor_consumer_id()); |
| |
| // Cancel the pending request in preparation to check that creating an |
| // AccessTokenFetcher without a custom factory works as expected as well. |
| token_service()->IssueErrorForAllPendingRequestsForAccount( |
| primary_account_id(), |
| GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED)); |
| |
| // Now add a second account and request an access token for it to test |
| // that the default URLLoaderFactory is used if none is specified. |
| base::RunLoop run_loop2; |
| identity_manager_diagnostics_observer() |
| ->set_on_access_token_requested_callback(run_loop2.QuitClosure()); |
| |
| account_tracker()->SeedAccountInfo(kTestGaiaId2, kTestEmail2); |
| CoreAccountId account_id2 = |
| account_tracker()->FindAccountInfoByGaiaId(kTestGaiaId2).account_id; |
| SetRefreshTokenForAccount(identity_manager(), account_id2, "refresh_token"); |
| |
| // No changes to the declared scopes, we can reuse it. |
| callback = base::BindOnce( |
| [](GoogleServiceAuthError error, AccessTokenInfo access_token_info) {}); |
| std::unique_ptr<AccessTokenFetcher> token_fetcher2 = |
| identity_manager()->CreateAccessTokenFetcherForAccount( |
| account_id2, kTestConsumerId2, scopes, std::move(callback), |
| AccessTokenFetcher::Mode::kImmediate); |
| |
| run_loop2.Run(); |
| |
| // There should be one pending request now as well, just like before. |
| std::vector<FakeOAuth2AccessTokenManager::PendingRequest> pending_requests2 = |
| token_service()->GetPendingRequests(); |
| EXPECT_EQ(pending_requests2.size(), 1U); |
| |
| // The URLLoaderFactory present in the pending request should match |
| // the one created by default for the token service's delegate. |
| ProfileOAuth2TokenServiceDelegate* service_delegate = |
| token_service()->GetDelegate(); |
| EXPECT_EQ(pending_requests2[0].url_loader_factory, |
| service_delegate->GetURLLoaderFactory()); |
| |
| // The account ID and consumer's name should match the data passed again. |
| EXPECT_EQ( |
| account_id2, |
| identity_manager_diagnostics_observer()->token_requestor_account_id()); |
| EXPECT_EQ( |
| kTestConsumerId2, |
| identity_manager_diagnostics_observer()->token_requestor_consumer_id()); |
| } |
| |
| TEST_F(IdentityManagerTest, ObserveAccessTokenFetch) { |
| base::RunLoop run_loop; |
| identity_manager_diagnostics_observer() |
| ->set_on_access_token_requested_callback(run_loop.QuitClosure()); |
| |
| identity_manager()->GetAccountTrackerService()->SeedAccountInfo(kTestGaiaId, |
| kTestEmail); |
| identity_manager()->GetPrimaryAccountMutator()->SetPrimaryAccount( |
| primary_account_id(), ConsentLevel::kSync); |
| SetRefreshTokenForAccount(identity_manager(), primary_account_id(), |
| "refresh_token"); |
| |
| std::set<std::string> scopes{"scope"}; |
| AccessTokenFetcher::TokenCallback callback = base::BindOnce( |
| [](GoogleServiceAuthError error, AccessTokenInfo access_token_info) {}); |
| std::unique_ptr<AccessTokenFetcher> token_fetcher = |
| identity_manager()->CreateAccessTokenFetcherForAccount( |
| identity_manager()->GetPrimaryAccountId(signin::ConsentLevel::kSync), |
| kTestConsumerId, scopes, std::move(callback), |
| AccessTokenFetcher::Mode::kImmediate); |
| |
| run_loop.Run(); |
| |
| EXPECT_EQ( |
| primary_account_id(), |
| identity_manager_diagnostics_observer()->token_requestor_account_id()); |
| EXPECT_EQ( |
| kTestConsumerId, |
| identity_manager_diagnostics_observer()->token_requestor_consumer_id()); |
| EXPECT_EQ(scopes, |
| identity_manager_diagnostics_observer()->token_requestor_scopes()); |
| } |
| |
| TEST_F(IdentityManagerTest, |
| ObserveAccessTokenRequestCompletionWithoutRefreshToken) { |
| base::RunLoop run_loop; |
| identity_manager_diagnostics_observer() |
| ->set_on_access_token_request_completed_callback(run_loop.QuitClosure()); |
| |
| std::set<std::string> scopes{"scope"}; |
| AccessTokenFetcher::TokenCallback callback = base::BindOnce( |
| [](GoogleServiceAuthError error, AccessTokenInfo access_token_info) {}); |
| // Account has no refresh token. |
| std::unique_ptr<AccessTokenFetcher> token_fetcher = |
| identity_manager()->CreateAccessTokenFetcherForAccount( |
| identity_manager()->GetPrimaryAccountId(signin::ConsentLevel::kSync), |
| kTestConsumerId, scopes, std::move(callback), |
| AccessTokenFetcher::Mode::kImmediate); |
| |
| run_loop.Run(); |
| |
| EXPECT_TRUE(token_fetcher); |
| EXPECT_EQ(GoogleServiceAuthError(GoogleServiceAuthError::USER_NOT_SIGNED_UP), |
| identity_manager_diagnostics_observer() |
| ->on_access_token_request_completed_error()); |
| } |
| |
| TEST_F(IdentityManagerTest, |
| ObserveAccessTokenRequestCompletionWithRefreshToken) { |
| base::RunLoop run_loop; |
| identity_manager_diagnostics_observer() |
| ->set_on_access_token_request_completed_callback(run_loop.QuitClosure()); |
| |
| identity_manager()->GetAccountTrackerService()->SeedAccountInfo(kTestGaiaId, |
| kTestEmail); |
| identity_manager()->GetPrimaryAccountMutator()->SetPrimaryAccount( |
| primary_account_id(), ConsentLevel::kSync); |
| SetRefreshTokenForAccount(identity_manager(), primary_account_id(), |
| "refresh_token"); |
| token_service()->set_auto_post_fetch_response_on_message_loop(true); |
| |
| std::set<std::string> scopes{"scope"}; |
| AccessTokenFetcher::TokenCallback callback = base::BindOnce( |
| [](GoogleServiceAuthError error, AccessTokenInfo access_token_info) {}); |
| // This should result in a request for an access token without an error. |
| std::unique_ptr<AccessTokenFetcher> token_fetcher = |
| identity_manager()->CreateAccessTokenFetcherForAccount( |
| identity_manager()->GetPrimaryAccountId(signin::ConsentLevel::kSync), |
| kTestConsumerId, scopes, std::move(callback), |
| AccessTokenFetcher::Mode::kImmediate); |
| |
| run_loop.Run(); |
| |
| EXPECT_TRUE(token_fetcher); |
| EXPECT_EQ(primary_account_id(), |
| identity_manager_diagnostics_observer() |
| ->on_access_token_request_completed_account_id()); |
| EXPECT_EQ(kTestConsumerId, |
| identity_manager_diagnostics_observer() |
| ->on_access_token_request_completed_consumer_id()); |
| EXPECT_EQ(scopes, identity_manager_diagnostics_observer() |
| ->on_access_token_request_completed_scopes()); |
| EXPECT_EQ(GoogleServiceAuthError(GoogleServiceAuthError::NONE), |
| identity_manager_diagnostics_observer() |
| ->on_access_token_request_completed_error()); |
| } |
| |
| TEST_F(IdentityManagerTest, |
| ObserveAccessTokenRequestCompletionAfterRevokingRefreshToken) { |
| base::RunLoop run_loop; |
| identity_manager_diagnostics_observer() |
| ->set_on_access_token_request_completed_callback(run_loop.QuitClosure()); |
| |
| account_tracker()->SeedAccountInfo(kTestGaiaId2, kTestEmail2); |
| CoreAccountId account_id2 = |
| account_tracker()->FindAccountInfoByGaiaId(kTestGaiaId2).account_id; |
| SetRefreshTokenForAccount(identity_manager(), account_id2, "refresh_token"); |
| |
| std::set<std::string> scopes{"scope"}; |
| AccessTokenFetcher::TokenCallback callback = base::BindOnce( |
| [](GoogleServiceAuthError error, AccessTokenInfo access_token_info) {}); |
| // This should result in a request for an access token. |
| std::unique_ptr<AccessTokenFetcher> token_fetcher = |
| identity_manager()->CreateAccessTokenFetcherForAccount( |
| account_id2, kTestConsumerId2, scopes, std::move(callback), |
| AccessTokenFetcher::Mode::kImmediate); |
| |
| // Revoke the refresh token result cancelling access token request. |
| RemoveRefreshTokenForAccount(identity_manager(), account_id2); |
| |
| run_loop.Run(); |
| |
| EXPECT_TRUE(token_fetcher); |
| EXPECT_EQ(GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED), |
| identity_manager_diagnostics_observer() |
| ->on_access_token_request_completed_error()); |
| } |
| |
| TEST_F(IdentityManagerTest, GetAccountsCookieMutator) { |
| AccountsCookieMutator* mutator = |
| identity_manager()->GetAccountsCookieMutator(); |
| EXPECT_TRUE(mutator); |
| } |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| // On ChromeOS, AccountTrackerService first receives the normalized email |
| // address from GAIA and then later has it updated with the user's |
| // originally-specified version of their email address (at the time of that |
| // address' creation). This latter will differ if the user's originally- |
| // specified address was not in normalized form (e.g., if it contained |
| // periods). This test simulates such a flow in order to verify that |
| // IdentityManager correctly reflects the updated version. See crbug.com/842041 |
| // and crbug.com/842670 for further details. |
| TEST_F(IdentityManagerTest, IdentityManagerReflectsUpdatedEmailAddress) { |
| CoreAccountInfo primary_account_info = |
| identity_manager()->GetPrimaryAccountInfo(signin::ConsentLevel::kSync); |
| EXPECT_EQ(kTestGaiaId, primary_account_info.gaia); |
| EXPECT_EQ(kTestEmail, primary_account_info.email); |
| |
| // Simulate the flow wherein the user's email address was updated |
| // to the originally-created non-normalized version. |
| SimulateSuccessfulFetchOfAccountInfo( |
| identity_manager(), primary_account_info.account_id, kTestEmailWithPeriod, |
| kTestGaiaId, kTestHostedDomain, kTestFullName, kTestGivenName, |
| kTestLocale, kTestPictureUrl); |
| // Verify that IdentityManager reflects the update. |
| primary_account_info = |
| identity_manager()->GetPrimaryAccountInfo(signin::ConsentLevel::kSync); |
| EXPECT_EQ(kTestGaiaId, primary_account_info.gaia); |
| EXPECT_EQ(kTestEmailWithPeriod, primary_account_info.email); |
| EXPECT_EQ(identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSignin), |
| primary_account_info); |
| } |
| #endif |
| |
| TEST_F(IdentityManagerTest, |
| CallbackSentOnPrimaryAccountRefreshTokenUpdateWithValidToken) { |
| SetRefreshTokenForPrimaryAccount(identity_manager()); |
| |
| CoreAccountInfo account_info = |
| identity_manager_observer()->AccountFromRefreshTokenUpdatedCallback(); |
| EXPECT_EQ(kTestGaiaId, account_info.gaia); |
| EXPECT_EQ(kTestEmail, account_info.email); |
| } |
| |
| TEST_F(IdentityManagerTest, |
| CallbackSentOnPrimaryAccountRefreshTokenUpdateWithInvalidToken) { |
| SetInvalidRefreshTokenForPrimaryAccount(identity_manager()); |
| |
| CoreAccountInfo account_info = |
| identity_manager_observer()->AccountFromRefreshTokenUpdatedCallback(); |
| EXPECT_EQ(kTestGaiaId, account_info.gaia); |
| EXPECT_EQ(kTestEmail, account_info.email); |
| } |
| |
| TEST_F(IdentityManagerTest, CallbackSentOnPrimaryAccountRefreshTokenRemoval) { |
| SetRefreshTokenForPrimaryAccount(identity_manager()); |
| |
| RemoveRefreshTokenForPrimaryAccount(identity_manager()); |
| |
| EXPECT_EQ( |
| primary_account_id(), |
| identity_manager_observer()->AccountIdFromRefreshTokenRemovedCallback()); |
| } |
| |
| TEST_F(IdentityManagerTest, |
| CallbackSentOnSecondaryAccountRefreshTokenUpdateWithValidToken) { |
| AccountInfo expected_account_info = |
| MakeAccountAvailable(identity_manager(), kTestEmail2); |
| EXPECT_EQ(kTestEmail2, expected_account_info.email); |
| |
| CoreAccountInfo account_info = |
| identity_manager_observer()->AccountFromRefreshTokenUpdatedCallback(); |
| EXPECT_EQ(expected_account_info.account_id, account_info.account_id); |
| EXPECT_EQ(expected_account_info.gaia, account_info.gaia); |
| EXPECT_EQ(expected_account_info.email, account_info.email); |
| } |
| |
| TEST_F(IdentityManagerTest, |
| CallbackSentOnSecondaryAccountRefreshTokenUpdateWithInvalidToken) { |
| AccountInfo expected_account_info = |
| MakeAccountAvailable(identity_manager(), kTestEmail2); |
| EXPECT_EQ(kTestEmail2, expected_account_info.email); |
| |
| SetInvalidRefreshTokenForAccount(identity_manager(), |
| expected_account_info.account_id); |
| |
| CoreAccountInfo account_info = |
| identity_manager_observer()->AccountFromRefreshTokenUpdatedCallback(); |
| EXPECT_EQ(expected_account_info.account_id, account_info.account_id); |
| EXPECT_EQ(expected_account_info.gaia, account_info.gaia); |
| EXPECT_EQ(expected_account_info.email, account_info.email); |
| } |
| |
| TEST_F(IdentityManagerTest, CallbackSentOnSecondaryAccountRefreshTokenRemoval) { |
| AccountInfo expected_account_info = |
| MakeAccountAvailable(identity_manager(), kTestEmail2); |
| EXPECT_EQ(kTestEmail2, expected_account_info.email); |
| |
| RemoveRefreshTokenForAccount(identity_manager(), |
| expected_account_info.account_id); |
| |
| EXPECT_EQ( |
| expected_account_info.account_id, |
| identity_manager_observer()->AccountIdFromRefreshTokenRemovedCallback()); |
| } |
| |
| #if !BUILDFLAG(IS_CHROMEOS_ASH) |
| TEST_F( |
| IdentityManagerTest, |
| CallbackSentOnSecondaryAccountRefreshTokenUpdateWithValidTokenWhenNoPrimaryAccount) { |
| ClearPrimaryAccount(identity_manager()); |
| |
| // Add an unconsented primary account, incl. proper cookies. |
| AccountInfo expected_account_info = MakeAccountAvailableWithCookies( |
| identity_manager(), test_url_loader_factory(), kTestEmail2, kTestGaiaId2); |
| EXPECT_EQ(kTestEmail2, expected_account_info.email); |
| |
| CoreAccountInfo account_info = |
| identity_manager_observer()->AccountFromRefreshTokenUpdatedCallback(); |
| EXPECT_EQ(expected_account_info.account_id, account_info.account_id); |
| EXPECT_EQ(expected_account_info.gaia, account_info.gaia); |
| EXPECT_EQ(expected_account_info.email, account_info.email); |
| } |
| |
| TEST_F( |
| IdentityManagerTest, |
| CallbackSentOnSecondaryAccountRefreshTokenUpdateWithInvalidTokenWhenNoPrimaryAccount) { |
| ClearPrimaryAccount(identity_manager()); |
| |
| // Add an unconsented primary account, incl. proper cookies. |
| AccountInfo expected_account_info = MakeAccountAvailableWithCookies( |
| identity_manager(), test_url_loader_factory(), kTestEmail2, kTestGaiaId2); |
| EXPECT_EQ(kTestEmail2, expected_account_info.email); |
| |
| SetInvalidRefreshTokenForAccount(identity_manager(), |
| expected_account_info.account_id); |
| |
| CoreAccountInfo account_info = |
| identity_manager_observer()->AccountFromRefreshTokenUpdatedCallback(); |
| EXPECT_EQ(expected_account_info.account_id, account_info.account_id); |
| EXPECT_EQ(expected_account_info.gaia, account_info.gaia); |
| EXPECT_EQ(expected_account_info.email, account_info.email); |
| } |
| |
| TEST_F(IdentityManagerTest, |
| CallbackSentOnSecondaryAccountRefreshTokenRemovalWhenNoPrimaryAccount) { |
| ClearPrimaryAccount(identity_manager()); |
| |
| // Add an unconsented primary account, incl. proper cookies. |
| AccountInfo expected_account_info = MakeAccountAvailableWithCookies( |
| identity_manager(), test_url_loader_factory(), kTestEmail2, kTestGaiaId2); |
| EXPECT_EQ(kTestEmail2, expected_account_info.email); |
| |
| RemoveRefreshTokenForAccount(identity_manager(), |
| expected_account_info.account_id); |
| |
| EXPECT_EQ( |
| expected_account_info.account_id, |
| identity_manager_observer()->AccountIdFromRefreshTokenRemovedCallback()); |
| } |
| |
| TEST_F(IdentityManagerTest, CallbackSentOnRefreshTokenRemovalOfUnknownAccount) { |
| // When the token service is still loading credentials, it may send token |
| // revoked callbacks for accounts that it has never sent a token available |
| // callback. Our common test setup actually completes this loading, so use the |
| // *for_testing() method below to simulate the race condition and ensure that |
| // IdentityManager passes on the callback in this case. |
| token_service()->set_all_credentials_loaded_for_testing(false); |
| |
| CoreAccountId dummy_account_id("dummy_account"); |
| |
| base::RunLoop run_loop; |
| token_service()->RevokeCredentials(dummy_account_id); |
| run_loop.RunUntilIdle(); |
| |
| EXPECT_EQ( |
| dummy_account_id, |
| identity_manager_observer()->AccountIdFromRefreshTokenRemovedCallback()); |
| } |
| #endif |
| |
| TEST_F(IdentityManagerTest, IdentityManagerGetsTokensLoadedEvent) { |
| base::RunLoop run_loop; |
| identity_manager_observer()->SetOnRefreshTokensLoadedCallback( |
| run_loop.QuitClosure()); |
| |
| // Credentials are already loaded in PrimaryAccountManager::Initialize() |
| // which runs even before the IdentityManager is created. That's why |
| // we fake the credentials loaded state and force another load in |
| // order to be able to capture the TokensLoaded event. |
| token_service()->set_all_credentials_loaded_for_testing(false); |
| token_service()->LoadCredentials(CoreAccountId()); |
| run_loop.Run(); |
| } |
| |
| TEST_F(IdentityManagerTest, |
| CallbackSentOnUpdateToAccountsInCookieWithNoAccounts) { |
| base::RunLoop run_loop; |
| identity_manager_observer()->SetOnAccountsInCookieUpdatedCallback( |
| run_loop.QuitClosure()); |
| |
| SetListAccountsResponseNoAccounts(test_url_loader_factory()); |
| identity_manager()->GetGaiaCookieManagerService()->TriggerListAccounts(); |
| run_loop.Run(); |
| |
| const AccountsInCookieJarInfo& accounts_in_cookie_jar_info = |
| identity_manager_observer() |
| ->AccountsInfoFromAccountsInCookieUpdatedCallback(); |
| EXPECT_TRUE(accounts_in_cookie_jar_info.accounts_are_fresh); |
| EXPECT_TRUE(accounts_in_cookie_jar_info.signed_in_accounts.empty()); |
| } |
| |
| TEST_F(IdentityManagerTest, |
| CallbackSentOnUpdateToAccountsInCookieWithOneAccount) { |
| base::RunLoop run_loop; |
| identity_manager_observer()->SetOnAccountsInCookieUpdatedCallback( |
| run_loop.QuitClosure()); |
| |
| SetListAccountsResponseOneAccount(kTestEmail, kTestGaiaId, |
| test_url_loader_factory()); |
| identity_manager()->GetGaiaCookieManagerService()->TriggerListAccounts(); |
| run_loop.Run(); |
| |
| const AccountsInCookieJarInfo& accounts_in_cookie_jar_info = |
| identity_manager_observer() |
| ->AccountsInfoFromAccountsInCookieUpdatedCallback(); |
| EXPECT_TRUE(accounts_in_cookie_jar_info.accounts_are_fresh); |
| ASSERT_EQ(1u, accounts_in_cookie_jar_info.signed_in_accounts.size()); |
| ASSERT_TRUE(accounts_in_cookie_jar_info.signed_out_accounts.empty()); |
| |
| gaia::ListedAccount listed_account = |
| accounts_in_cookie_jar_info.signed_in_accounts[0]; |
| EXPECT_EQ( |
| identity_manager()->PickAccountIdForAccount(kTestGaiaId, kTestEmail), |
| listed_account.id); |
| EXPECT_EQ(kTestGaiaId, listed_account.gaia_id); |
| EXPECT_EQ(kTestEmail, listed_account.email); |
| } |
| |
| TEST_F(IdentityManagerTest, |
| CallbackSentOnUpdateToAccountsInCookieWithTwoAccounts) { |
| base::RunLoop run_loop; |
| identity_manager_observer()->SetOnAccountsInCookieUpdatedCallback( |
| run_loop.QuitClosure()); |
| |
| SetListAccountsResponseTwoAccounts(kTestEmail, kTestGaiaId, kTestEmail2, |
| kTestGaiaId2, test_url_loader_factory()); |
| identity_manager()->GetGaiaCookieManagerService()->TriggerListAccounts(); |
| run_loop.Run(); |
| |
| const AccountsInCookieJarInfo& accounts_in_cookie_jar_info = |
| identity_manager_observer() |
| ->AccountsInfoFromAccountsInCookieUpdatedCallback(); |
| EXPECT_TRUE(accounts_in_cookie_jar_info.accounts_are_fresh); |
| ASSERT_EQ(2u, accounts_in_cookie_jar_info.signed_in_accounts.size()); |
| ASSERT_TRUE(accounts_in_cookie_jar_info.signed_out_accounts.empty()); |
| |
| // Verify not only that both accounts are present but that they are listed in |
| // the expected order as well. |
| gaia::ListedAccount listed_account1 = |
| accounts_in_cookie_jar_info.signed_in_accounts[0]; |
| EXPECT_EQ( |
| identity_manager()->PickAccountIdForAccount(kTestGaiaId, kTestEmail), |
| listed_account1.id); |
| EXPECT_EQ(kTestGaiaId, listed_account1.gaia_id); |
| EXPECT_EQ(kTestEmail, listed_account1.email); |
| |
| gaia::ListedAccount account_info2 = |
| accounts_in_cookie_jar_info.signed_in_accounts[1]; |
| EXPECT_EQ( |
| identity_manager()->PickAccountIdForAccount(kTestGaiaId2, kTestEmail2), |
| account_info2.id); |
| EXPECT_EQ(kTestGaiaId2, account_info2.gaia_id); |
| EXPECT_EQ(kTestEmail2, account_info2.email); |
| } |
| |
| TEST_F(IdentityManagerTest, CallbackSentOnUpdateToSignOutAccountsInCookie) { |
| struct SignedOutStatus { |
| bool account_1; |
| bool account_2; |
| } signed_out_status_set[] = { |
| {false, false}, {true, false}, {false, true}, {true, true}}; |
| |
| for (const auto& signed_out_status : signed_out_status_set) { |
| base::RunLoop run_loop; |
| identity_manager_observer()->SetOnAccountsInCookieUpdatedCallback( |
| run_loop.QuitClosure()); |
| |
| SetListAccountsResponseWithParams( |
| {{kTestEmail, kTestGaiaId, true /* valid */, |
| signed_out_status.account_1 /* signed_out */, true /* verified */}, |
| {kTestEmail2, kTestGaiaId2, true /* valid */, |
| signed_out_status.account_2 /* signed_out */, true /* verified */}}, |
| test_url_loader_factory()); |
| |
| identity_manager()->GetGaiaCookieManagerService()->TriggerListAccounts(); |
| run_loop.Run(); |
| |
| size_t accounts_signed_out = size_t{signed_out_status.account_1} + |
| size_t{signed_out_status.account_2}; |
| const AccountsInCookieJarInfo& accounts_in_cookie_jar_info = |
| identity_manager_observer() |
| ->AccountsInfoFromAccountsInCookieUpdatedCallback(); |
| EXPECT_TRUE(accounts_in_cookie_jar_info.accounts_are_fresh); |
| ASSERT_EQ(2 - accounts_signed_out, |
| accounts_in_cookie_jar_info.signed_in_accounts.size()); |
| ASSERT_EQ(accounts_signed_out, |
| accounts_in_cookie_jar_info.signed_out_accounts.size()); |
| |
| // Verify not only that both accounts are present but that they are listed |
| // in the expected order as well. |
| // |
| // The two variables below, control the lookup indexes signed in and signed |
| // out accounts list, respectively. |
| int i = 0, j = 0; |
| gaia::ListedAccount listed_account1 = |
| signed_out_status.account_1 |
| ? accounts_in_cookie_jar_info.signed_out_accounts[i++] |
| : accounts_in_cookie_jar_info.signed_in_accounts[j++]; |
| if (!signed_out_status.account_1) |
| EXPECT_EQ( |
| identity_manager()->PickAccountIdForAccount(kTestGaiaId, kTestEmail), |
| listed_account1.id); |
| EXPECT_EQ(kTestGaiaId, listed_account1.gaia_id); |
| EXPECT_EQ(kTestEmail, listed_account1.email); |
| |
| gaia::ListedAccount listed_account2 = |
| signed_out_status.account_2 |
| ? accounts_in_cookie_jar_info.signed_out_accounts[i++] |
| : accounts_in_cookie_jar_info.signed_in_accounts[j++]; |
| if (!signed_out_status.account_2) |
| EXPECT_EQ(identity_manager()->PickAccountIdForAccount(kTestGaiaId2, |
| kTestEmail2), |
| listed_account2.id); |
| EXPECT_EQ(kTestGaiaId2, listed_account2.gaia_id); |
| EXPECT_EQ(kTestEmail2, listed_account2.email); |
| } |
| } |
| |
| TEST_F(IdentityManagerTest, |
| CallbackSentOnUpdateToAccountsInCookieWithStaleAccounts) { |
| base::RunLoop run_loop; |
| identity_manager_observer()->SetOnAccountsInCookieUpdatedCallback( |
| run_loop.QuitClosure()); |
| |
| // Configure list accounts to return a permanent Gaia auth error. |
| SetListAccountsResponseWithUnexpectedServiceResponse( |
| test_url_loader_factory()); |
| identity_manager()->GetGaiaCookieManagerService()->TriggerListAccounts(); |
| run_loop.Run(); |
| |
| const AccountsInCookieJarInfo& accounts_in_cookie_jar_info = |
| identity_manager_observer() |
| ->AccountsInfoFromAccountsInCookieUpdatedCallback(); |
| EXPECT_FALSE(accounts_in_cookie_jar_info.accounts_are_fresh); |
| EXPECT_TRUE(accounts_in_cookie_jar_info.signed_in_accounts.empty()); |
| EXPECT_TRUE(accounts_in_cookie_jar_info.signed_out_accounts.empty()); |
| } |
| |
| TEST_F(IdentityManagerTest, GetAccountsInCookieJarWithNoAccounts) { |
| base::RunLoop run_loop; |
| identity_manager_observer()->SetOnAccountsInCookieUpdatedCallback( |
| run_loop.QuitClosure()); |
| |
| SetListAccountsResponseNoAccounts(test_url_loader_factory()); |
| |
| // Do an initial call to GetAccountsInCookieJar(). This call should return no |
| // accounts but should also trigger an internal update and eventual |
| // notification that the accounts in the cookie jar have been updated. |
| const AccountsInCookieJarInfo& accounts_in_cookie_jar = |
| identity_manager()->GetAccountsInCookieJar(); |
| EXPECT_FALSE(accounts_in_cookie_jar.accounts_are_fresh); |
| EXPECT_TRUE(accounts_in_cookie_jar.signed_in_accounts.empty()); |
| EXPECT_TRUE(accounts_in_cookie_jar.signed_out_accounts.empty()); |
| |
| run_loop.Run(); |
| |
| // The state of the accounts in IdentityManager should now reflect the |
| // internal update. |
| const AccountsInCookieJarInfo updated_accounts_in_cookie_jar = |
| identity_manager()->GetAccountsInCookieJar(); |
| |
| EXPECT_TRUE(updated_accounts_in_cookie_jar.accounts_are_fresh); |
| EXPECT_TRUE(updated_accounts_in_cookie_jar.signed_in_accounts.empty()); |
| EXPECT_TRUE(updated_accounts_in_cookie_jar.signed_out_accounts.empty()); |
| } |
| |
| TEST_F(IdentityManagerTest, GetAccountsInCookieJarWithOneAccount) { |
| base::RunLoop run_loop; |
| identity_manager_observer()->SetOnAccountsInCookieUpdatedCallback( |
| run_loop.QuitClosure()); |
| |
| SetListAccountsResponseOneAccount(kTestEmail, kTestGaiaId, |
| test_url_loader_factory()); |
| |
| // Do an initial call to GetAccountsInCookieJar(). This call should return no |
| // accounts but should also trigger an internal update and eventual |
| // notification that the accounts in the cookie jar have been updated. |
| const AccountsInCookieJarInfo& accounts_in_cookie_jar = |
| identity_manager()->GetAccountsInCookieJar(); |
| EXPECT_FALSE(accounts_in_cookie_jar.accounts_are_fresh); |
| EXPECT_TRUE(accounts_in_cookie_jar.signed_in_accounts.empty()); |
| EXPECT_TRUE(accounts_in_cookie_jar.signed_out_accounts.empty()); |
| |
| run_loop.Run(); |
| |
| // The state of the accounts in IdentityManager should now reflect the |
| // internal update. |
| const AccountsInCookieJarInfo& updated_accounts_in_cookie_jar = |
| identity_manager()->GetAccountsInCookieJar(); |
| |
| EXPECT_TRUE(updated_accounts_in_cookie_jar.accounts_are_fresh); |
| ASSERT_EQ(1u, updated_accounts_in_cookie_jar.signed_in_accounts.size()); |
| ASSERT_TRUE(updated_accounts_in_cookie_jar.signed_out_accounts.empty()); |
| |
| gaia::ListedAccount listed_account = |
| updated_accounts_in_cookie_jar.signed_in_accounts[0]; |
| EXPECT_EQ( |
| identity_manager()->PickAccountIdForAccount(kTestGaiaId, kTestEmail), |
| listed_account.id); |
| EXPECT_EQ(kTestGaiaId, listed_account.gaia_id); |
| EXPECT_EQ(kTestEmail, listed_account.email); |
| } |
| |
| TEST_F(IdentityManagerTest, GetAccountsInCookieJarWithTwoAccounts) { |
| base::RunLoop run_loop; |
| identity_manager_observer()->SetOnAccountsInCookieUpdatedCallback( |
| run_loop.QuitClosure()); |
| |
| SetListAccountsResponseTwoAccounts(kTestEmail, kTestGaiaId, kTestEmail2, |
| kTestGaiaId2, test_url_loader_factory()); |
| |
| // Do an initial call to GetAccountsInCookieJar(). This call should return no |
| // accounts but should also trigger an internal update and eventual |
| // notification that the accounts in the cookie jar have been updated. |
| const AccountsInCookieJarInfo& accounts_in_cookie_jar = |
| identity_manager()->GetAccountsInCookieJar(); |
| EXPECT_FALSE(accounts_in_cookie_jar.accounts_are_fresh); |
| EXPECT_TRUE(accounts_in_cookie_jar.signed_in_accounts.empty()); |
| EXPECT_TRUE(accounts_in_cookie_jar.signed_out_accounts.empty()); |
| |
| run_loop.Run(); |
| |
| // The state of the accounts in IdentityManager should now reflect the |
| // internal update. |
| const AccountsInCookieJarInfo& updated_accounts_in_cookie_jar = |
| identity_manager()->GetAccountsInCookieJar(); |
| |
| EXPECT_TRUE(updated_accounts_in_cookie_jar.accounts_are_fresh); |
| ASSERT_EQ(2u, updated_accounts_in_cookie_jar.signed_in_accounts.size()); |
| ASSERT_TRUE(updated_accounts_in_cookie_jar.signed_out_accounts.empty()); |
| |
| // Verify not only that both accounts are present but that they are listed in |
| // the expected order as well. |
| gaia::ListedAccount listed_account1 = |
| updated_accounts_in_cookie_jar.signed_in_accounts[0]; |
| EXPECT_EQ( |
| identity_manager()->PickAccountIdForAccount(kTestGaiaId, kTestEmail), |
| listed_account1.id); |
| EXPECT_EQ(kTestGaiaId, listed_account1.gaia_id); |
| EXPECT_EQ(kTestEmail, listed_account1.email); |
| |
| gaia::ListedAccount listed_account2 = |
| updated_accounts_in_cookie_jar.signed_in_accounts[1]; |
| EXPECT_EQ( |
| identity_manager()->PickAccountIdForAccount(kTestGaiaId2, kTestEmail2), |
| listed_account2.id); |
| EXPECT_EQ(kTestGaiaId2, listed_account2.gaia_id); |
| EXPECT_EQ(kTestEmail2, listed_account2.email); |
| } |
| |
| TEST_F(IdentityManagerTest, CallbackSentOnSuccessfulAdditionOfAccountToCookie) { |
| const CoreAccountId kTestAccountId("account_id"); |
| |
| CoreAccountId account_from_add_account_to_cookie_completed_callback; |
| GoogleServiceAuthError error_from_add_account_to_cookie_completed_callback; |
| auto completion_callback = |
| base::BindLambdaForTesting([&](const CoreAccountId& account_id, |
| const GoogleServiceAuthError& error) { |
| account_from_add_account_to_cookie_completed_callback = account_id; |
| error_from_add_account_to_cookie_completed_callback = error; |
| }); |
| |
| identity_manager()->GetGaiaCookieManagerService()->AddAccountToCookie( |
| kTestAccountId, gaia::GaiaSource::kChrome, |
| std::move(completion_callback)); |
| SimulateAdditionOfAccountToCookieSuccess( |
| identity_manager()->GetGaiaCookieManagerService(), "token"); |
| EXPECT_EQ(account_from_add_account_to_cookie_completed_callback, |
| kTestAccountId); |
| EXPECT_EQ(error_from_add_account_to_cookie_completed_callback, |
| GoogleServiceAuthError::AuthErrorNone()); |
| } |
| |
| TEST_F(IdentityManagerTest, CallbackSentOnFailureAdditionOfAccountToCookie) { |
| const CoreAccountId kTestAccountId("account_id"); |
| |
| CoreAccountId account_from_add_account_to_cookie_completed_callback; |
| GoogleServiceAuthError error_from_add_account_to_cookie_completed_callback; |
| auto completion_callback = |
| base::BindLambdaForTesting([&](const CoreAccountId& account_id, |
| const GoogleServiceAuthError& error) { |
| account_from_add_account_to_cookie_completed_callback = account_id; |
| error_from_add_account_to_cookie_completed_callback = error; |
| }); |
| |
| identity_manager()->GetGaiaCookieManagerService()->AddAccountToCookie( |
| kTestAccountId, gaia::GaiaSource::kChrome, |
| std::move(completion_callback)); |
| |
| GoogleServiceAuthError error(GoogleServiceAuthError::SERVICE_ERROR); |
| SimulateAdditionOfAccountToCookieSuccessFailure( |
| identity_manager()->GetGaiaCookieManagerService(), error); |
| |
| EXPECT_EQ(account_from_add_account_to_cookie_completed_callback, |
| kTestAccountId); |
| EXPECT_EQ(error_from_add_account_to_cookie_completed_callback, error); |
| } |
| |
| TEST_F(IdentityManagerTest, |
| CallbackSentOnSetAccountsInCookieCompleted_Success) { |
| const CoreAccountId kTestAccountId("account_id"); |
| const CoreAccountId kTestAccountId2("account_id2"); |
| const std::vector<std::pair<CoreAccountId, std::string>> accounts = { |
| {kTestAccountId, kTestAccountId.ToString()}, |
| {kTestAccountId2, kTestAccountId2.ToString()}}; |
| |
| SetAccountsInCookieResult |
| error_from_set_accounts_in_cookie_completed_callback; |
| auto completion_callback = base::BindLambdaForTesting( |
| [&error_from_set_accounts_in_cookie_completed_callback]( |
| SetAccountsInCookieResult error) { |
| error_from_set_accounts_in_cookie_completed_callback = error; |
| }); |
| |
| // Needed to insert request in the queue. |
| identity_manager()->GetGaiaCookieManagerService()->SetAccountsInCookie( |
| gaia::MultiloginMode::MULTILOGIN_UPDATE_COOKIE_ACCOUNTS_ORDER, accounts, |
| gaia::GaiaSource::kChrome, std::move(completion_callback)); |
| |
| SimulateOAuthMultiloginFinished( |
| identity_manager()->GetGaiaCookieManagerService(), |
| SetAccountsInCookieResult::kSuccess); |
| |
| EXPECT_EQ(error_from_set_accounts_in_cookie_completed_callback, |
| SetAccountsInCookieResult::kSuccess); |
| } |
| |
| TEST_F(IdentityManagerTest, |
| CallbackSentOnSetAccountsInCookieCompleted_Failure) { |
| const CoreAccountId kTestAccountId("account_id"); |
| const CoreAccountId kTestAccountId2("account_id2"); |
| const std::vector<std::pair<CoreAccountId, std::string>> accounts = { |
| {kTestAccountId, kTestAccountId.ToString()}, |
| {kTestAccountId2, kTestAccountId2.ToString()}}; |
| |
| SetAccountsInCookieResult |
| error_from_set_accounts_in_cookie_completed_callback; |
| auto completion_callback = base::BindLambdaForTesting( |
| [&error_from_set_accounts_in_cookie_completed_callback]( |
| SetAccountsInCookieResult error) { |
| error_from_set_accounts_in_cookie_completed_callback = error; |
| }); |
| |
| // Needed to insert request in the queue. |
| identity_manager()->GetGaiaCookieManagerService()->SetAccountsInCookie( |
| gaia::MultiloginMode::MULTILOGIN_UPDATE_COOKIE_ACCOUNTS_ORDER, accounts, |
| gaia::GaiaSource::kChrome, std::move(completion_callback)); |
| |
| // Sample an erroneous response. |
| SetAccountsInCookieResult error = SetAccountsInCookieResult::kPersistentError; |
| |
| SimulateOAuthMultiloginFinished( |
| identity_manager()->GetGaiaCookieManagerService(), error); |
| |
| EXPECT_EQ(error_from_set_accounts_in_cookie_completed_callback, error); |
| } |
| |
| TEST_F(IdentityManagerTest, CallbackSentOnAccountsCookieDeletedByUserAction) { |
| base::RunLoop run_loop; |
| identity_manager_observer()->SetOnCookieDeletedByUserCallback( |
| run_loop.QuitClosure()); |
| auto cookie = net::CanonicalCookie::CreateUnsafeCookieForTesting( |
| "SAPISID", std::string(), ".google.com", "/", base::Time(), base::Time(), |
| base::Time(), /*secure=*/true, false, net::CookieSameSite::NO_RESTRICTION, |
| net::COOKIE_PRIORITY_DEFAULT, false); |
| SimulateCookieDeletedByUser(identity_manager()->GetGaiaCookieManagerService(), |
| *cookie); |
| run_loop.Run(); |
| } |
| |
| TEST_F(IdentityManagerTest, OnNetworkInitialized) { |
| auto test_cookie_manager = std::make_unique<network::TestCookieManager>(); |
| network::TestCookieManager* test_cookie_manager_ptr = |
| test_cookie_manager.get(); |
| signin_client()->set_cookie_manager(std::move(test_cookie_manager)); |
| |
| identity_manager()->OnNetworkInitialized(); |
| |
| base::RunLoop run_loop; |
| identity_manager_observer()->SetOnCookieDeletedByUserCallback( |
| run_loop.QuitClosure()); |
| |
| // Dispatch a known change of a known cookie instance *through the mojo |
| // pipe* in order to ensure the GCMS is listening to CookieManager changes. |
| // |
| // It is important the the cause of the change is known here (ie |
| // network::mojom::CookieChangeCause::EXPLICIT) so the test can block of the |
| // proper IdentityManager observer callback to be called (in this case |
| // OnAccountsCookieDeletedByUserAction). |
| // |
| // Note that this call differs from calling SimulateCookieDeletedByUser() |
| // directly in the sense that SimulateCookieDeletedByUser() does not go |
| // through any mojo pipe. |
| auto cookie = net::CanonicalCookie::CreateUnsafeCookieForTesting( |
| "SAPISID", std::string(), ".google.com", "/", base::Time(), base::Time(), |
| base::Time(), /*secure=*/true, false, net::CookieSameSite::NO_RESTRICTION, |
| net::COOKIE_PRIORITY_DEFAULT, false); |
| test_cookie_manager_ptr->DispatchCookieChange(net::CookieChangeInfo( |
| *cookie, net::CookieAccessResult(), net::CookieChangeCause::EXPLICIT)); |
| run_loop.Run(); |
| } |
| |
| TEST_F(IdentityManagerTest, |
| BatchChangeObserversAreNotifiedOnCredentialsUpdate) { |
| identity_manager()->GetAccountTrackerService()->SeedAccountInfo(kTestGaiaId, |
| kTestEmail); |
| identity_manager()->GetPrimaryAccountMutator()->SetPrimaryAccount( |
| primary_account_id(), ConsentLevel::kSync); |
| SetRefreshTokenForAccount(identity_manager(), primary_account_id(), |
| "refresh_token"); |
| |
| EXPECT_EQ(1ul, identity_manager_observer()->BatchChangeRecords().size()); |
| EXPECT_EQ(1ul, |
| identity_manager_observer()->BatchChangeRecords().at(0).size()); |
| EXPECT_EQ(primary_account_id(), |
| identity_manager_observer()->BatchChangeRecords().at(0).at(0)); |
| } |
| |
| // Check that FindExtendedAccountInfo returns a valid account info iff the |
| // account is known, and all the extended information is available. |
| TEST_F(IdentityManagerTest, FindExtendedAccountInfo) { |
| CoreAccountInfo account_info; |
| account_info.email = kTestEmail2; |
| account_info.gaia = kTestGaiaId2; |
| account_info.account_id = identity_manager()->PickAccountIdForAccount( |
| account_info.gaia, account_info.email); |
| |
| // FindExtendedAccountInfo() returns empty if the account_info is invalid. |
| EXPECT_TRUE( |
| identity_manager()->FindExtendedAccountInfo(CoreAccountInfo{}).IsEmpty()); |
| |
| // FindExtendedAccountInfo() returns empty if the account_info is unknown. |
| EXPECT_TRUE( |
| identity_manager()->FindExtendedAccountInfo(account_info).IsEmpty()); |
| |
| // Insert the core account information in the AccountTrackerService. |
| const CoreAccountId account_id = |
| account_tracker()->SeedAccountInfo(account_info.gaia, account_info.email); |
| ASSERT_EQ(account_info.account_id, account_id); |
| |
| // The refresh token is not available. |
| EXPECT_TRUE( |
| identity_manager()->FindExtendedAccountInfo(account_info).IsEmpty()); |
| |
| // FindExtendedAccountInfo() returns extended account information if the |
| // account is known and the token is available. |
| SetRefreshTokenForAccount(identity_manager(), account_info.account_id, |
| "token"); |
| const AccountInfo extended_account_info = |
| identity_manager()->FindExtendedAccountInfo(account_info); |
| EXPECT_TRUE(!extended_account_info.IsEmpty()); |
| EXPECT_EQ(account_info.gaia, extended_account_info.gaia); |
| EXPECT_EQ(account_info.email, extended_account_info.email); |
| EXPECT_EQ(account_info.account_id, extended_account_info.account_id); |
| } |
| |
| // Checks that FindExtendedAccountInfoByAccountId() returns information about |
| // the account if the account is found, or an empty account info. |
| TEST_F(IdentityManagerTest, FindExtendedAccountInfoByAccountId) { |
| CoreAccountInfo account_info; |
| account_info.email = kTestEmail2; |
| account_info.gaia = kTestGaiaId2; |
| account_info.account_id = identity_manager()->PickAccountIdForAccount( |
| account_info.gaia, account_info.email); |
| |
| // Account is unknown. |
| AccountInfo maybe_account_info = |
| identity_manager()->FindExtendedAccountInfoByAccountId( |
| account_info.account_id); |
| EXPECT_TRUE(maybe_account_info.IsEmpty()); |
| |
| // Refresh token is not available. |
| const CoreAccountId account_id = |
| account_tracker()->SeedAccountInfo(account_info.gaia, account_info.email); |
| maybe_account_info = identity_manager()->FindExtendedAccountInfoByAccountId( |
| account_info.account_id); |
| EXPECT_TRUE(maybe_account_info.IsEmpty()); |
| |
| // Account with refresh token. |
| SetRefreshTokenForAccount(identity_manager(), account_info.account_id, |
| "token"); |
| maybe_account_info = identity_manager()->FindExtendedAccountInfoByAccountId( |
| account_info.account_id); |
| EXPECT_FALSE(maybe_account_info.IsEmpty()); |
| EXPECT_EQ(account_info.account_id, maybe_account_info.account_id); |
| EXPECT_EQ(account_info.email, maybe_account_info.email); |
| EXPECT_EQ(account_info.gaia, maybe_account_info.gaia); |
| } |
| |
| // Checks that FindExtendedAccountInfoByEmailAddress() returns information about |
| // the account if the account is found, or an empty account info. |
| TEST_F(IdentityManagerTest, FindExtendedAccountInfoByEmailAddress) { |
| CoreAccountInfo account_info; |
| account_info.email = kTestEmail2; |
| account_info.gaia = kTestGaiaId2; |
| account_info.account_id = identity_manager()->PickAccountIdForAccount( |
| account_info.gaia, account_info.email); |
| |
| // Account is unknown. |
| AccountInfo maybe_account_info = |
| identity_manager()->FindExtendedAccountInfoByEmailAddress( |
| account_info.email); |
| EXPECT_TRUE(maybe_account_info.IsEmpty()); |
| |
| // Refresh token is not available. |
| const CoreAccountId account_id = |
| account_tracker()->SeedAccountInfo(account_info.gaia, account_info.email); |
| maybe_account_info = |
| identity_manager()->FindExtendedAccountInfoByEmailAddress( |
| account_info.email); |
| EXPECT_TRUE(maybe_account_info.IsEmpty()); |
| |
| // Account with refresh token. |
| SetRefreshTokenForAccount(identity_manager(), account_info.account_id, |
| "token"); |
| maybe_account_info = |
| identity_manager()->FindExtendedAccountInfoByEmailAddress( |
| account_info.email); |
| EXPECT_FALSE(maybe_account_info.IsEmpty()); |
| EXPECT_EQ(account_info.account_id, maybe_account_info.account_id); |
| EXPECT_EQ(account_info.email, maybe_account_info.email); |
| EXPECT_EQ(account_info.gaia, maybe_account_info.gaia); |
| } |
| |
| // Checks that FindExtendedAccountInfoByGaiaId() returns information about the |
| // account if the account is found, or an empty account info. |
| TEST_F(IdentityManagerTest, FindExtendedAccountInfoByGaiaId) { |
| CoreAccountInfo account_info; |
| account_info.email = kTestEmail2; |
| account_info.gaia = kTestGaiaId2; |
| account_info.account_id = identity_manager()->PickAccountIdForAccount( |
| account_info.gaia, account_info.email); |
| |
| // Account is unknown. |
| AccountInfo maybe_account_info = |
| identity_manager()->FindExtendedAccountInfoByGaiaId(account_info.gaia); |
| EXPECT_TRUE(maybe_account_info.IsEmpty()); |
| |
| // Refresh token is not available. |
| const CoreAccountId account_id = |
| account_tracker()->SeedAccountInfo(account_info.gaia, account_info.email); |
| maybe_account_info = |
| identity_manager()->FindExtendedAccountInfoByGaiaId(account_info.gaia); |
| EXPECT_TRUE(maybe_account_info.IsEmpty()); |
| |
| // Account with refresh token. |
| SetRefreshTokenForAccount(identity_manager(), account_info.account_id, |
| "token"); |
| maybe_account_info = |
| identity_manager()->FindExtendedAccountInfoByGaiaId(account_info.gaia); |
| EXPECT_FALSE(maybe_account_info.IsEmpty()); |
| EXPECT_EQ(account_info.account_id, maybe_account_info.account_id); |
| EXPECT_EQ(account_info.email, maybe_account_info.email); |
| EXPECT_EQ(account_info.gaia, maybe_account_info.gaia); |
| } |
| |
| TEST_F(IdentityManagerTest, FindExtendedPrimaryAccountInfo) { |
| // AccountInfo found for primary account, even without token. |
| RemoveRefreshTokenForPrimaryAccount(identity_manager()); |
| ASSERT_TRUE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); |
| ASSERT_FALSE(identity_manager()->HasPrimaryAccountWithRefreshToken( |
| ConsentLevel::kSignin)); |
| AccountInfo extended_info = |
| identity_manager()->FindExtendedPrimaryAccountInfo(ConsentLevel::kSignin); |
| CoreAccountInfo core_info = |
| identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSignin); |
| EXPECT_FALSE(extended_info.IsEmpty()); |
| EXPECT_EQ(core_info.account_id, extended_info.account_id); |
| EXPECT_EQ(core_info.email, extended_info.email); |
| EXPECT_EQ(core_info.gaia, extended_info.gaia); |
| |
| #if !BUILDFLAG(IS_CHROMEOS_ASH) |
| // It's not possible to sign out on Ash. |
| ClearPrimaryAccount(identity_manager()); |
| SetRefreshTokenForAccount(identity_manager(), core_info.account_id, "token"); |
| // No info found if there is no primary account. |
| ASSERT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); |
| ASSERT_TRUE( |
| identity_manager()->HasAccountWithRefreshToken(core_info.account_id)); |
| EXPECT_TRUE(identity_manager() |
| ->FindExtendedPrimaryAccountInfo(ConsentLevel::kSignin) |
| .IsEmpty()); |
| #endif |
| } |
| |
| // Checks that AreRefreshTokensLoaded() returns true after LoadCredentials. |
| TEST_F(IdentityManagerTest, AreRefreshTokensLoaded) { |
| base::RunLoop run_loop; |
| identity_manager_observer()->SetOnRefreshTokensLoadedCallback( |
| run_loop.QuitClosure()); |
| |
| // Credentials are already loaded in PrimaryAccountManager::Initialize() |
| // which runs even before the IdentityManager is created. That's why |
| // we fake the credentials loaded state and force another load in |
| // order to test AreRefreshTokensLoaded. |
| token_service()->set_all_credentials_loaded_for_testing(false); |
| EXPECT_FALSE(identity_manager()->AreRefreshTokensLoaded()); |
| token_service()->LoadCredentials(CoreAccountId()); |
| run_loop.Run(); |
| EXPECT_TRUE(identity_manager()->AreRefreshTokensLoaded()); |
| } |
| |
| #if BUILDFLAG(IS_CHROMEOS_LACROS) |
| TEST_F(IdentityManagerTest, SetPrimaryAccount) { |
| signin_client()->SetInitialPrimaryAccountForTests(account_manager::Account{ |
| account_manager::AccountKey{kTestGaiaId, |
| account_manager::AccountType::kGaia}, |
| kTestEmail}); |
| // Do not sign into a primary account as part of the test setup. |
| RecreateIdentityManager(AccountConsistencyMethod::kDisabled, |
| PrimaryAccountManagerSetup::kNoAuthenticatedAccount); |
| |
| // We should have a Primary Account set up automatically. |
| ASSERT_TRUE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSync)); |
| EXPECT_EQ( |
| kTestGaiaId, |
| identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSync).gaia); |
| } |
| |
| // TODO(https://crbug.com/1223364): Remove this when all the users are migrated. |
| TEST_F(IdentityManagerTest, SetPrimaryAccountClearsExistingPrimaryAccount) { |
| signin_client()->SetInitialPrimaryAccountForTests(account_manager::Account{ |
| account_manager::AccountKey{kTestGaiaId2, |
| account_manager::AccountType::kGaia}, |
| kTestEmail2}); |
| |
| // RecreateIdentityManager will create PrimaryAccountManager with the primary |
| // account set to kTestGaiaId. After that, IdentityManager ctor should clear |
| // this existing primary account and set the new one to the initial value |
| // provided by the SigninClient. |
| RecreateIdentityManager(AccountConsistencyMethod::kDisabled, |
| PrimaryAccountManagerSetup::kWithAuthenticatedAccout); |
| |
| ASSERT_TRUE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSync)); |
| EXPECT_EQ( |
| kTestGaiaId2, |
| identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSync).gaia); |
| } |
| #endif |
| |
| TEST_F(IdentityManagerTest, AccountIdMigration_DoneOnInitialization) { |
| EXPECT_EQ(IdentityManager::AccountIdMigrationState::MIGRATION_DONE, |
| identity_manager()->GetAccountIdMigrationState()); |
| } |
| |
| // Checks that IdentityManager::Observer gets OnAccountUpdated when account info |
| // is updated. |
| TEST_F(IdentityManagerTest, ObserveOnAccountUpdated) { |
| const AccountInfo account_info = |
| MakeAccountAvailable(identity_manager(), kTestEmail3); |
| |
| SimulateSuccessfulFetchOfAccountInfo( |
| identity_manager(), account_info.account_id, account_info.email, |
| account_info.gaia, kTestHostedDomain, kTestFullName, kTestGivenName, |
| kTestLocale, kTestPictureUrl); |
| |
| EXPECT_EQ(account_info.account_id, identity_manager_observer() |
| ->AccountFromAccountUpdatedCallback() |
| .account_id); |
| EXPECT_EQ( |
| account_info.email, |
| identity_manager_observer()->AccountFromAccountUpdatedCallback().email); |
| } |
| |
| TEST_F(IdentityManagerTest, TestOnAccountRemovedWithInfoCallback) { |
| AccountInfo account_info = |
| MakeAccountAvailable(identity_manager(), kTestEmail2); |
| EXPECT_EQ(kTestEmail2, account_info.email); |
| |
| account_tracker()->RemoveAccount(account_info.account_id); |
| |
| // Check if OnAccountRemovedWithInfo is called after removing |account_info| |
| // by RemoveAccount(). |
| EXPECT_TRUE( |
| identity_manager_observer()->WasCalledAccountRemovedWithInfoCallback()); |
| |
| // Check if the passed AccountInfo is the same to the removing one. |
| EXPECT_EQ(account_info.account_id, |
| identity_manager_observer() |
| ->AccountFromAccountRemovedWithInfoCallback() |
| .account_id); |
| EXPECT_EQ(account_info.email, |
| identity_manager_observer() |
| ->AccountFromAccountRemovedWithInfoCallback() |
| .email); |
| } |
| |
| TEST_F(IdentityManagerTest, TestPickAccountIdForAccount) { |
| const CoreAccountId account_id = |
| identity_manager()->PickAccountIdForAccount(kTestGaiaId, kTestEmail); |
| const bool account_id_migration_done = |
| identity_manager()->GetAccountIdMigrationState() == |
| IdentityManager::AccountIdMigrationState::MIGRATION_DONE; |
| if (account_id_migration_done) { |
| EXPECT_EQ(kTestGaiaId, account_id.ToString()); |
| } else { |
| EXPECT_TRUE(gaia::AreEmailsSame(kTestEmail, account_id.ToString())); |
| } |
| } |
| |
| #if defined(OS_ANDROID) |
| TEST_F(IdentityManagerTest, RefreshAccountInfoIfStale) { |
| // The flow of this test results in an interaction with |
| // ChildAccountInfoFetcherAndroid, which requires initialization of |
| // AccountManagerFacade in java code to avoid a crash. |
| SetUpMockAccountManagerFacade(); |
| |
| identity_manager()->GetAccountFetcherService()->OnNetworkInitialized(); |
| AccountInfo account_info = |
| MakeAccountAvailable(identity_manager(), kTestEmail2); |
| identity_manager()->RefreshAccountInfoIfStale(account_info.account_id); |
| |
| SimulateSuccessfulFetchOfAccountInfo( |
| identity_manager(), account_info.account_id, account_info.email, |
| account_info.gaia, kTestHostedDomain, kTestFullName, kTestGivenName, |
| kTestLocale, kTestPictureUrl); |
| |
| const AccountInfo& refreshed_account_info = |
| identity_manager_observer()->AccountFromAccountUpdatedCallback(); |
| EXPECT_EQ(account_info.account_id, refreshed_account_info.account_id); |
| EXPECT_EQ(account_info.email, refreshed_account_info.email); |
| EXPECT_EQ(account_info.gaia, refreshed_account_info.gaia); |
| EXPECT_EQ(kTestHostedDomain, refreshed_account_info.hosted_domain); |
| EXPECT_EQ(kTestFullName, refreshed_account_info.full_name); |
| EXPECT_EQ(kTestGivenName, refreshed_account_info.given_name); |
| EXPECT_EQ(kTestLocale, refreshed_account_info.locale); |
| EXPECT_EQ(kTestPictureUrl, refreshed_account_info.picture_url); |
| } |
| #endif |
| |
| } // namespace signin |