diff options
Diffstat (limited to 'chromium/chrome/browser/signin/signin_manager_unittest.cc')
-rw-r--r-- | chromium/chrome/browser/signin/signin_manager_unittest.cc | 421 |
1 files changed, 421 insertions, 0 deletions
diff --git a/chromium/chrome/browser/signin/signin_manager_unittest.cc b/chromium/chrome/browser/signin/signin_manager_unittest.cc new file mode 100644 index 00000000000..e2bb33af9f0 --- /dev/null +++ b/chromium/chrome/browser/signin/signin_manager_unittest.cc @@ -0,0 +1,421 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#include "chrome/browser/signin/signin_manager.h" + +#include "base/memory/raw_ptr.h" +#include "components/signin/public/base/signin_pref_names.h" +#include "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h" +#include "components/signin/public/identity_manager/identity_manager.h" +#include "components/signin/public/identity_manager/identity_test_environment.h" +#include "components/signin/public/identity_manager/identity_test_utils.h" +#include "components/sync_preferences/testing_pref_service_syncable.h" +#include "content/public/test/browser_task_environment.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using ::testing::_; +using ::testing::Mock; + +namespace signin { +namespace { +const char kTestEmail[] = "me@gmail.com"; +const char kTestEmail2[] = "me2@gmail.com"; + +class FakeIdentityManagerObserver : public IdentityManager::Observer { + public: + explicit FakeIdentityManagerObserver(IdentityManager* identity_manager) + : identity_manager_(identity_manager) {} + ~FakeIdentityManagerObserver() override = default; + + void OnPrimaryAccountChanged( + const PrimaryAccountChangeEvent& event) override { + auto current_state = event.GetCurrentState(); + EXPECT_EQ( + current_state.primary_account, + identity_manager_->GetPrimaryAccountInfo(current_state.consent_level)); + events_.push_back(event); + } + + const std::vector<PrimaryAccountChangeEvent>& events() const { + return events_; + } + + void Reset() { events_.clear(); } + + private: + raw_ptr<IdentityManager> identity_manager_; + std::vector<PrimaryAccountChangeEvent> events_; +}; +} // namespace + +class SigninManagerTest : public testing::Test { + public: + SigninManagerTest() + : identity_test_env_(/*test_url_loader_factory=*/nullptr, + /*pref_service=*/&prefs_, + signin::AccountConsistencyMethod::kDice, + /*test_signin_client=*/nullptr), + observer_(identity_test_env_.identity_manager()) {} + + SigninManagerTest(const SigninManagerTest&) = delete; + SigninManagerTest& operator=(const SigninManagerTest&) = delete; + + void SetUp() override { + testing::Test::SetUp(); + RecreateSigninManager(); + identity_manager()->AddObserver(&observer_); + } + + void TearDown() override { identity_manager()->RemoveObserver(&observer_); } + + void RecreateSigninManager() { + signin_manger_ = + std::make_unique<SigninManager>(&prefs_, identity_manager()); + } + + AccountInfo GetAccountInfo(const std::string& email) { + AccountInfo account_info; + account_info.gaia = GetTestGaiaIdForEmail(email); + account_info.account_id = + identity_manager()->PickAccountIdForAccount(account_info.gaia, email); + account_info.email = email; + return account_info; + } + + void ExpectUnconsentedPrimaryAccountSetEvent( + const CoreAccountInfo& expected_primary_account) { + EXPECT_EQ(1U, observer().events().size()); + auto event = observer().events()[0]; + EXPECT_EQ(PrimaryAccountChangeEvent::Type::kSet, + event.GetEventTypeFor(ConsentLevel::kSignin)); + EXPECT_TRUE(event.GetPreviousState().primary_account.IsEmpty()); + EXPECT_EQ(expected_primary_account, + event.GetCurrentState().primary_account); + observer().Reset(); + } + + void ExpectUnconsentedPrimaryAccountClearedEvent( + const CoreAccountInfo& expected_cleared_account) { + EXPECT_EQ(1U, observer().events().size()); + auto event = observer().events()[0]; + EXPECT_EQ(PrimaryAccountChangeEvent::Type::kCleared, + event.GetEventTypeFor(ConsentLevel::kSignin)); + EXPECT_EQ(expected_cleared_account, + event.GetPreviousState().primary_account); + EXPECT_TRUE(event.GetCurrentState().primary_account.IsEmpty()); + observer().Reset(); + } + + void ExpectSyncPrimaryAccountSetEvent( + const CoreAccountInfo& expected_primary_account) { + EXPECT_EQ(1U, observer().events().size()); + auto event = observer().events()[0]; + EXPECT_EQ(PrimaryAccountChangeEvent::Type::kSet, + event.GetEventTypeFor(ConsentLevel::kSignin)); + EXPECT_EQ(PrimaryAccountChangeEvent::Type::kSet, + event.GetEventTypeFor(ConsentLevel::kSync)); + EXPECT_TRUE(event.GetPreviousState().primary_account.IsEmpty()); + EXPECT_EQ(expected_primary_account, + event.GetCurrentState().primary_account); + observer().Reset(); + } + + IdentityManager* identity_manager() { + return identity_test_env_.identity_manager(); + } + + IdentityTestEnvironment* identity_test_env() { return &identity_test_env_; } + + AccountInfo MakeAccountAvailableWithCookies(const std::string& email) { + AccountInfo account = GetAccountInfo(kTestEmail); + identity_test_env_.MakeAccountAvailableWithCookies(account.email, + account.gaia); + EXPECT_FALSE(account.IsEmpty()); + EXPECT_TRUE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); + EXPECT_EQ(account, + identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSignin)); + EXPECT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSync)); + return account; + } + + AccountInfo MakeSyncAccountAvailableWithCookies(const std::string& email) { + AccountInfo account = identity_test_env_.MakePrimaryAccountAvailable( + email, signin::ConsentLevel::kSync); + identity_test_env_.SetCookieAccounts({{account.email, account.gaia}}); + EXPECT_EQ(account, + identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSignin)); + EXPECT_EQ(account, + identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSync)); + EXPECT_TRUE(identity_manager()->HasPrimaryAccountWithRefreshToken( + signin::ConsentLevel::kSync)); + return account; + } + + FakeIdentityManagerObserver& observer() { return observer_; } + + sync_preferences::TestingPrefServiceSyncable prefs_; + content::BrowserTaskEnvironment task_environment_; + IdentityTestEnvironment identity_test_env_; + std::unique_ptr<SigninManager> signin_manger_; + FakeIdentityManagerObserver observer_; +}; + +TEST_F( + SigninManagerTest, + UnconsentedPrimaryAccountUpdatedOnItsAccountRefreshTokenUpdateWithValidTokenWhenNoSyncConsent) { + // Add an unconsented primary account, incl. proper cookies. + AccountInfo account = MakeAccountAvailableWithCookies(kTestEmail); + ExpectUnconsentedPrimaryAccountSetEvent(account); + EXPECT_EQ(account, + identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSignin)); +} + +TEST_F( + SigninManagerTest, + UnconsentedPrimaryAccountUpdatedOnItsAccountRefreshTokenUpdateWithInvalidTokenWhenNoSyncConsent) { + // Prerequisite: add an unconsented primary account, incl. proper cookies. + AccountInfo account = MakeAccountAvailableWithCookies(kTestEmail); + ExpectUnconsentedPrimaryAccountSetEvent(account); + + // Invalid token. + SetInvalidRefreshTokenForAccount(identity_manager(), account.account_id); + ExpectUnconsentedPrimaryAccountClearedEvent(account); + EXPECT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); + + // Update with a valid token. + SetRefreshTokenForAccount(identity_manager(), account.account_id, ""); + ExpectUnconsentedPrimaryAccountSetEvent(account); + EXPECT_EQ(identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSignin), + account); +} + +TEST_F( + SigninManagerTest, + UnconsentedPrimaryAccountRemovedOnItsAccountRefreshTokenRemovalWhenNoSyncConsent) { + // Prerequisite: Add an unconsented primary account, incl. proper cookies. + AccountInfo account = MakeAccountAvailableWithCookies(kTestEmail); + ExpectUnconsentedPrimaryAccountSetEvent(account); + + // With no refresh token, there is no unconsented primary account any more. + identity_test_env()->RemoveRefreshTokenForAccount(account.account_id); + ExpectUnconsentedPrimaryAccountClearedEvent(account); + EXPECT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); +} + +TEST_F(SigninManagerTest, UnconsentedPrimaryAccountNotChangedOnSignout) { + // Set a primary account at sync consent level. + AccountInfo account = MakeSyncAccountAvailableWithCookies(kTestEmail); + EXPECT_EQ(account, + identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSignin)); + EXPECT_EQ(account, + identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSync)); + EXPECT_TRUE(identity_manager()->HasPrimaryAccountWithRefreshToken( + signin::ConsentLevel::kSync)); + + // Verify the primary account changed event. + ExpectSyncPrimaryAccountSetEvent(account); + + // Tests that sync primary account is cleared, but unconsented account is not. + identity_test_env()->RevokeSyncConsent(); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(account, + identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSignin)); + EXPECT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSync)); + + EXPECT_EQ(1U, observer().events().size()); + auto event = observer().events()[0]; + EXPECT_EQ(PrimaryAccountChangeEvent::Type::kNone, + event.GetEventTypeFor(ConsentLevel::kSignin)); + EXPECT_EQ(PrimaryAccountChangeEvent::Type::kCleared, + event.GetEventTypeFor(ConsentLevel::kSync)); + EXPECT_EQ(account, event.GetPreviousState().primary_account); + EXPECT_EQ(account, event.GetCurrentState().primary_account); +} + +TEST_F(SigninManagerTest, + UnconsentedPrimaryAccountTokenRevokedWithStaleCookies) { + // Prerequisite: add an unconsented primary account, incl. proper cookies. + AccountInfo account = MakeAccountAvailableWithCookies(kTestEmail); + ExpectUnconsentedPrimaryAccountSetEvent(account); + + // Make the cookies stale and remove the account. + // Removing the refresh token for the unconsented primary account is + // sufficient to clear it. + identity_test_env()->SetFreshnessOfAccountsInGaiaCookie(false); + identity_test_env()->RemoveRefreshTokenForAccount(account.account_id); + ASSERT_FALSE(identity_manager()->GetAccountsInCookieJar().accounts_are_fresh); + + // Unconsented account was removed. + EXPECT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); + ExpectUnconsentedPrimaryAccountClearedEvent(account); +} + +TEST_F(SigninManagerTest, + UnconsentedPrimaryAccountTokenRevokedWithStaleCookiesMultipleAccounts) { + // Add two accounts with cookies. + AccountInfo main_account = + identity_test_env()->MakeAccountAvailable(kTestEmail); + AccountInfo secondary_account = + identity_test_env()->MakeAccountAvailable(kTestEmail2); + identity_test_env()->SetCookieAccounts( + {{main_account.email, main_account.gaia}, + {secondary_account.email, secondary_account.gaia}}); + + EXPECT_TRUE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); + EXPECT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSync)); + EXPECT_EQ(main_account, + identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSignin)); + ExpectUnconsentedPrimaryAccountSetEvent(main_account); + + // Make the cookies stale and remove the main account. + identity_test_env()->SetFreshnessOfAccountsInGaiaCookie(false); + identity_test_env()->RemoveRefreshTokenForAccount(main_account.account_id); + ASSERT_FALSE(identity_manager()->GetAccountsInCookieJar().accounts_are_fresh); + + // Unconsented account was removed. + EXPECT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); + ExpectUnconsentedPrimaryAccountClearedEvent(main_account); +} + +TEST_F(SigninManagerTest, UnconsentedPrimaryAccountDuringLoad) { + // Pre-requisite: Add two accounts with cookies. + AccountInfo main_account = + identity_test_env()->MakeAccountAvailable(kTestEmail); + AccountInfo secondary_account = + identity_test_env()->MakeAccountAvailable(kTestEmail2); + identity_test_env()->SetCookieAccounts( + {{main_account.email, main_account.gaia}, + {secondary_account.email, secondary_account.gaia}}); + ASSERT_EQ(main_account, + identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSignin)); + ASSERT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSync)); + ExpectUnconsentedPrimaryAccountSetEvent(main_account); + + // Set the token service in "loading" mode. + identity_test_env()->ResetToAccountsNotYetLoadedFromDiskState(); + RecreateSigninManager(); + + // Unconsented primary account is available while tokens are not loaded. + EXPECT_EQ(main_account, + identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSignin)); + EXPECT_TRUE(observer().events().empty()); + + // Revoking an unrelated token doesn't change the unconsented primary account. + identity_test_env()->RemoveRefreshTokenForAccount( + secondary_account.account_id); + EXPECT_EQ(main_account, + identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSignin)); + EXPECT_TRUE(observer().events().empty()); + + // Revoking the token of the unconsented primary account while the tokens + // are still loading does not change the unconsented primary account. + identity_test_env()->RemoveRefreshTokenForAccount(main_account.account_id); + EXPECT_EQ(main_account, + identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSignin)); + EXPECT_TRUE(observer().events().empty()); + + // Finish the token load should clear the primary account as the token of the + // primary account was revoked. + identity_test_env()->ReloadAccountsFromDisk(); + EXPECT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); + ExpectUnconsentedPrimaryAccountClearedEvent(main_account); +} + +TEST_F(SigninManagerTest, + UnconsentedPrimaryAccountUpdatedOnSyncConsentRevoked) { + AccountInfo first_account = + identity_test_env()->MakeAccountAvailable(kTestEmail); + AccountInfo second_account = + identity_test_env()->MakeAccountAvailable(kTestEmail2); + identity_test_env()->SetCookieAccounts( + {{first_account.email, first_account.gaia}, + {second_account.email, second_account.gaia}}); + ASSERT_EQ(first_account, + identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSignin)); + ExpectUnconsentedPrimaryAccountSetEvent(first_account); + + // Set the sync primary account to the second account in cookies. + // The unconsented primary account should be updated. + identity_test_env()->SetPrimaryAccount(second_account.email, + signin::ConsentLevel::kSync); + EXPECT_EQ(second_account, + identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSync)); + EXPECT_EQ(1U, observer().events().size()); + auto event = observer().events()[0]; + EXPECT_EQ(PrimaryAccountChangeEvent::Type::kSet, + event.GetEventTypeFor(ConsentLevel::kSync)); + EXPECT_EQ(first_account, event.GetPreviousState().primary_account); + EXPECT_EQ(second_account, event.GetCurrentState().primary_account); + observer().Reset(); + + // Clear primary account but do not delete the account. The unconsented + // primary account should be updated to be the first account in cookies. + identity_test_env()->RevokeSyncConsent(); + base::RunLoop().RunUntilIdle(); + + // Primary account is cleared, but unconsented account is not. + EXPECT_FALSE( + identity_manager()->HasPrimaryAccount(signin::ConsentLevel::kSync)); + EXPECT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSync)); + EXPECT_TRUE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); + EXPECT_EQ(first_account, + identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSignin)); + + EXPECT_EQ(2U, observer().events().size()); + event = observer().events()[0]; + EXPECT_EQ(PrimaryAccountChangeEvent::Type::kCleared, + event.GetEventTypeFor(ConsentLevel::kSync)); + EXPECT_EQ(PrimaryAccountChangeEvent::Type::kNone, + event.GetEventTypeFor(ConsentLevel::kSignin)); + EXPECT_EQ(second_account, event.GetPreviousState().primary_account); + EXPECT_EQ(second_account, event.GetCurrentState().primary_account); + + event = observer().events()[1]; + EXPECT_EQ(PrimaryAccountChangeEvent::Type::kNone, + event.GetEventTypeFor(ConsentLevel::kSync)); + EXPECT_EQ(PrimaryAccountChangeEvent::Type::kSet, + event.GetEventTypeFor(ConsentLevel::kSignin)); + EXPECT_EQ(second_account, event.GetPreviousState().primary_account); + EXPECT_EQ(first_account, event.GetCurrentState().primary_account); +} + +TEST_F(SigninManagerTest, ClearPrimaryAccountAndSignOut) { + AccountInfo account = MakeSyncAccountAvailableWithCookies(kTestEmail); + ExpectSyncPrimaryAccountSetEvent(account); + + identity_test_env()->ClearPrimaryAccount(); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(1U, observer().events().size()); + auto event = observer().events()[0]; + EXPECT_EQ(PrimaryAccountChangeEvent::Type::kCleared, + event.GetEventTypeFor(ConsentLevel::kSignin)); + EXPECT_EQ(PrimaryAccountChangeEvent::Type::kCleared, + event.GetEventTypeFor(ConsentLevel::kSync)); + EXPECT_EQ(account, event.GetPreviousState().primary_account); + EXPECT_TRUE(event.GetCurrentState().primary_account.IsEmpty()); +} + +TEST_F(SigninManagerTest, + UnconsentedPrimaryAccountClearedWhenSigninDisallowed) { + // Prerequisite: add an unconsented primary account. + AccountInfo account = MakeAccountAvailableWithCookies(kTestEmail); + ExpectUnconsentedPrimaryAccountSetEvent(account); + + prefs_.SetBoolean(prefs::kSigninAllowed, false); + base::RunLoop().RunUntilIdle(); + + EXPECT_FALSE( + identity_manager()->HasPrimaryAccount(signin::ConsentLevel::kSignin)); + + EXPECT_EQ(1U, observer().events().size()); + auto event = observer().events()[0]; + EXPECT_EQ(PrimaryAccountChangeEvent::Type::kCleared, + event.GetEventTypeFor(ConsentLevel::kSignin)); + EXPECT_EQ(account, event.GetPreviousState().primary_account); + EXPECT_TRUE(event.GetCurrentState().primary_account.IsEmpty()); +} + +} // namespace signin |