Commit b531a162 authored by Mihai Sardarescu's avatar Mihai Sardarescu Committed by Chromium LUCI CQ

Fix order of notifications to update the unconsent/sync primary account

This CL fixes the order in which the notifications to update the
primary account are being fired. The scenario that failed before
this CL was the following (covered in test
SigninManagerTest.UnconsentedPrimaryAccountUpdatedOnSyncConsentRevoked):
1. Account A and B are signed in with this order in the cookie jar.
2. Unconsented primary account: A
3. User enables sync with account B. B becomes the primary account
4. User revokes sync consent.
5. Unconsented primary account is reverted to B

Before this CL, 2 notifications were sent with primary account changed
in the wrong order:
1. { previous_state: { primary_account: gaia_id_for_me2_gmail.com,
                       consent_level:NotRequired }
     current_state: { primary_account: gaia_id_for_me_gmail.com,
                      consent_level:NotRequired } }
2. { previous_state: { primary_account: gaia_id_for_me2_gmail.com,
                       consent_level:Sync },
     current_state: { primary_account: gaia_id_for_me2_gmail.com,
                       consent_level:NotRequired } }

This CL fixes this order, and ensures that notification 2 above is
correctly sent before notification 1.

The change in the CL is fairly complex as it also updates the
SigninManager to observe OnPrimaryAccountChanged notifications which
is required as OnUnconsentedPrimaryAccountSet is deprecated.

Bug: 1163126

Change-Id: I047014ce9bc569040d44121d90670d375f8fba62
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2613971
Commit-Queue: Mihai Sardarescu <msarda@chromium.org>
Reviewed-by: default avatarMonica Basta <msalama@chromium.org>
Reviewed-by: default avatarDavid Roger <droger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#841999}
parent 185616aa
...@@ -104,8 +104,7 @@ SigninManager::ComputeUnconsentedPrimaryAccountInfo() const { ...@@ -104,8 +104,7 @@ SigninManager::ComputeUnconsentedPrimaryAccountInfo() const {
} }
// signin::IdentityManager::Observer implementation. // signin::IdentityManager::Observer implementation.
void SigninManager::BeforePrimaryAccountCleared( void SigninManager::AfterSyncPrimaryAccountCleared() {
const CoreAccountInfo& previous_primary_account_info) {
// This is needed for the case where the user chooses to start syncing // This is needed for the case where the user chooses to start syncing
// with an account that is different from the unconsented primary account // with an account that is different from the unconsented primary account
// (not the first in cookies) but then cancels. In that case, the tokens stay // (not the first in cookies) but then cancels. In that case, the tokens stay
......
...@@ -36,8 +36,7 @@ class SigninManager : public KeyedService, ...@@ -36,8 +36,7 @@ class SigninManager : public KeyedService,
base::Optional<CoreAccountInfo> ComputeUnconsentedPrimaryAccountInfo() const; base::Optional<CoreAccountInfo> ComputeUnconsentedPrimaryAccountInfo() const;
// signin::IdentityManager::Observer implementation. // signin::IdentityManager::Observer implementation.
void BeforePrimaryAccountCleared( void AfterSyncPrimaryAccountCleared() override;
const CoreAccountInfo& previous_primary_account_info) override;
void OnRefreshTokenUpdatedForAccount( void OnRefreshTokenUpdatedForAccount(
const CoreAccountInfo& account_info) override; const CoreAccountInfo& account_info) override;
void OnRefreshTokenRemovedForAccount( void OnRefreshTokenRemovedForAccount(
......
...@@ -19,12 +19,30 @@ namespace { ...@@ -19,12 +19,30 @@ namespace {
const char kTestEmail[] = "me@gmail.com"; const char kTestEmail[] = "me@gmail.com";
const char kTestEmail2[] = "me2@gmail.com"; const char kTestEmail2[] = "me2@gmail.com";
class IdentityManagerObserver : public IdentityManager::Observer { class FakeIdentityManagerObserver : public IdentityManager::Observer {
public: public:
MOCK_METHOD1(OnUnconsentedPrimaryAccountChanged, explicit FakeIdentityManagerObserver(IdentityManager* identity_manager)
void(const CoreAccountInfo& unconsented_primary_account_info)); : identity_manager_(identity_manager) {}
MOCK_METHOD1(BeforePrimaryAccountCleared, ~FakeIdentityManagerObserver() override = default;
void(const CoreAccountInfo& previous_primary_account_info));
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:
IdentityManager* identity_manager_;
std::vector<PrimaryAccountChangeEvent> events_;
}; };
} // namespace } // namespace
...@@ -34,12 +52,12 @@ class SigninManagerTest : public testing::Test { ...@@ -34,12 +52,12 @@ class SigninManagerTest : public testing::Test {
: identity_test_env_(/*test_url_loader_factory=*/nullptr, : identity_test_env_(/*test_url_loader_factory=*/nullptr,
/*pref_service=*/nullptr, /*pref_service=*/nullptr,
signin::AccountConsistencyMethod::kDice, signin::AccountConsistencyMethod::kDice,
/*test_signin_client=*/nullptr) {} /*test_signin_client=*/nullptr),
observer_(identity_test_env_.identity_manager()) {}
void SetUp() override { void SetUp() override {
testing::Test::SetUp(); testing::Test::SetUp();
RecreateSigninManager(); RecreateSigninManager();
VerifyAndResetCallExpectations();
identity_manager()->AddObserver(&observer_); identity_manager()->AddObserver(&observer_);
} }
...@@ -58,29 +76,80 @@ class SigninManagerTest : public testing::Test { ...@@ -58,29 +76,80 @@ class SigninManagerTest : public testing::Test {
return account_info; 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::kNotRequired));
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::kNotRequired));
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::kNotRequired));
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() { IdentityManager* identity_manager() {
return identity_test_env_.identity_manager(); return identity_test_env_.identity_manager();
} }
IdentityTestEnvironment* identity_test_env() { return &identity_test_env_; } IdentityTestEnvironment* identity_test_env() { return &identity_test_env_; }
void MakeAccountAvailableWithCookies(const AccountInfo& account_info) { AccountInfo MakeAccountAvailableWithCookies(const std::string& email) {
EXPECT_EQ(account_info, identity_test_env_.MakeAccountAvailableWithCookies( AccountInfo account = GetAccountInfo(kTestEmail);
account_info.email, account_info.gaia)); identity_test_env_.MakeAccountAvailableWithCookies(account.email,
account.gaia);
EXPECT_FALSE(account.IsEmpty());
EXPECT_TRUE(
identity_manager()->HasPrimaryAccount(ConsentLevel::kNotRequired));
EXPECT_EQ(account, identity_manager()->GetPrimaryAccountInfo(
ConsentLevel::kNotRequired));
EXPECT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSync));
return account;
} }
IdentityManagerObserver& observer() { return observer_; } AccountInfo MakeSyncAccountAvailableWithCookies(const std::string& email) {
AccountInfo account = identity_test_env_.MakePrimaryAccountAvailable(email);
void VerifyAndResetCallExpectations() { identity_test_env_.SetCookieAccounts({{account.email, account.gaia}});
Mock::VerifyAndClear(&observer_); EXPECT_EQ(account, identity_manager()->GetPrimaryAccountInfo(
EXPECT_CALL(observer_, OnUnconsentedPrimaryAccountChanged(_)).Times(0); ConsentLevel::kNotRequired));
EXPECT_CALL(observer_, BeforePrimaryAccountCleared(_)).Times(0); EXPECT_EQ(account,
identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSync));
EXPECT_TRUE(identity_manager()->HasPrimaryAccountWithRefreshToken());
return account;
} }
FakeIdentityManagerObserver& observer() { return observer_; }
content::BrowserTaskEnvironment task_environment_; content::BrowserTaskEnvironment task_environment_;
IdentityTestEnvironment identity_test_env_; IdentityTestEnvironment identity_test_env_;
std::unique_ptr<SigninManager> signin_manger_; std::unique_ptr<SigninManager> signin_manger_;
IdentityManagerObserver observer_; FakeIdentityManagerObserver observer_;
DISALLOW_COPY_AND_ASSIGN(SigninManagerTest); DISALLOW_COPY_AND_ASSIGN(SigninManagerTest);
}; };
...@@ -89,278 +158,237 @@ TEST_F( ...@@ -89,278 +158,237 @@ TEST_F(
SigninManagerTest, SigninManagerTest,
UnconsentedPrimaryAccountUpdatedOnItsAccountRefreshTokenUpdateWithValidTokenWhenNoSyncConsent) { UnconsentedPrimaryAccountUpdatedOnItsAccountRefreshTokenUpdateWithValidTokenWhenNoSyncConsent) {
// Add an unconsented primary account, incl. proper cookies. // Add an unconsented primary account, incl. proper cookies.
AccountInfo account_info = GetAccountInfo(kTestEmail); AccountInfo account = MakeAccountAvailableWithCookies(kTestEmail);
EXPECT_CALL(observer(), OnUnconsentedPrimaryAccountChanged(account_info)) ExpectUnconsentedPrimaryAccountSetEvent(account);
.Times(1); EXPECT_EQ(account, identity_manager()->GetPrimaryAccountInfo(
MakeAccountAvailableWithCookies(account_info); ConsentLevel::kNotRequired));
VerifyAndResetCallExpectations();
EXPECT_EQ(
identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kNotRequired),
account_info);
} }
TEST_F( TEST_F(
SigninManagerTest, SigninManagerTest,
UnconsentedPrimaryAccountUpdatedOnItsAccountRefreshTokenUpdateWithInvalidTokenWhenNoSyncConsent) { UnconsentedPrimaryAccountUpdatedOnItsAccountRefreshTokenUpdateWithInvalidTokenWhenNoSyncConsent) {
// Add an unconsented primary account, incl. proper cookies. // Prerequisite: add an unconsented primary account, incl. proper cookies.
AccountInfo account_info = GetAccountInfo(kTestEmail); AccountInfo account = MakeAccountAvailableWithCookies(kTestEmail);
EXPECT_CALL(observer(), OnUnconsentedPrimaryAccountChanged(account_info)) ExpectUnconsentedPrimaryAccountSetEvent(account);
.Times(1);
MakeAccountAvailableWithCookies(account_info);
VerifyAndResetCallExpectations();
// Invalid token. // Invalid token.
CoreAccountInfo empty_info; SetInvalidRefreshTokenForAccount(identity_manager(), account.account_id);
EXPECT_CALL(observer(), OnUnconsentedPrimaryAccountChanged(empty_info)) ExpectUnconsentedPrimaryAccountClearedEvent(account);
.Times(1); EXPECT_FALSE(
SetInvalidRefreshTokenForAccount(identity_manager(), account_info.account_id); identity_manager()->HasPrimaryAccount(ConsentLevel::kNotRequired));
EXPECT_EQ(
identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kNotRequired),
empty_info);
VerifyAndResetCallExpectations();
// Update with a valid token. // Update with a valid token.
EXPECT_CALL(observer(), OnUnconsentedPrimaryAccountChanged(account_info))
.Times(1);
UpdatePersistentErrorOfRefreshTokenForAccount( UpdatePersistentErrorOfRefreshTokenForAccount(
identity_manager(), account_info.account_id, identity_manager(), account.account_id,
GoogleServiceAuthError::AuthErrorNone()); GoogleServiceAuthError::AuthErrorNone());
ExpectUnconsentedPrimaryAccountSetEvent(account);
EXPECT_EQ( EXPECT_EQ(
identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kNotRequired), identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kNotRequired),
account_info); account);
// Unconsented primary account should not be called.
VerifyAndResetCallExpectations();
} }
TEST_F( TEST_F(
SigninManagerTest, SigninManagerTest,
UnconsentedPrimaryAccountRemovedOnItsAccountRefreshTokenRemovalWhenNoSyncConsent) { UnconsentedPrimaryAccountRemovedOnItsAccountRefreshTokenRemovalWhenNoSyncConsent) {
// Add an unconsented primary account, incl. proper cookies. // Prerequisite: Add an unconsented primary account, incl. proper cookies.
AccountInfo account_info = GetAccountInfo(kTestEmail); AccountInfo account = MakeAccountAvailableWithCookies(kTestEmail);
EXPECT_CALL(observer(), OnUnconsentedPrimaryAccountChanged(account_info)) ExpectUnconsentedPrimaryAccountSetEvent(account);
.Times(1);
MakeAccountAvailableWithCookies(account_info);
VerifyAndResetCallExpectations();
// With no refresh token, there is no unconsented primary account any more. // With no refresh token, there is no unconsented primary account any more.
CoreAccountInfo empty_info; identity_test_env()->RemoveRefreshTokenForAccount(account.account_id);
EXPECT_CALL(observer(), OnUnconsentedPrimaryAccountChanged(empty_info)) ExpectUnconsentedPrimaryAccountClearedEvent(account);
.Times(1);
identity_test_env()->RemoveRefreshTokenForAccount(account_info.account_id);
VerifyAndResetCallExpectations();
EXPECT_FALSE( EXPECT_FALSE(
identity_manager()->HasPrimaryAccount(ConsentLevel::kNotRequired)); identity_manager()->HasPrimaryAccount(ConsentLevel::kNotRequired));
EXPECT_EQ(
identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kNotRequired),
empty_info);
VerifyAndResetCallExpectations();
} }
TEST_F(SigninManagerTest, UnconsentedPrimaryAccountNotChangedOnSignout) { TEST_F(SigninManagerTest, UnconsentedPrimaryAccountNotChangedOnSignout) {
// Setup cookies and token for the main account. // Set a primary account at sync consent level.
AccountInfo account_info = GetAccountInfo(kTestEmail); AccountInfo account = MakeSyncAccountAvailableWithCookies(kTestEmail);
EXPECT_CALL(observer(), OnUnconsentedPrimaryAccountChanged(account_info)) EXPECT_EQ(account, identity_manager()->GetPrimaryAccountInfo(
.Times(1);
identity_test_env()->MakePrimaryAccountAvailable(account_info.email);
identity_test_env()->SetCookieAccounts(
{{account_info.email, account_info.gaia}});
EXPECT_EQ(account_info, identity_manager()->GetPrimaryAccountInfo(
ConsentLevel::kNotRequired)); ConsentLevel::kNotRequired));
EXPECT_EQ(account_info, EXPECT_EQ(account,
identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSync)); identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSync));
EXPECT_TRUE(identity_manager()->HasPrimaryAccountWithRefreshToken()); EXPECT_TRUE(identity_manager()->HasPrimaryAccountWithRefreshToken());
VerifyAndResetCallExpectations();
// Tests that OnUnconsentedPrimaryAccountChanged is never called. // Verify the primary account changed event.
EXPECT_CALL(observer(), BeforePrimaryAccountCleared(account_info)).Times(1); ExpectSyncPrimaryAccountSetEvent(account);
// Tests that sync primary account is cleared, but unconsented account is not.
identity_test_env()->RevokeSyncConsent(); identity_test_env()->RevokeSyncConsent();
// Primary account is cleared, but unconsented account is not. EXPECT_EQ(account, identity_manager()->GetPrimaryAccountInfo(
EXPECT_FALSE(identity_manager()->HasPrimaryAccount());
EXPECT_EQ(account_info, identity_manager()->GetPrimaryAccountInfo(
ConsentLevel::kNotRequired)); ConsentLevel::kNotRequired));
// OnUnconsentedPrimaryAccountChanged was not fired. EXPECT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSync));
VerifyAndResetCallExpectations();
EXPECT_EQ(1U, observer().events().size());
auto event = observer().events()[0];
EXPECT_EQ(PrimaryAccountChangeEvent::Type::kNone,
event.GetEventTypeFor(ConsentLevel::kNotRequired));
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, TEST_F(SigninManagerTest,
UnconsentedPrimaryAccountTokenRevokedWithStaleCookies) { UnconsentedPrimaryAccountTokenRevokedWithStaleCookies) {
AccountInfo account_info = GetAccountInfo(kTestEmail); // Prerequisite: add an unconsented primary account, incl. proper cookies.
// Add an unconsented primary account, incl. proper cookies. AccountInfo account = MakeAccountAvailableWithCookies(kTestEmail);
EXPECT_CALL(observer(), OnUnconsentedPrimaryAccountChanged(account_info)) ExpectUnconsentedPrimaryAccountSetEvent(account);
.Times(1);
MakeAccountAvailableWithCookies(account_info);
VerifyAndResetCallExpectations();
EXPECT_EQ(
identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kNotRequired),
account_info);
// Make the cookies stale and remove the account. // Make the cookies stale and remove the account.
EXPECT_CALL(observer(), OnUnconsentedPrimaryAccountChanged(CoreAccountInfo()))
.Times(1);
identity_test_env()->SetFreshnessOfAccountsInGaiaCookie(false);
// Removing the refresh token for the unconsented primary account is // Removing the refresh token for the unconsented primary account is
// sufficient to clear it. // sufficient to clear it.
identity_test_env()->RemoveRefreshTokenForAccount(account_info.account_id); identity_test_env()->SetFreshnessOfAccountsInGaiaCookie(false);
AccountsInCookieJarInfo cookie_info = identity_test_env()->RemoveRefreshTokenForAccount(account.account_id);
identity_manager()->GetAccountsInCookieJar(); ASSERT_FALSE(identity_manager()->GetAccountsInCookieJar().accounts_are_fresh);
ASSERT_FALSE(cookie_info.accounts_are_fresh);
// Unconsented account was removed. // Unconsented account was removed.
EXPECT_EQ( EXPECT_FALSE(
identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kNotRequired), identity_manager()->HasPrimaryAccount(ConsentLevel::kNotRequired));
CoreAccountInfo()); ExpectUnconsentedPrimaryAccountClearedEvent(account);
} }
TEST_F(SigninManagerTest, TEST_F(SigninManagerTest,
UnconsentedPrimaryAccountTokenRevokedWithStaleCookiesMultipleAccounts) { UnconsentedPrimaryAccountTokenRevokedWithStaleCookiesMultipleAccounts) {
// Add two accounts with cookies. // Add two accounts with cookies.
AccountInfo main_account_info = AccountInfo main_account =
identity_test_env()->MakeAccountAvailable(kTestEmail); identity_test_env()->MakeAccountAvailable(kTestEmail);
AccountInfo secondary_account_info = AccountInfo secondary_account =
identity_test_env()->MakeAccountAvailable(kTestEmail2); identity_test_env()->MakeAccountAvailable(kTestEmail2);
EXPECT_CALL(observer(), OnUnconsentedPrimaryAccountChanged(main_account_info))
.Times(1);
identity_test_env()->SetCookieAccounts( identity_test_env()->SetCookieAccounts(
{{main_account_info.email, main_account_info.gaia}, {{main_account.email, main_account.gaia},
{secondary_account_info.email, secondary_account_info.gaia}}); {secondary_account.email, secondary_account.gaia}});
VerifyAndResetCallExpectations(); EXPECT_TRUE(
EXPECT_EQ( identity_manager()->HasPrimaryAccount(ConsentLevel::kNotRequired));
identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kNotRequired), EXPECT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSync));
main_account_info); EXPECT_EQ(main_account, identity_manager()->GetPrimaryAccountInfo(
ConsentLevel::kNotRequired));
ExpectUnconsentedPrimaryAccountSetEvent(main_account);
// Make the cookies stale and remove the main account. // Make the cookies stale and remove the main account.
EXPECT_CALL(observer(), OnUnconsentedPrimaryAccountChanged(CoreAccountInfo()))
.Times(1);
identity_test_env()->SetFreshnessOfAccountsInGaiaCookie(false); identity_test_env()->SetFreshnessOfAccountsInGaiaCookie(false);
identity_test_env()->RemoveRefreshTokenForAccount( identity_test_env()->RemoveRefreshTokenForAccount(main_account.account_id);
main_account_info.account_id); ASSERT_FALSE(identity_manager()->GetAccountsInCookieJar().accounts_are_fresh);
AccountsInCookieJarInfo cookie_info =
identity_manager()->GetAccountsInCookieJar();
ASSERT_FALSE(cookie_info.accounts_are_fresh);
// Unconsented account was removed. // Unconsented account was removed.
EXPECT_EQ( EXPECT_FALSE(
identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kNotRequired), identity_manager()->HasPrimaryAccount(ConsentLevel::kNotRequired));
CoreAccountInfo()); ExpectUnconsentedPrimaryAccountClearedEvent(main_account);
} }
TEST_F(SigninManagerTest, UnconsentedPrimaryAccountDuringLoad) { TEST_F(SigninManagerTest, UnconsentedPrimaryAccountDuringLoad) {
// Add two accounts with cookies. // Pre-requisite: Add two accounts with cookies.
AccountInfo main_account_info = AccountInfo main_account =
identity_test_env()->MakeAccountAvailable(kTestEmail); identity_test_env()->MakeAccountAvailable(kTestEmail);
AccountInfo secondary_account_info = AccountInfo secondary_account =
identity_test_env()->MakeAccountAvailable(kTestEmail2); identity_test_env()->MakeAccountAvailable(kTestEmail2);
EXPECT_CALL(observer(), OnUnconsentedPrimaryAccountChanged(main_account_info))
.Times(1);
identity_test_env()->SetCookieAccounts( identity_test_env()->SetCookieAccounts(
{{main_account_info.email, main_account_info.gaia}, {{main_account.email, main_account.gaia},
{secondary_account_info.email, secondary_account_info.gaia}}); {secondary_account.email, secondary_account.gaia}});
ASSERT_EQ(main_account, identity_manager()->GetPrimaryAccountInfo(
VerifyAndResetCallExpectations(); ConsentLevel::kNotRequired));
EXPECT_EQ( ASSERT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSync));
identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kNotRequired), ExpectUnconsentedPrimaryAccountSetEvent(main_account);
main_account_info);
// Set the token service in "loading" mode. // Set the token service in "loading" mode.
identity_test_env()->ResetToAccountsNotYetLoadedFromDiskState(); identity_test_env()->ResetToAccountsNotYetLoadedFromDiskState();
RecreateSigninManager(); RecreateSigninManager();
// Unconsented primary account is available while tokens are not loaded. // Unconsented primary account is available while tokens are not loaded.
EXPECT_EQ( EXPECT_EQ(main_account, identity_manager()->GetPrimaryAccountInfo(
identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kNotRequired), ConsentLevel::kNotRequired));
main_account_info); EXPECT_TRUE(observer().events().empty());
VerifyAndResetCallExpectations();
// Revoking an unrelated token doesn't change the unconsented primary account. // Revoking an unrelated token doesn't change the unconsented primary account.
identity_test_env()->RemoveRefreshTokenForAccount( identity_test_env()->RemoveRefreshTokenForAccount(
secondary_account_info.account_id); secondary_account.account_id);
EXPECT_EQ( EXPECT_EQ(main_account, identity_manager()->GetPrimaryAccountInfo(
identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kNotRequired), ConsentLevel::kNotRequired));
main_account_info); EXPECT_TRUE(observer().events().empty());
// Revoke the unconsented primary account while tokens are not loaded. // Revoke the unconsented primary account while tokens are not loaded.
EXPECT_CALL(observer(), OnUnconsentedPrimaryAccountChanged(CoreAccountInfo())) identity_test_env()->RemoveRefreshTokenForAccount(main_account.account_id);
.Times(1);
identity_test_env()->RemoveRefreshTokenForAccount(
main_account_info.account_id);
EXPECT_FALSE( EXPECT_FALSE(
identity_manager()->HasPrimaryAccount(ConsentLevel::kNotRequired)); identity_manager()->HasPrimaryAccount(ConsentLevel::kNotRequired));
VerifyAndResetCallExpectations(); ExpectUnconsentedPrimaryAccountClearedEvent(main_account);
// Finish the token load. // Finish the token load.
identity_test_env()->ReloadAccountsFromDisk(); identity_test_env()->ReloadAccountsFromDisk();
EXPECT_FALSE( EXPECT_FALSE(
identity_manager()->HasPrimaryAccount(ConsentLevel::kNotRequired)); identity_manager()->HasPrimaryAccount(ConsentLevel::kNotRequired));
EXPECT_TRUE(observer().events().empty());
} }
TEST_F(SigninManagerTest, TEST_F(SigninManagerTest,
UnconsentedPrimaryAccountUpdatedOnSyncConsentRevoked) { UnconsentedPrimaryAccountUpdatedOnSyncConsentRevoked) {
AccountInfo first_account_info = AccountInfo first_account =
identity_test_env()->MakeAccountAvailable(kTestEmail); identity_test_env()->MakeAccountAvailable(kTestEmail);
AccountInfo second_account_info = AccountInfo second_account =
identity_test_env()->MakeAccountAvailable(kTestEmail2); identity_test_env()->MakeAccountAvailable(kTestEmail2);
EXPECT_CALL(observer(),
OnUnconsentedPrimaryAccountChanged(first_account_info))
.Times(1);
identity_test_env()->SetCookieAccounts( identity_test_env()->SetCookieAccounts(
{{first_account_info.email, first_account_info.gaia}, {{first_account.email, first_account.gaia},
{second_account_info.email, second_account_info.gaia}}); {second_account.email, second_account.gaia}});
ASSERT_EQ(first_account, identity_manager()->GetPrimaryAccountInfo(
VerifyAndResetCallExpectations(); ConsentLevel::kNotRequired));
ExpectUnconsentedPrimaryAccountSetEvent(first_account);
// Set the primary account to the second account in cookies. // Set the sync primary account to the second account in cookies.
// The unconsented primary account should be updated. // The unconsented primary account should be updated.
EXPECT_CALL(observer(), identity_test_env()->SetPrimaryAccount(second_account.email);
OnUnconsentedPrimaryAccountChanged(second_account_info)) EXPECT_EQ(second_account,
.Times(1); identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSync));
identity_test_env()->SetPrimaryAccount(second_account_info.email); EXPECT_EQ(1U, observer().events().size());
EXPECT_EQ(identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSync), auto event = observer().events()[0];
second_account_info); EXPECT_EQ(PrimaryAccountChangeEvent::Type::kSet,
VerifyAndResetCallExpectations(); 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 // Clear primary account but do not delete the account. The unconsented
// primary account should be updated to be the first account in cookies. // primary account should be updated to be the first account in cookies.
EXPECT_CALL(observer(), BeforePrimaryAccountCleared(second_account_info))
.Times(1);
EXPECT_CALL(observer(),
OnUnconsentedPrimaryAccountChanged(first_account_info))
.Times(1);
identity_test_env()->RevokeSyncConsent(); identity_test_env()->RevokeSyncConsent();
// Primary account is cleared, but unconsented account is not. // Primary account is cleared, but unconsented account is not.
EXPECT_FALSE(identity_manager()->HasPrimaryAccount()); EXPECT_FALSE(identity_manager()->HasPrimaryAccount());
EXPECT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSync)); EXPECT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSync));
EXPECT_EQ(first_account_info, identity_manager()->GetPrimaryAccountInfo( EXPECT_TRUE(
identity_manager()->HasPrimaryAccount(ConsentLevel::kNotRequired));
EXPECT_EQ(first_account, identity_manager()->GetPrimaryAccountInfo(
ConsentLevel::kNotRequired)); ConsentLevel::kNotRequired));
// OnUnconsentedPrimaryAccountChanged was fired.
VerifyAndResetCallExpectations(); 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::kNotRequired));
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::kNotRequired));
EXPECT_EQ(second_account, event.GetPreviousState().primary_account);
EXPECT_EQ(first_account, event.GetCurrentState().primary_account);
} }
TEST_F(SigninManagerTest, ClearPrimaryAccountAndSignOut) { TEST_F(SigninManagerTest, ClearPrimaryAccountAndSignOut) {
AccountInfo account_info = GetAccountInfo(kTestEmail); AccountInfo account = MakeSyncAccountAvailableWithCookies(kTestEmail);
EXPECT_CALL(observer(), OnUnconsentedPrimaryAccountChanged(account_info)) ExpectSyncPrimaryAccountSetEvent(account);
.Times(1);
identity_test_env()->MakePrimaryAccountAvailable(kTestEmail);
EXPECT_EQ(identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSync),
account_info);
VerifyAndResetCallExpectations();
identity_test_env()->SetCookieAccounts(
{{account_info.email, account_info.gaia}});
EXPECT_CALL(observer(), BeforePrimaryAccountCleared(account_info)).Times(1);
EXPECT_CALL(observer(), OnUnconsentedPrimaryAccountChanged(CoreAccountInfo()))
.Times(1);
identity_test_env()->ClearPrimaryAccount(); identity_test_env()->ClearPrimaryAccount();
VerifyAndResetCallExpectations();
EXPECT_EQ(1U, observer().events().size());
auto event = observer().events()[0];
EXPECT_EQ(PrimaryAccountChangeEvent::Type::kCleared,
event.GetEventTypeFor(ConsentLevel::kNotRequired));
EXPECT_EQ(PrimaryAccountChangeEvent::Type::kCleared,
event.GetEventTypeFor(ConsentLevel::kSync));
EXPECT_EQ(account, event.GetPreviousState().primary_account);
EXPECT_TRUE(event.GetCurrentState().primary_account.IsEmpty());
} }
} // namespace signin } // namespace signin
...@@ -503,13 +503,20 @@ void IdentityManager::OnPrimaryAccountChanged( ...@@ -503,13 +503,20 @@ void IdentityManager::OnPrimaryAccountChanged(
observer.OnPrimaryAccountChanged(event_details); observer.OnPrimaryAccountChanged(event_details);
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
if (!java_identity_manager_) if (java_identity_manager_) {
return;
JNIEnv* env = base::android::AttachCurrentThread(); JNIEnv* env = base::android::AttachCurrentThread();
Java_IdentityManager_onPrimaryAccountChanged( Java_IdentityManager_onPrimaryAccountChanged(
env, java_identity_manager_, env, java_identity_manager_,
ConvertToJavaPrimaryAccountChangeEvent(env, event_details)); ConvertToJavaPrimaryAccountChangeEvent(env, event_details));
}
#endif #endif
if (event_details.GetEventTypeFor(ConsentLevel::kSync) ==
PrimaryAccountChangeEvent::Type::kCleared) {
for (auto& observer : observer_list_) {
observer.AfterSyncPrimaryAccountCleared();
}
}
} }
void IdentityManager::FirePrimaryAccountSet( void IdentityManager::FirePrimaryAccountSet(
...@@ -536,10 +543,6 @@ void IdentityManager::FirePrimaryAccountCleared( ...@@ -536,10 +543,6 @@ void IdentityManager::FirePrimaryAccountCleared(
event_details.GetPreviousState().primary_account; event_details.GetPreviousState().primary_account;
DCHECK(!HasPrimaryAccount()); DCHECK(!HasPrimaryAccount());
DCHECK(!account_info.IsEmpty()); DCHECK(!account_info.IsEmpty());
for (auto& observer : observer_list_) {
observer.BeforePrimaryAccountCleared(account_info);
}
for (auto& observer : observer_list_) { for (auto& observer : observer_list_) {
observer.OnPrimaryAccountCleared(account_info); observer.OnPrimaryAccountCleared(account_info);
} }
......
...@@ -94,12 +94,12 @@ class IdentityManager : public KeyedService, ...@@ -94,12 +94,12 @@ class IdentityManager : public KeyedService,
const CoreAccountInfo& previous_primary_account_info) {} const CoreAccountInfo& previous_primary_account_info) {}
// TODO(crbug.com/1046746): Move to |SigninClient|. // TODO(crbug.com/1046746): Move to |SigninClient|.
// Called Before notifying all the observers of |OnPrimaryAccountCleared|. // Called After notifying all the observers of |OnPrimaryAccountChanged|
// |OnPrimaryAccountCleared| should be used instead in general.This function // if the sync primary account was cleared.
// should be used carefully, as the value of the unconsented primary account //
// is not properly defined when it is run and can be changed meanwhile. // Note: This function is only intended to be used by the signin code.
virtual void BeforePrimaryAccountCleared( // General observers should use |OnPrimaryAccountChanged|.
const CoreAccountInfo& previous_primary_account_info) {} virtual void AfterSyncPrimaryAccountCleared() {}
// When the unconsented primary account (see ./README.md) of the user // When the unconsented primary account (see ./README.md) of the user
// changes, this callback gets called with the new account as // changes, this callback gets called with the new account as
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment