Commit 386e6e51 authored by Mihai Sardarescu's avatar Mihai Sardarescu Committed by Commit Bot

Avoid useless fetches of user ID from GCM account tracker.

For every account available in the account tracker service, both the
Gaia ID and the email are available. The GCM AccountTracker was fetching
again the gaia ID from the server on every start-up and every time a new
account was added to the profile. This CL removes this useless fetch
and changed the GCM AccountTracker to reuse the information already
available in the IdentityManager.

Additional clean-up to completely remove the GCM AccountTracker would
also be good, but I do not know this code well enough to do this cleanup.

Fixed: 1028522

Change-Id: I77790a3203a94ea8c7baf19ca0eb2449b096b630
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1944492Reviewed-by: default avatarColin Blundell <blundell@chromium.org>
Commit-Queue: Mihai Sardarescu <msarda@chromium.org>
Cr-Commit-Position: refs/heads/master@{#720515}
parent d7e0ca7c
......@@ -4,22 +4,15 @@
#include "components/gcm_driver/account_tracker.h"
#include "base/bind.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/stl_util.h"
#include "base/trace_event/trace_event.h"
#include "components/signin/public/identity_manager/access_token_info.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
namespace gcm {
AccountTracker::AccountTracker(
signin::IdentityManager* identity_manager,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
: identity_manager_(identity_manager),
url_loader_factory_(std::move(url_loader_factory)),
shutdown_called_(false) {
AccountTracker::AccountTracker(signin::IdentityManager* identity_manager)
: identity_manager_(identity_manager), shutdown_called_(false) {
identity_manager_->AddObserver(this);
}
......@@ -29,14 +22,9 @@ AccountTracker::~AccountTracker() {
void AccountTracker::Shutdown() {
shutdown_called_ = true;
user_info_requests_.clear();
identity_manager_->RemoveObserver(this);
}
bool AccountTracker::IsAllUserInfoFetched() const {
return user_info_requests_.empty();
}
void AccountTracker::AddObserver(Observer* observer) {
observer_list_.AddObserver(observer);
}
......@@ -45,23 +33,25 @@ void AccountTracker::RemoveObserver(Observer* observer) {
observer_list_.RemoveObserver(observer);
}
std::vector<AccountIds> AccountTracker::GetAccounts() const {
std::vector<CoreAccountInfo> AccountTracker::GetAccounts() const {
const CoreAccountId active_account_id =
identity_manager_->GetPrimaryAccountId();
std::vector<AccountIds> accounts;
std::vector<CoreAccountInfo> accounts;
for (auto it = accounts_.begin(); it != accounts_.end(); ++it) {
const AccountState& state = it->second;
bool is_visible = state.is_signed_in && !state.ids.gaia.empty();
DCHECK(!state.account.account_id.empty());
DCHECK(!state.account.gaia.empty());
DCHECK(!state.account.email.empty());
bool is_visible = state.is_signed_in;
if (it->first == active_account_id) {
if (is_visible)
accounts.insert(accounts.begin(), state.ids);
accounts.insert(accounts.begin(), state.account);
else
return std::vector<AccountIds>();
return std::vector<CoreAccountInfo>();
} else if (is_visible) {
accounts.push_back(state.ids);
accounts.push_back(state.account);
}
}
return accounts;
......@@ -77,6 +67,7 @@ void AccountTracker::OnRefreshTokenUpdatedForAccount(
return;
DVLOG(1) << "AVAILABLE " << account_info.account_id;
StartTrackingAccount(account_info);
UpdateSignInState(account_info.account_id, /*is_signed_in=*/true);
}
......@@ -99,6 +90,7 @@ void AccountTracker::OnPrimaryAccountSet(
DVLOG(1) << "LOGIN " << accounts.size() << " accounts available.";
for (const CoreAccountInfo& account_info : accounts) {
StartTrackingAccount(account_info);
UpdateSignInState(account_info.account_id, /*is_signed_in=*/true);
}
}
......@@ -110,50 +102,38 @@ void AccountTracker::OnPrimaryAccountCleared(
StopTrackingAllAccounts();
}
void AccountTracker::NotifySignInChanged(const AccountState& account) {
DCHECK(!account.ids.gaia.empty());
for (auto& observer : observer_list_)
observer.OnAccountSignInChanged(account.ids, account.is_signed_in);
}
void AccountTracker::UpdateSignInState(const CoreAccountId& account_key,
void AccountTracker::UpdateSignInState(const CoreAccountId& account_id,
bool is_signed_in) {
StartTrackingAccount(account_key);
AccountState& account = accounts_[account_key];
bool needs_gaia_id = account.ids.gaia.empty();
bool was_signed_in = account.is_signed_in;
account.is_signed_in = is_signed_in;
if (!is_signed_in && !base::Contains(accounts_, account_id))
return;
if (needs_gaia_id && is_signed_in)
StartFetchingUserInfo(account_key);
DCHECK(base::Contains(accounts_, account_id));
AccountState& account = accounts_[account_id];
if (account.is_signed_in == is_signed_in)
return;
if (!needs_gaia_id && (was_signed_in != is_signed_in))
NotifySignInChanged(account);
account.is_signed_in = is_signed_in;
for (auto& observer : observer_list_)
observer.OnAccountSignInChanged(account.account, account.is_signed_in);
}
void AccountTracker::StartTrackingAccount(const CoreAccountId& account_key) {
if (!base::Contains(accounts_, account_key)) {
DVLOG(1) << "StartTracking " << account_key;
AccountState account_state;
account_state.ids.account_key = account_key;
account_state.ids.email = account_key.ToString();
account_state.is_signed_in = false;
accounts_.insert(std::make_pair(account_key, account_state));
}
void AccountTracker::StartTrackingAccount(const CoreAccountInfo& account) {
if (base::Contains(accounts_, account.account_id))
return;
DVLOG(1) << "StartTracking " << account.account_id;
AccountState account_state;
account_state.account = account;
account_state.is_signed_in = false;
accounts_.insert(std::make_pair(account.account_id, account_state));
}
void AccountTracker::StopTrackingAccount(const CoreAccountId account_key) {
DVLOG(1) << "StopTracking " << account_key;
if (base::Contains(accounts_, account_key)) {
AccountState& account = accounts_[account_key];
if (!account.ids.gaia.empty()) {
UpdateSignInState(account_key, /*is_signed_in=*/false);
}
accounts_.erase(account_key);
void AccountTracker::StopTrackingAccount(const CoreAccountId account_id) {
DVLOG(1) << "StopTracking " << account_id;
if (base::Contains(accounts_, account_id)) {
UpdateSignInState(account_id, /*is_signed_in=*/false);
accounts_.erase(account_id);
}
if (base::Contains(user_info_requests_, account_key))
DeleteFetcher(user_info_requests_[account_key].get());
}
void AccountTracker::StopTrackingAllAccounts() {
......@@ -161,117 +141,4 @@ void AccountTracker::StopTrackingAllAccounts() {
StopTrackingAccount(accounts_.begin()->first);
}
void AccountTracker::StartFetchingUserInfo(const CoreAccountId& account_key) {
if (base::Contains(user_info_requests_, account_key)) {
DeleteFetcher(user_info_requests_[account_key].get());
}
DVLOG(1) << "StartFetching " << account_key;
AccountIdFetcher* fetcher = new AccountIdFetcher(
identity_manager_, url_loader_factory_, this, account_key);
user_info_requests_[account_key] = base::WrapUnique(fetcher);
fetcher->Start();
}
void AccountTracker::OnUserInfoFetchSuccess(AccountIdFetcher* fetcher,
const std::string& gaia_id) {
const CoreAccountId& account_key = fetcher->account_key();
DCHECK(base::Contains(accounts_, account_key));
AccountState& account = accounts_[account_key];
account.ids.gaia = gaia_id;
if (account.is_signed_in)
NotifySignInChanged(account);
DeleteFetcher(fetcher);
}
void AccountTracker::OnUserInfoFetchFailure(AccountIdFetcher* fetcher) {
LOG(WARNING) << "Failed to get UserInfo for " << fetcher->account_key();
CoreAccountId key = fetcher->account_key();
DeleteFetcher(fetcher);
StopTrackingAccount(key);
}
void AccountTracker::DeleteFetcher(AccountIdFetcher* fetcher) {
DVLOG(1) << "DeleteFetcher " << fetcher->account_key();
const CoreAccountId& account_key = fetcher->account_key();
DCHECK(base::Contains(user_info_requests_, account_key));
DCHECK_EQ(fetcher, user_info_requests_[account_key].get());
user_info_requests_.erase(account_key);
}
AccountIdFetcher::AccountIdFetcher(
signin::IdentityManager* identity_manager,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
AccountTracker* tracker,
const CoreAccountId& account_key)
: identity_manager_(identity_manager),
url_loader_factory_(std::move(url_loader_factory)),
tracker_(tracker),
account_key_(account_key) {
TRACE_EVENT_ASYNC_BEGIN1("identity", "AccountIdFetcher", this, "account_key",
account_key.ToString());
}
AccountIdFetcher::~AccountIdFetcher() {
TRACE_EVENT_ASYNC_END0("identity", "AccountIdFetcher", this);
}
void AccountIdFetcher::Start() {
identity::ScopeSet scopes;
scopes.insert("https://www.googleapis.com/auth/userinfo.profile");
access_token_fetcher_ = identity_manager_->CreateAccessTokenFetcherForAccount(
account_key_, "gaia_account_tracker", scopes,
base::BindOnce(&AccountIdFetcher::AccessTokenFetched,
base::Unretained(this)),
signin::AccessTokenFetcher::Mode::kImmediate);
}
void AccountIdFetcher::AccessTokenFetched(
GoogleServiceAuthError error,
signin::AccessTokenInfo access_token_info) {
access_token_fetcher_.reset();
if (error != GoogleServiceAuthError::AuthErrorNone()) {
TRACE_EVENT_ASYNC_STEP_PAST1("identity", "AccountIdFetcher", this,
"AccessTokenFetched",
"google_service_auth_error", error.ToString());
LOG(ERROR) << "AccessTokenFetched error: " << error.ToString();
tracker_->OnUserInfoFetchFailure(this);
return;
}
TRACE_EVENT_ASYNC_STEP_PAST0("identity", "AccountIdFetcher", this,
"AccessTokenFetched");
gaia_oauth_client_.reset(new gaia::GaiaOAuthClient(url_loader_factory_));
const int kMaxGetUserIdRetries = 3;
gaia_oauth_client_->GetUserId(access_token_info.token, kMaxGetUserIdRetries,
this);
}
void AccountIdFetcher::OnGetUserIdResponse(const std::string& gaia_id) {
TRACE_EVENT_ASYNC_STEP_PAST1("identity", "AccountIdFetcher", this,
"OnGetUserIdResponse", "gaia_id", gaia_id);
tracker_->OnUserInfoFetchSuccess(this, gaia_id);
}
void AccountIdFetcher::OnOAuthError() {
TRACE_EVENT_ASYNC_STEP_PAST0("identity", "AccountIdFetcher", this,
"OnOAuthError");
LOG(ERROR) << "OnOAuthError";
tracker_->OnUserInfoFetchFailure(this);
}
void AccountIdFetcher::OnNetworkError(int response_code) {
TRACE_EVENT_ASYNC_STEP_PAST1("identity", "AccountIdFetcher", this,
"OnNetworkError", "response_code",
response_code);
LOG(ERROR) << "OnNetworkError " << response_code;
tracker_->OnUserInfoFetchFailure(this);
}
} // namespace gcm
......@@ -10,52 +10,22 @@
#include <string>
#include <vector>
#include "base/memory/scoped_refptr.h"
#include "base/observer_list.h"
#include "components/signin/public/identity_manager/access_token_fetcher.h"
#include "components/signin/public/identity_manager/identity_manager.h"
#include "google_apis/gaia/core_account_id.h"
#include "google_apis/gaia/gaia_oauth_client.h"
class GoogleServiceAuthError;
namespace signin {
struct AccessTokenInfo;
}
namespace network {
class SharedURLLoaderFactory;
}
namespace gcm {
struct AccountIds {
CoreAccountId account_key; // The account ID used by IdentityManager.
std::string gaia;
std::string email;
};
class AccountIdFetcher;
// The AccountTracker keeps track of what accounts exist on the
// profile and the state of their credentials. The tracker fetches the
// gaia ID of each account it knows about.
//
// The AccountTracker maintains these invariants:
// 1. Events are only fired after the gaia ID has been fetched.
// 2. Add/Remove and SignIn/SignOut pairs are always generated in order.
// 3. SignIn follows Add, and there will be a SignOut between SignIn & Remove.
// 4. If there is no primary account, there are no other accounts.
// profile and the state of their credentials.
class AccountTracker : public signin::IdentityManager::Observer {
public:
AccountTracker(
signin::IdentityManager* identity_manager,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
explicit AccountTracker(signin::IdentityManager* identity_manager);
~AccountTracker() override;
class Observer {
public:
virtual void OnAccountSignInChanged(const AccountIds& ids,
virtual void OnAccountSignInChanged(const CoreAccountInfo& account,
bool is_signed_in) = 0;
};
......@@ -64,20 +34,14 @@ class AccountTracker : public signin::IdentityManager::Observer {
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
// Returns the list of accounts that are signed in, and for which gaia IDs
// Returns the list of accounts that are signed in, and for which gaia account
// have been fetched. The primary account for the profile will be first
// in the vector. Additional accounts will be in order of their gaia IDs.
std::vector<AccountIds> GetAccounts() const;
// Indicates if all user information has been fetched. If the result is false,
// there are still unfinished fetchers.
virtual bool IsAllUserInfoFetched() const;
// in the vector. Additional accounts will be in order of their gaia account.
std::vector<CoreAccountInfo> GetAccounts() const;
private:
friend class AccountIdFetcher;
struct AccountState {
AccountIds ids;
CoreAccountInfo account;
bool is_signed_in;
};
......@@ -91,65 +55,26 @@ class AccountTracker : public signin::IdentityManager::Observer {
void OnRefreshTokenRemovedForAccount(
const CoreAccountId& account_id) override;
void OnUserInfoFetchSuccess(AccountIdFetcher* fetcher,
const std::string& gaia_id);
void OnUserInfoFetchFailure(AccountIdFetcher* fetcher);
void NotifySignInChanged(const AccountState& account);
// Add |account_info| to the lists of accounts tracked by this AccountTracker.
void StartTrackingAccount(const CoreAccountInfo& account_info);
void UpdateSignInState(const CoreAccountId& account_key, bool is_signed_in);
void StartTrackingAccount(const CoreAccountId& account_key);
// Note: |account_key| is passed by value here, because the original
// object may be stored in |accounts_| and if so, it will be destroyed
// after erasing the key from the map.
void StopTrackingAccount(const CoreAccountId account_key);
// Stops tracking |account_id|. Notifies all observers if the account was
// previously signed in.
void StopTrackingAccount(const CoreAccountId account_id);
// Stops tracking all accounts.
void StopTrackingAllAccounts();
void StartFetchingUserInfo(const CoreAccountId& account_key);
void DeleteFetcher(AccountIdFetcher* fetcher);
// Updates the is_signed_in corresponding to the given account. Notifies all
// observers of the signed in state changes.
void UpdateSignInState(const CoreAccountId& account_id, bool is_signed_in);
signin::IdentityManager* identity_manager_;
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
std::map<CoreAccountId, std::unique_ptr<AccountIdFetcher>>
user_info_requests_;
std::map<CoreAccountId, AccountState> accounts_;
base::ObserverList<Observer>::Unchecked observer_list_;
bool shutdown_called_;
};
class AccountIdFetcher : public gaia::GaiaOAuthClient::Delegate {
public:
AccountIdFetcher(
signin::IdentityManager* identity_manager,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
AccountTracker* tracker,
const CoreAccountId& account_key);
~AccountIdFetcher() override;
const CoreAccountId& account_key() { return account_key_; }
void Start();
void AccessTokenFetched(GoogleServiceAuthError error,
signin::AccessTokenInfo access_token_info);
// gaia::GaiaOAuthClient::Delegate implementation.
void OnGetUserIdResponse(const std::string& gaia_id) override;
void OnOAuthError() override;
void OnNetworkError(int response_code) override;
private:
signin::IdentityManager* identity_manager_;
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
AccountTracker* tracker_;
const CoreAccountId account_key_;
std::unique_ptr<signin::AccessTokenFetcher> access_token_fetcher_;
std::unique_ptr<gaia::GaiaOAuthClient> gaia_oauth_client_;
};
} // namespace gcm
#endif // COMPONENTS_GCM_DRIVER_ACCOUNT_TRACKER_H_
......@@ -11,24 +11,14 @@
#include "base/test/task_environment.h"
#include "build/build_config.h"
#include "components/signin/public/identity_manager/identity_test_environment.h"
#include "google_apis/gaia/gaia_oauth_client.h"
#include "net/http/http_status_code.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/test/test_url_loader_factory.h"
#include "services/network/test/test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
const char kOAuthURL[] = "https://www.googleapis.com/oauth2/v1/userinfo";
const char kPrimaryAccountEmail[] = "primary_account@example.com";
enum TrackingEventType { SIGN_IN, SIGN_OUT };
std::string AccountKeyToObfuscatedId(const CoreAccountId& account_id) {
return "obfid-" + account_id.ToString();
}
class TrackingEvent {
public:
TrackingEvent(TrackingEventType type,
......@@ -36,10 +26,10 @@ class TrackingEvent {
const std::string& gaia_id)
: type_(type), account_id_(account_id), gaia_id_(gaia_id) {}
TrackingEvent(TrackingEventType type, const CoreAccountId& account_id)
TrackingEvent(TrackingEventType type, const CoreAccountInfo& account_info)
: type_(type),
account_id_(account_id),
gaia_id_(AccountKeyToObfuscatedId(account_id)) {}
account_id_(account_info.account_id),
gaia_id_(account_info.gaia) {}
bool operator==(const TrackingEvent& event) const {
return type_ == event.type_ && account_id_ == event.account_id_ &&
......@@ -120,7 +110,7 @@ class AccountTrackerObserver : public AccountTracker::Observer {
void SortEventsByUser();
// AccountTracker::Observer implementation
void OnAccountSignInChanged(const AccountIds& ids,
void OnAccountSignInChanged(const CoreAccountInfo& account,
bool is_signed_in) override;
private:
......@@ -130,10 +120,11 @@ class AccountTrackerObserver : public AccountTracker::Observer {
std::vector<TrackingEvent> events_;
};
void AccountTrackerObserver::OnAccountSignInChanged(const AccountIds& ids,
bool is_signed_in) {
void AccountTrackerObserver::OnAccountSignInChanged(
const CoreAccountInfo& account,
bool is_signed_in) {
events_.push_back(TrackingEvent(is_signed_in ? SIGN_IN : SIGN_OUT,
ids.account_key, ids.gaia));
account.account_id, account.gaia));
}
void AccountTrackerObserver::Clear() {
......@@ -241,10 +232,8 @@ class AccountTrackerTest : public testing::Test {
~AccountTrackerTest() override {}
void SetUp() override {
account_tracker_.reset(new AccountTracker(
identity_test_env_.identity_manager(),
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&test_url_loader_factory_)));
account_tracker_.reset(
new AccountTracker(identity_test_env_.identity_manager()));
account_tracker_->AddObserver(&observer_);
}
......@@ -265,8 +254,8 @@ class AccountTrackerTest : public testing::Test {
// the underlying GoogleSigninSucceeded callback is never sent). Tests that
// exercise functionality dependent on that callback firing are not relevant
// on ChromeOS and should simply not run on that platform.
CoreAccountId SetActiveAccount(const std::string& email) {
return identity_test_env_.SetPrimaryAccount(email).account_id;
CoreAccountInfo SetActiveAccount(const std::string& email) {
return identity_test_env_.SetPrimaryAccount(email);
}
// Helpers that go through a logout flow.
......@@ -286,8 +275,8 @@ class AccountTrackerTest : public testing::Test {
}
#endif
CoreAccountId AddAccountWithToken(const std::string& email) {
return identity_test_env_.MakeAccountAvailable(email).account_id;
CoreAccountInfo AddAccountWithToken(const std::string& email) {
return identity_test_env_.MakeAccountAvailable(email);
}
void NotifyTokenAvailable(const CoreAccountId& account_id) {
......@@ -298,74 +287,30 @@ class AccountTrackerTest : public testing::Test {
identity_test_env_.RemoveRefreshTokenForAccount(account_id);
}
// Helpers to fake access token and user info fetching
void IssueAccessToken(const CoreAccountId& account_id) {
identity_test_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
account_id, "access_token-" + account_id.ToString(), base::Time::Max());
}
std::string GetValidTokenInfoResponse(const CoreAccountId& account_id) {
return std::string("{ \"id\": \"") + AccountKeyToObfuscatedId(account_id) +
"\" }";
}
void ReturnOAuthUrlFetchResults(net::HttpStatusCode response_code,
const std::string& response_string);
void ReturnOAuthUrlFetchSuccess(const CoreAccountId& account_id);
void ReturnOAuthUrlFetchFailure(const CoreAccountId& account_id);
CoreAccountId SetupPrimaryLogin() {
CoreAccountInfo SetupPrimaryLogin() {
// Initial setup for tests that start with a signed in profile.
CoreAccountId primary_account_id = SetActiveAccount(kPrimaryAccountEmail);
NotifyTokenAvailable(primary_account_id);
ReturnOAuthUrlFetchSuccess(primary_account_id);
CoreAccountInfo primary_account = SetActiveAccount(kPrimaryAccountEmail);
NotifyTokenAvailable(primary_account.account_id);
observer()->Clear();
return primary_account_id;
}
network::TestURLLoaderFactory* test_url_loader_factory() {
return &test_url_loader_factory_;
return primary_account;
}
private:
// net:: stuff needs IO message loop.
base::test::SingleThreadTaskEnvironment task_environment_{
base::test::SingleThreadTaskEnvironment::MainThreadType::IO};
network::TestURLLoaderFactory test_url_loader_factory_;
signin::IdentityTestEnvironment identity_test_env_;
std::unique_ptr<AccountTracker> account_tracker_;
AccountTrackerObserver observer_;
};
void AccountTrackerTest::ReturnOAuthUrlFetchResults(
net::HttpStatusCode response_code,
const std::string& response_string) {
EXPECT_TRUE(test_url_loader_factory()->SimulateResponseForPendingRequest(
GURL(kOAuthURL), network::URLLoaderCompletionStatus(net::OK),
network::CreateURLResponseHead(response_code), response_string));
}
void AccountTrackerTest::ReturnOAuthUrlFetchSuccess(
const CoreAccountId& account_id) {
IssueAccessToken(account_id);
ReturnOAuthUrlFetchResults(net::HTTP_OK,
GetValidTokenInfoResponse(account_id));
}
void AccountTrackerTest::ReturnOAuthUrlFetchFailure(
const CoreAccountId& account_id) {
IssueAccessToken(account_id);
ReturnOAuthUrlFetchResults(net::HTTP_BAD_REQUEST, "");
}
// Primary tests just involve the Active account
TEST_F(AccountTrackerTest, PrimaryNoEventsBeforeLogin) {
CoreAccountId account_id = AddAccountWithToken("me@dummy.com");
NotifyTokenRevoked(account_id);
CoreAccountInfo account = AddAccountWithToken("me@dummy.com");
NotifyTokenRevoked(account.account_id);
// Logout is not possible on ChromeOS.
#if !defined(OS_CHROMEOS)
......@@ -376,36 +321,29 @@ TEST_F(AccountTrackerTest, PrimaryNoEventsBeforeLogin) {
}
TEST_F(AccountTrackerTest, PrimaryLoginThenTokenAvailable) {
CoreAccountId primary_account_id = SetActiveAccount(kPrimaryAccountEmail);
NotifyTokenAvailable(primary_account_id);
EXPECT_TRUE(observer()->CheckEvents());
ReturnOAuthUrlFetchSuccess(primary_account_id);
EXPECT_TRUE(
observer()->CheckEvents(TrackingEvent(SIGN_IN, primary_account_id)));
CoreAccountInfo primary_account = SetActiveAccount(kPrimaryAccountEmail);
NotifyTokenAvailable(primary_account.account_id);
EXPECT_TRUE(observer()->CheckEvents(TrackingEvent(SIGN_IN, primary_account)));
}
TEST_F(AccountTrackerTest, PrimaryRevoke) {
CoreAccountId primary_account_id = SetActiveAccount(kPrimaryAccountEmail);
NotifyTokenAvailable(primary_account_id);
ReturnOAuthUrlFetchSuccess(primary_account_id);
CoreAccountInfo primary_account = SetActiveAccount(kPrimaryAccountEmail);
NotifyTokenAvailable(primary_account.account_id);
observer()->Clear();
NotifyTokenRevoked(primary_account_id);
NotifyTokenRevoked(primary_account.account_id);
EXPECT_TRUE(
observer()->CheckEvents(TrackingEvent(SIGN_OUT, primary_account_id)));
observer()->CheckEvents(TrackingEvent(SIGN_OUT, primary_account)));
}
TEST_F(AccountTrackerTest, PrimaryRevokeThenTokenAvailable) {
CoreAccountId primary_account_id = SetActiveAccount(kPrimaryAccountEmail);
NotifyTokenAvailable(primary_account_id);
ReturnOAuthUrlFetchSuccess(primary_account_id);
NotifyTokenRevoked(primary_account_id);
CoreAccountInfo primary_account = SetActiveAccount(kPrimaryAccountEmail);
NotifyTokenAvailable(primary_account.account_id);
NotifyTokenRevoked(primary_account.account_id);
observer()->Clear();
NotifyTokenAvailable(primary_account_id);
EXPECT_TRUE(
observer()->CheckEvents(TrackingEvent(SIGN_IN, primary_account_id)));
NotifyTokenAvailable(primary_account.account_id);
EXPECT_TRUE(observer()->CheckEvents(TrackingEvent(SIGN_IN, primary_account)));
}
// These tests exercise true login/logout, which are not possible on ChromeOS.
......@@ -414,17 +352,15 @@ TEST_F(AccountTrackerTest, PrimaryTokenAvailableThenLogin) {
AddAccountWithToken(kPrimaryAccountEmail);
EXPECT_TRUE(observer()->CheckEvents());
CoreAccountId primary_account_id = SetActiveAccount(kPrimaryAccountEmail);
ReturnOAuthUrlFetchSuccess(primary_account_id);
EXPECT_TRUE(
observer()->CheckEvents(TrackingEvent(SIGN_IN, primary_account_id)));
CoreAccountInfo primary_account = SetActiveAccount(kPrimaryAccountEmail);
EXPECT_TRUE(observer()->CheckEvents(TrackingEvent(SIGN_IN, primary_account)));
}
TEST_F(AccountTrackerTest, PrimaryTokenAvailableAndRevokedThenLogin) {
CoreAccountId primary_account_id = AddAccountWithToken(kPrimaryAccountEmail);
CoreAccountInfo primary_account = AddAccountWithToken(kPrimaryAccountEmail);
EXPECT_TRUE(observer()->CheckEvents());
NotifyTokenRevoked(primary_account_id);
NotifyTokenRevoked(primary_account.account_id);
EXPECT_TRUE(observer()->CheckEvents());
SetActiveAccount(kPrimaryAccountEmail);
......@@ -432,9 +368,8 @@ TEST_F(AccountTrackerTest, PrimaryTokenAvailableAndRevokedThenLogin) {
}
TEST_F(AccountTrackerTest, PrimaryRevokeThenLogin) {
CoreAccountId primary_account_id = SetActiveAccount(kPrimaryAccountEmail);
NotifyTokenAvailable(primary_account_id);
ReturnOAuthUrlFetchSuccess(primary_account_id);
CoreAccountInfo primary_account = SetActiveAccount(kPrimaryAccountEmail);
NotifyTokenAvailable(primary_account.account_id);
NotifyLogoutOfAllAccounts();
observer()->Clear();
......@@ -443,32 +378,18 @@ TEST_F(AccountTrackerTest, PrimaryRevokeThenLogin) {
}
TEST_F(AccountTrackerTest, PrimaryLogoutThenRevoke) {
CoreAccountId primary_account_id = SetActiveAccount(kPrimaryAccountEmail);
NotifyTokenAvailable(primary_account_id);
ReturnOAuthUrlFetchSuccess(primary_account_id);
CoreAccountInfo primary_account = SetActiveAccount(kPrimaryAccountEmail);
NotifyTokenAvailable(primary_account.account_id);
observer()->Clear();
NotifyLogoutOfAllAccounts();
EXPECT_TRUE(
observer()->CheckEvents(TrackingEvent(SIGN_OUT, primary_account_id)));
observer()->CheckEvents(TrackingEvent(SIGN_OUT, primary_account)));
NotifyTokenRevoked(primary_account_id);
NotifyTokenRevoked(primary_account.account_id);
EXPECT_TRUE(observer()->CheckEvents());
}
TEST_F(AccountTrackerTest, PrimaryLogoutFetchCancelAvailable) {
CoreAccountId primary_account_id = SetActiveAccount(kPrimaryAccountEmail);
NotifyTokenAvailable(primary_account_id);
// TokenAvailable kicks off a fetch. Logout without satisfying it.
NotifyLogoutOfAllAccounts();
EXPECT_TRUE(observer()->CheckEvents());
SetActiveAccount(kPrimaryAccountEmail);
NotifyTokenAvailable(primary_account_id);
ReturnOAuthUrlFetchSuccess(primary_account_id);
EXPECT_TRUE(
observer()->CheckEvents(TrackingEvent(SIGN_IN, primary_account_id)));
}
#endif
// Non-primary accounts
......@@ -476,153 +397,67 @@ TEST_F(AccountTrackerTest, PrimaryLogoutFetchCancelAvailable) {
TEST_F(AccountTrackerTest, Available) {
SetupPrimaryLogin();
CoreAccountId account_id = AddAccountWithToken("user@example.com");
EXPECT_TRUE(observer()->CheckEvents());
ReturnOAuthUrlFetchSuccess(account_id);
EXPECT_TRUE(observer()->CheckEvents(TrackingEvent(SIGN_IN, account_id)));
CoreAccountInfo account = AddAccountWithToken("user@example.com");
EXPECT_TRUE(observer()->CheckEvents(TrackingEvent(SIGN_IN, account)));
}
TEST_F(AccountTrackerTest, AvailableRevokeAvailable) {
SetupPrimaryLogin();
CoreAccountId account_id = AddAccountWithToken("user@example.com");
ReturnOAuthUrlFetchSuccess(account_id);
NotifyTokenRevoked(account_id);
EXPECT_TRUE(observer()->CheckEvents(TrackingEvent(SIGN_IN, account_id),
TrackingEvent(SIGN_OUT, account_id)));
NotifyTokenAvailable(account_id);
EXPECT_TRUE(observer()->CheckEvents(TrackingEvent(SIGN_IN, account_id)));
}
TEST_F(AccountTrackerTest, AvailableRevokeAvailableWithPendingFetch) {
SetupPrimaryLogin();
CoreAccountId account_id = AddAccountWithToken("user@example.com");
NotifyTokenRevoked(account_id);
EXPECT_TRUE(observer()->CheckEvents());
CoreAccountInfo account = AddAccountWithToken("user@example.com");
NotifyTokenRevoked(account.account_id);
EXPECT_TRUE(observer()->CheckEvents(TrackingEvent(SIGN_IN, account),
TrackingEvent(SIGN_OUT, account)));
NotifyTokenAvailable(account_id);
ReturnOAuthUrlFetchSuccess(account_id);
EXPECT_TRUE(observer()->CheckEvents(TrackingEvent(SIGN_IN, account_id)));
NotifyTokenAvailable(account.account_id);
EXPECT_TRUE(observer()->CheckEvents(TrackingEvent(SIGN_IN, account)));
}
TEST_F(AccountTrackerTest, AvailableRevokeRevoke) {
SetupPrimaryLogin();
CoreAccountId account_id = AddAccountWithToken("user@example.com");
ReturnOAuthUrlFetchSuccess(account_id);
NotifyTokenRevoked(account_id);
EXPECT_TRUE(observer()->CheckEvents(TrackingEvent(SIGN_IN, account_id),
TrackingEvent(SIGN_OUT, account_id)));
CoreAccountInfo account = AddAccountWithToken("user@example.com");
NotifyTokenRevoked(account.account_id);
EXPECT_TRUE(observer()->CheckEvents(TrackingEvent(SIGN_IN, account),
TrackingEvent(SIGN_OUT, account)));
NotifyTokenRevoked(account_id);
NotifyTokenRevoked(account.account_id);
EXPECT_TRUE(observer()->CheckEvents());
}
TEST_F(AccountTrackerTest, AvailableAvailable) {
SetupPrimaryLogin();
CoreAccountId account_id = AddAccountWithToken("user@example.com");
ReturnOAuthUrlFetchSuccess(account_id);
EXPECT_TRUE(observer()->CheckEvents(TrackingEvent(SIGN_IN, account_id)));
CoreAccountInfo account = AddAccountWithToken("user@example.com");
EXPECT_TRUE(observer()->CheckEvents(TrackingEvent(SIGN_IN, account)));
NotifyTokenAvailable(account_id);
NotifyTokenAvailable(account.account_id);
EXPECT_TRUE(observer()->CheckEvents());
}
TEST_F(AccountTrackerTest, TwoAccounts) {
SetupPrimaryLogin();
CoreAccountId alpha_account_id = AddAccountWithToken("alpha@example.com");
ReturnOAuthUrlFetchSuccess(alpha_account_id);
EXPECT_TRUE(
observer()->CheckEvents(TrackingEvent(SIGN_IN, alpha_account_id)));
CoreAccountId beta_account_id = AddAccountWithToken("beta@example.com");
ReturnOAuthUrlFetchSuccess(beta_account_id);
EXPECT_TRUE(observer()->CheckEvents(TrackingEvent(SIGN_IN, beta_account_id)));
NotifyTokenRevoked(alpha_account_id);
EXPECT_TRUE(
observer()->CheckEvents(TrackingEvent(SIGN_OUT, alpha_account_id)));
NotifyTokenRevoked(beta_account_id);
EXPECT_TRUE(
observer()->CheckEvents(TrackingEvent(SIGN_OUT, beta_account_id)));
}
TEST_F(AccountTrackerTest, AvailableTokenFetchFailAvailable) {
SetupPrimaryLogin();
CoreAccountId account_id = AddAccountWithToken("user@example.com");
ReturnOAuthUrlFetchFailure(account_id);
EXPECT_TRUE(observer()->CheckEvents());
NotifyTokenAvailable(account_id);
ReturnOAuthUrlFetchSuccess(account_id);
EXPECT_TRUE(observer()->CheckEvents(TrackingEvent(SIGN_IN, account_id)));
}
// These tests exercise true login/logout, which are not possible on ChromeOS.
#if !defined(OS_CHROMEOS)
TEST_F(AccountTrackerTest, MultiSignOutSignIn) {
CoreAccountId primary_account_id = SetupPrimaryLogin();
CoreAccountId alpha_account_id = AddAccountWithToken("alpha@example.com");
ReturnOAuthUrlFetchSuccess(alpha_account_id);
CoreAccountId beta_account_id = AddAccountWithToken("beta@example.com");
ReturnOAuthUrlFetchSuccess(beta_account_id);
CoreAccountInfo alpha_account = AddAccountWithToken("alpha@example.com");
EXPECT_TRUE(observer()->CheckEvents(TrackingEvent(SIGN_IN, alpha_account)));
observer()->SortEventsByUser();
EXPECT_TRUE(observer()->CheckEvents(TrackingEvent(SIGN_IN, alpha_account_id),
TrackingEvent(SIGN_IN, beta_account_id)));
CoreAccountInfo beta_account = AddAccountWithToken("beta@example.com");
EXPECT_TRUE(observer()->CheckEvents(TrackingEvent(SIGN_IN, beta_account)));
// Log out of the primary account only (allows for testing that the account
// tracker preserves knowledge of "beta@example.com").
NotifyLogoutOfPrimaryAccountOnly();
observer()->SortEventsByUser();
EXPECT_TRUE(
observer()->CheckEvents(TrackingEvent(SIGN_OUT, alpha_account_id),
TrackingEvent(SIGN_OUT, beta_account_id),
TrackingEvent(SIGN_OUT, primary_account_id)));
// No events fire at all while profile is signed out.
NotifyTokenRevoked(alpha_account_id);
CoreAccountId gamma_account_id = AddAccountWithToken("gamma@example.com");
EXPECT_TRUE(observer()->CheckEvents());
// Signing the profile in again will resume tracking all accounts.
SetActiveAccount(kPrimaryAccountEmail);
NotifyTokenAvailable(primary_account_id);
ReturnOAuthUrlFetchSuccess(beta_account_id);
ReturnOAuthUrlFetchSuccess(gamma_account_id);
ReturnOAuthUrlFetchSuccess(primary_account_id);
observer()->SortEventsByUser();
EXPECT_TRUE(
observer()->CheckEvents(TrackingEvent(SIGN_IN, beta_account_id),
TrackingEvent(SIGN_IN, gamma_account_id),
TrackingEvent(SIGN_IN, primary_account_id)));
NotifyTokenRevoked(alpha_account.account_id);
EXPECT_TRUE(observer()->CheckEvents(TrackingEvent(SIGN_OUT, alpha_account)));
// Revoking the primary token does not affect other accounts.
NotifyTokenRevoked(primary_account_id);
EXPECT_TRUE(
observer()->CheckEvents(TrackingEvent(SIGN_OUT, primary_account_id)));
NotifyTokenAvailable(primary_account_id);
EXPECT_TRUE(
observer()->CheckEvents(TrackingEvent(SIGN_IN, primary_account_id)));
NotifyTokenRevoked(beta_account.account_id);
EXPECT_TRUE(observer()->CheckEvents(TrackingEvent(SIGN_OUT, beta_account)));
}
#endif
// Primary/non-primary interactions
TEST_F(AccountTrackerTest, MultiNoEventsBeforeLogin) {
CoreAccountId account_id1 = AddAccountWithToken("user@example.com");
CoreAccountId account_id2 = AddAccountWithToken("user2@example.com");
NotifyTokenRevoked(account_id2);
NotifyTokenRevoked(account_id1);
CoreAccountInfo account1 = AddAccountWithToken("user@example.com");
CoreAccountInfo account2 = AddAccountWithToken("user2@example.com");
NotifyTokenRevoked(account2.account_id);
NotifyTokenRevoked(account2.account_id);
// Logout is not possible on ChromeOS.
#if !defined(OS_CHROMEOS)
......@@ -633,97 +468,76 @@ TEST_F(AccountTrackerTest, MultiNoEventsBeforeLogin) {
}
TEST_F(AccountTrackerTest, MultiRevokePrimaryDoesNotRemoveAllAccounts) {
CoreAccountId primary_account_id = SetActiveAccount(kPrimaryAccountEmail);
NotifyTokenAvailable(primary_account_id);
ReturnOAuthUrlFetchSuccess(primary_account_id);
CoreAccountId account_id = AddAccountWithToken("user@example.com");
ReturnOAuthUrlFetchSuccess(account_id);
CoreAccountInfo primary_account = SetActiveAccount(kPrimaryAccountEmail);
NotifyTokenAvailable(primary_account.account_id);
CoreAccountInfo account = AddAccountWithToken("user@example.com");
observer()->Clear();
NotifyTokenRevoked(primary_account_id);
NotifyTokenRevoked(primary_account.account_id);
observer()->SortEventsByUser();
EXPECT_TRUE(
observer()->CheckEvents(TrackingEvent(SIGN_OUT, primary_account_id)));
observer()->CheckEvents(TrackingEvent(SIGN_OUT, primary_account)));
}
TEST_F(AccountTrackerTest, GetAccountsPrimary) {
CoreAccountId primary_account_id = SetupPrimaryLogin();
CoreAccountInfo primary_account = SetupPrimaryLogin();
std::vector<AccountIds> ids = account_tracker()->GetAccounts();
EXPECT_EQ(1ul, ids.size());
EXPECT_EQ(primary_account_id, ids[0].account_key);
EXPECT_EQ(AccountKeyToObfuscatedId(primary_account_id), ids[0].gaia);
std::vector<CoreAccountInfo> account = account_tracker()->GetAccounts();
EXPECT_EQ(1ul, account.size());
EXPECT_EQ(primary_account.account_id, account[0].account_id);
EXPECT_EQ(primary_account.gaia, account[0].gaia);
EXPECT_EQ(primary_account.email, account[0].email);
}
TEST_F(AccountTrackerTest, GetAccountsSignedOut) {
std::vector<AccountIds> ids = account_tracker()->GetAccounts();
EXPECT_EQ(0ul, ids.size());
std::vector<CoreAccountInfo> accounts = account_tracker()->GetAccounts();
EXPECT_EQ(0ul, accounts.size());
}
TEST_F(AccountTrackerTest, GetAccountsOnlyReturnAccountsWithTokens) {
CoreAccountId primary_account_id = SetupPrimaryLogin();
TEST_F(AccountTrackerTest, GetMultipleAccounts) {
CoreAccountInfo primary_account = SetupPrimaryLogin();
CoreAccountInfo alpha_account = AddAccountWithToken("alpha@example.com");
CoreAccountInfo beta_account = AddAccountWithToken("beta@example.com");
CoreAccountId alpha_account_id = AddAccountWithToken("alpha@example.com");
CoreAccountId beta_account_id = AddAccountWithToken("beta@example.com");
ReturnOAuthUrlFetchSuccess(beta_account_id);
std::vector<CoreAccountInfo> account = account_tracker()->GetAccounts();
EXPECT_EQ(3ul, account.size());
EXPECT_EQ(primary_account.account_id, account[0].account_id);
EXPECT_EQ(primary_account.email, account[0].email);
EXPECT_EQ(primary_account.gaia, account[0].gaia);
std::vector<AccountIds> ids = account_tracker()->GetAccounts();
EXPECT_EQ(2ul, ids.size());
EXPECT_EQ(primary_account_id, ids[0].account_key);
EXPECT_EQ(AccountKeyToObfuscatedId(primary_account_id), ids[0].gaia);
EXPECT_EQ(beta_account_id, ids[1].account_key);
EXPECT_EQ(AccountKeyToObfuscatedId(beta_account_id), ids[1].gaia);
}
TEST_F(AccountTrackerTest, GetAccountsSortOrder) {
CoreAccountId primary_account_id = SetupPrimaryLogin();
EXPECT_EQ(alpha_account.account_id, account[1].account_id);
EXPECT_EQ(alpha_account.email, account[1].email);
EXPECT_EQ(alpha_account.gaia, account[1].gaia);
CoreAccountId zeta_account_id = AddAccountWithToken("zeta@example.com");
ReturnOAuthUrlFetchSuccess(zeta_account_id);
CoreAccountId alpha_account_id = AddAccountWithToken("alpha@example.com");
ReturnOAuthUrlFetchSuccess(alpha_account_id);
// The primary account will be first in the vector. Remaining accounts
// will be sorted by gaia ID.
std::vector<AccountIds> ids = account_tracker()->GetAccounts();
EXPECT_EQ(3ul, ids.size());
EXPECT_EQ(primary_account_id, ids[0].account_key);
EXPECT_EQ(AccountKeyToObfuscatedId(primary_account_id), ids[0].gaia);
EXPECT_EQ(alpha_account_id, ids[1].account_key);
EXPECT_EQ(AccountKeyToObfuscatedId(alpha_account_id), ids[1].gaia);
EXPECT_EQ(zeta_account_id, ids[2].account_key);
EXPECT_EQ(AccountKeyToObfuscatedId(zeta_account_id), ids[2].gaia);
EXPECT_EQ(beta_account.account_id, account[2].account_id);
EXPECT_EQ(beta_account.email, account[2].email);
EXPECT_EQ(beta_account.gaia, account[2].gaia);
}
TEST_F(AccountTrackerTest, GetAccountsReturnNothingWhenPrimarySignedOut) {
CoreAccountId primary_account_id = SetupPrimaryLogin();
CoreAccountInfo primary_account = SetupPrimaryLogin();
CoreAccountId zeta_account_id = AddAccountWithToken("zeta@example.com");
ReturnOAuthUrlFetchSuccess(zeta_account_id);
CoreAccountId alpha_account_id = AddAccountWithToken("alpha@example.com");
ReturnOAuthUrlFetchSuccess(alpha_account_id);
CoreAccountInfo zeta_account = AddAccountWithToken("zeta@example.com");
CoreAccountInfo alpha_account = AddAccountWithToken("alpha@example.com");
NotifyTokenRevoked(primary_account_id);
NotifyTokenRevoked(primary_account.account_id);
std::vector<AccountIds> ids = account_tracker()->GetAccounts();
EXPECT_EQ(0ul, ids.size());
std::vector<CoreAccountInfo> account = account_tracker()->GetAccounts();
EXPECT_EQ(0ul, account.size());
}
// This test exercises true login/logout, which are not possible on ChromeOS.
#if !defined(OS_CHROMEOS)
TEST_F(AccountTrackerTest, MultiLogoutRemovesAllAccounts) {
CoreAccountId primary_account_id = SetActiveAccount(kPrimaryAccountEmail);
NotifyTokenAvailable(primary_account_id);
ReturnOAuthUrlFetchSuccess(primary_account_id);
CoreAccountId account_id = AddAccountWithToken("user@example.com");
ReturnOAuthUrlFetchSuccess(account_id);
CoreAccountInfo primary_account = SetActiveAccount(kPrimaryAccountEmail);
NotifyTokenAvailable(primary_account.account_id);
CoreAccountInfo account = AddAccountWithToken("user@example.com");
observer()->Clear();
NotifyLogoutOfAllAccounts();
observer()->SortEventsByUser();
EXPECT_TRUE(
observer()->CheckEvents(TrackingEvent(SIGN_OUT, primary_account_id),
TrackingEvent(SIGN_OUT, account_id)));
EXPECT_TRUE(observer()->CheckEvents(TrackingEvent(SIGN_OUT, primary_account),
TrackingEvent(SIGN_OUT, account)));
}
#endif
......
......@@ -72,12 +72,12 @@ void GCMAccountTracker::Start() {
account_tracker_->AddObserver(this);
driver_->AddConnectionObserver(this);
std::vector<AccountIds> accounts = account_tracker_->GetAccounts();
for (std::vector<AccountIds>::const_iterator iter = accounts.begin();
std::vector<CoreAccountInfo> accounts = account_tracker_->GetAccounts();
for (std::vector<CoreAccountInfo>::const_iterator iter = accounts.begin();
iter != accounts.end(); ++iter) {
if (!iter->email.empty()) {
account_infos_.insert(std::make_pair(
iter->account_key, AccountInfo(iter->email, TOKEN_NEEDED)));
iter->account_id, AccountInfo(iter->email, TOKEN_NEEDED)));
}
}
......@@ -104,12 +104,12 @@ void GCMAccountTracker::ScheduleReportTokens() {
GetTimeToNextTokenReporting());
}
void GCMAccountTracker::OnAccountSignInChanged(const AccountIds& ids,
void GCMAccountTracker::OnAccountSignInChanged(const CoreAccountInfo& account,
bool is_signed_in) {
if (is_signed_in)
OnAccountSignedIn(ids);
OnAccountSignedIn(account);
else
OnAccountSignedOut(ids);
OnAccountSignedOut(account);
}
void GCMAccountTracker::OnAccessTokenFetchCompleteForAccount(
......@@ -163,11 +163,9 @@ void GCMAccountTracker::ReportTokens() {
return;
}
// Wait for AccountTracker to be done with fetching the user info, as
// well as all of the pending token requests from GCMAccountTracker to be done
// before you report the results.
if (!account_tracker_->IsAllUserInfoFetched() ||
!pending_token_requests_.empty()) {
// Wait for all of the pending token requests from GCMAccountTracker to be
// done before you report the results.
if (!pending_token_requests_.empty()) {
return;
}
......@@ -311,13 +309,13 @@ void GCMAccountTracker::GetToken(AccountInfos::iterator& account_iter) {
account_iter->second.state = GETTING_TOKEN;
}
void GCMAccountTracker::OnAccountSignedIn(const AccountIds& ids) {
DVLOG(1) << "Account signed in: " << ids.email;
auto iter = account_infos_.find(ids.account_key);
void GCMAccountTracker::OnAccountSignedIn(const CoreAccountInfo& account) {
DVLOG(1) << "Account signed in: " << account.email;
auto iter = account_infos_.find(account.account_id);
if (iter == account_infos_.end()) {
DCHECK(!ids.email.empty());
account_infos_.insert(
std::make_pair(ids.account_key, AccountInfo(ids.email, TOKEN_NEEDED)));
DCHECK(!account.email.empty());
account_infos_.insert(std::make_pair(
account.account_id, AccountInfo(account.email, TOKEN_NEEDED)));
} else if (iter->second.state == ACCOUNT_REMOVED) {
iter->second.state = TOKEN_NEEDED;
}
......@@ -325,9 +323,9 @@ void GCMAccountTracker::OnAccountSignedIn(const AccountIds& ids) {
GetAllNeededTokens();
}
void GCMAccountTracker::OnAccountSignedOut(const AccountIds& ids) {
DVLOG(1) << "Account signed out: " << ids.email;
auto iter = account_infos_.find(ids.account_key);
void GCMAccountTracker::OnAccountSignedOut(const CoreAccountInfo& account) {
DVLOG(1) << "Account signed out: " << account.email;
auto iter = account_infos_.find(account.account_id);
if (iter == account_infos_.end())
return;
......@@ -338,7 +336,7 @@ void GCMAccountTracker::OnAccountSignedOut(const AccountIds& ids) {
// re-added and a new access token request made, we do not break this class'
// invariant that there is at most one ongoing access token request per
// account.
pending_token_requests_.erase(ids.account_key);
pending_token_requests_.erase(account.account_id);
ReportTokens();
}
......
......@@ -96,12 +96,12 @@ class GCMAccountTracker : public AccountTracker::Observer,
private:
friend class GCMAccountTrackerTest;
// Maps account keys to account states. Keyed by account_ids as used by
// Maps account keys to account states. Keyed by account_id as used by
// IdentityManager.
typedef std::map<CoreAccountId, AccountInfo> AccountInfos;
// AccountTracker::Observer overrides.
void OnAccountSignInChanged(const AccountIds& ids,
void OnAccountSignInChanged(const CoreAccountInfo& account,
bool is_signed_in) override;
void OnAccessTokenFetchCompleteForAccount(
......@@ -136,8 +136,8 @@ class GCMAccountTracker : public AccountTracker::Observer,
void GetToken(AccountInfos::iterator& account_iter);
// Handling of actual sign in and sign out for accounts.
void OnAccountSignedIn(const AccountIds& ids);
void OnAccountSignedOut(const AccountIds& ids);
void OnAccountSignedIn(const CoreAccountInfo& account);
void OnAccountSignedOut(const CoreAccountInfo& account);
// Account tracker.
std::unique_ptr<AccountTracker> account_tracker_;
......
......@@ -25,27 +25,16 @@ namespace gcm {
namespace {
const char kOAuthURL[] = "https://www.googleapis.com/oauth2/v1/userinfo";
const char kEmail1[] = "account_1@me.com";
const char kEmail2[] = "account_2@me.com";
std::string AccountIdToObfuscatedId(const CoreAccountId& account_id) {
return "obfid-" + account_id.ToString();
}
std::string GetValidTokenInfoResponse(const CoreAccountId& account_id) {
return std::string("{ \"id\": \"") + AccountIdToObfuscatedId(account_id) +
"\" }";
}
std::string MakeAccessToken(const CoreAccountId& account_id) {
return "access_token-" + account_id.ToString();
}
GCMClient::AccountTokenInfo MakeAccountToken(const CoreAccountId& account_id) {
GCMClient::AccountTokenInfo MakeAccountToken(const CoreAccountInfo& account) {
GCMClient::AccountTokenInfo token_info;
token_info.account_id = account_id;
token_info.account_id = account.account_id;
// TODO(https://crbug.com/856170): This *should* be expected to be the email
// address for the given account, but there is a bug in AccountTracker that
......@@ -54,8 +43,8 @@ GCMClient::AccountTokenInfo MakeAccountToken(const CoreAccountId& account_id) {
// production code actually does :). If/when that bug gets fixed, this
// function should be changed to take in the email address as well as the
// account ID and populate this field with the email address.
token_info.email = account_id.ToString();
token_info.access_token = MakeAccessToken(account_id);
token_info.email = account.email;
token_info.access_token = MakeAccessToken(account.account_id);
return token_info;
}
......@@ -170,17 +159,9 @@ class GCMAccountTrackerTest : public testing::Test {
GCMAccountTrackerTest();
~GCMAccountTrackerTest() override;
// Helpers to pass fake info to the tracker. Tests should have either a pair
// of Start(Primary)/FinishAccountAddition or Add(Primary)Account per
// account. Don't mix. Any methods that return an std::string are returning
// the account ID of the newly-added account, which can then be passed into
// any methods that take in an account ID.
// Call to RemoveAccount is not mandatory.
CoreAccountId StartAccountAddition(const std::string& email);
CoreAccountId StartPrimaryAccountAddition(const std::string& email);
void FinishAccountAddition(const CoreAccountId& account_id);
CoreAccountId AddAccount(const std::string& email);
CoreAccountId AddPrimaryAccount(const std::string& email);
// Helpers to pass fake info to the tracker.
CoreAccountInfo AddAccount(const std::string& email);
CoreAccountInfo SetPrimaryAccount(const std::string& email);
void RemoveAccount(const CoreAccountId& account_id);
// Helpers for dealing with OAuth2 access token requests.
......@@ -212,10 +193,8 @@ class GCMAccountTrackerTest : public testing::Test {
};
GCMAccountTrackerTest::GCMAccountTrackerTest() {
std::unique_ptr<AccountTracker> gaia_account_tracker(new AccountTracker(
identity_test_env_.identity_manager(),
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&test_url_loader_factory_)));
std::unique_ptr<AccountTracker> gaia_account_tracker(
new AccountTracker(identity_test_env_.identity_manager()));
tracker_.reset(new GCMAccountTracker(std::move(gaia_account_tracker),
identity_test_env_.identity_manager(),
......@@ -227,12 +206,11 @@ GCMAccountTrackerTest::~GCMAccountTrackerTest() {
tracker_->Shutdown();
}
CoreAccountId GCMAccountTrackerTest::StartAccountAddition(
const std::string& email) {
return identity_test_env_.MakeAccountAvailable(email).account_id;
CoreAccountInfo GCMAccountTrackerTest::AddAccount(const std::string& email) {
return identity_test_env_.MakeAccountAvailable(email);
}
CoreAccountId GCMAccountTrackerTest::StartPrimaryAccountAddition(
CoreAccountInfo GCMAccountTrackerTest::SetPrimaryAccount(
const std::string& email) {
// NOTE: Setting of the primary account info must be done first on ChromeOS
// to ensure that AccountTracker and GCMAccountTracker respond as expected
......@@ -241,33 +219,7 @@ CoreAccountId GCMAccountTrackerTest::StartPrimaryAccountAddition(
// setting of the primary account is done afterward to check that the flow
// that ensues from the GoogleSigninSucceeded callback firing works as
// expected.
return identity_test_env_.MakePrimaryAccountAvailable(email).account_id;
}
void GCMAccountTrackerTest::FinishAccountAddition(
const CoreAccountId& account_id) {
IssueAccessToken(account_id);
EXPECT_TRUE(test_url_loader_factory()->IsPending(kOAuthURL));
test_url_loader_factory()->SimulateResponseForPendingRequest(
GURL(kOAuthURL), network::URLLoaderCompletionStatus(net::OK),
network::CreateURLResponseHead(net::HTTP_OK),
GetValidTokenInfoResponse(account_id));
GetValidTokenInfoResponse(account_id);
}
CoreAccountId GCMAccountTrackerTest::AddPrimaryAccount(
const std::string& email) {
CoreAccountId account_id = StartPrimaryAccountAddition(email);
FinishAccountAddition(account_id);
return account_id;
}
CoreAccountId GCMAccountTrackerTest::AddAccount(const std::string& email) {
CoreAccountId account_id = StartAccountAddition(email);
FinishAccountAddition(account_id);
return account_id;
return identity_test_env_.MakePrimaryAccountAvailable(email);
}
void GCMAccountTrackerTest::RemoveAccount(const CoreAccountId& account_id) {
......@@ -315,43 +267,35 @@ TEST_F(GCMAccountTrackerTest, NoAccounts) {
// with a specific scope. In this scenario, the underlying account tracker is
// still working when the CompleteCollectingTokens is called for the first time.
TEST_F(GCMAccountTrackerTest, SingleAccount) {
CoreAccountId account_id1 = StartPrimaryAccountAddition(kEmail1);
CoreAccountInfo account1 = SetPrimaryAccount(kEmail1);
tracker()->Start();
// We don't have any accounts to report, but given the inner account tracker
// is still working we don't make a call with empty accounts list.
EXPECT_FALSE(driver()->update_accounts_called());
// This concludes the work of inner account tracker.
FinishAccountAddition(account_id1);
IssueAccessToken(account_id1);
IssueAccessToken(account1.account_id);
EXPECT_TRUE(driver()->update_accounts_called());
std::vector<GCMClient::AccountTokenInfo> expected_accounts;
expected_accounts.push_back(MakeAccountToken(account_id1));
expected_accounts.push_back(MakeAccountToken(account1));
VerifyAccountTokens(expected_accounts, driver()->accounts());
}
TEST_F(GCMAccountTrackerTest, MultipleAccounts) {
CoreAccountId account_id1 = StartPrimaryAccountAddition(kEmail1);
CoreAccountId account_id2 = StartAccountAddition(kEmail2);
CoreAccountInfo account1 = SetPrimaryAccount(kEmail1);
CoreAccountInfo account2 = AddAccount(kEmail2);
tracker()->Start();
EXPECT_FALSE(driver()->update_accounts_called());
FinishAccountAddition(account_id1);
IssueAccessToken(account_id1);
IssueAccessToken(account1.account_id);
EXPECT_FALSE(driver()->update_accounts_called());
FinishAccountAddition(account_id2);
IssueAccessToken(account_id2);
IssueAccessToken(account2.account_id);
EXPECT_TRUE(driver()->update_accounts_called());
std::vector<GCMClient::AccountTokenInfo> expected_accounts;
expected_accounts.push_back(MakeAccountToken(account_id1));
expected_accounts.push_back(MakeAccountToken(account_id2));
expected_accounts.push_back(MakeAccountToken(account1));
expected_accounts.push_back(MakeAccountToken(account2));
VerifyAccountTokens(expected_accounts, driver()->accounts());
}
......@@ -359,88 +303,88 @@ TEST_F(GCMAccountTrackerTest, AccountAdded) {
tracker()->Start();
driver()->ResetResults();
CoreAccountId account_id1 = AddPrimaryAccount(kEmail1);
CoreAccountInfo account1 = SetPrimaryAccount(kEmail1);
EXPECT_FALSE(driver()->update_accounts_called());
IssueAccessToken(account_id1);
IssueAccessToken(account1.account_id);
EXPECT_TRUE(driver()->update_accounts_called());
std::vector<GCMClient::AccountTokenInfo> expected_accounts;
expected_accounts.push_back(MakeAccountToken(account_id1));
expected_accounts.push_back(MakeAccountToken(account1));
VerifyAccountTokens(expected_accounts, driver()->accounts());
}
TEST_F(GCMAccountTrackerTest, AccountRemoved) {
CoreAccountId account_id1 = AddPrimaryAccount(kEmail1);
CoreAccountId account_id2 = AddAccount(kEmail2);
CoreAccountInfo account1 = SetPrimaryAccount(kEmail1);
CoreAccountInfo account2 = AddAccount(kEmail2);
tracker()->Start();
IssueAccessToken(account_id1);
IssueAccessToken(account_id2);
IssueAccessToken(account1.account_id);
IssueAccessToken(account2.account_id);
EXPECT_TRUE(driver()->update_accounts_called());
driver()->ResetResults();
EXPECT_FALSE(driver()->update_accounts_called());
RemoveAccount(account_id2);
RemoveAccount(account2.account_id);
EXPECT_TRUE(driver()->update_accounts_called());
std::vector<GCMClient::AccountTokenInfo> expected_accounts;
expected_accounts.push_back(MakeAccountToken(account_id1));
expected_accounts.push_back(MakeAccountToken(account1));
VerifyAccountTokens(expected_accounts, driver()->accounts());
}
TEST_F(GCMAccountTrackerTest, GetTokenFailed) {
CoreAccountId account_id1 = AddPrimaryAccount(kEmail1);
CoreAccountId account_id2 = AddAccount(kEmail2);
CoreAccountInfo account1 = SetPrimaryAccount(kEmail1);
CoreAccountInfo account2 = AddAccount(kEmail2);
tracker()->Start();
IssueAccessToken(account_id1);
IssueAccessToken(account1.account_id);
EXPECT_FALSE(driver()->update_accounts_called());
IssueError(account_id2);
IssueError(account2.account_id);
// Failed token is not retried any more. Account marked as removed.
EXPECT_EQ(0UL, tracker()->get_pending_token_request_count());
EXPECT_TRUE(driver()->update_accounts_called());
std::vector<GCMClient::AccountTokenInfo> expected_accounts;
expected_accounts.push_back(MakeAccountToken(account_id1));
expected_accounts.push_back(MakeAccountToken(account1));
VerifyAccountTokens(expected_accounts, driver()->accounts());
}
TEST_F(GCMAccountTrackerTest, GetTokenFailedAccountRemoved) {
CoreAccountId account_id1 = AddPrimaryAccount(kEmail1);
CoreAccountId account_id2 = AddAccount(kEmail2);
CoreAccountInfo account1 = SetPrimaryAccount(kEmail1);
CoreAccountInfo account2 = AddAccount(kEmail2);
tracker()->Start();
IssueAccessToken(account_id1);
IssueAccessToken(account1.account_id);
driver()->ResetResults();
RemoveAccount(account_id2);
IssueError(account_id2);
RemoveAccount(account2.account_id);
IssueError(account2.account_id);
EXPECT_TRUE(driver()->update_accounts_called());
std::vector<GCMClient::AccountTokenInfo> expected_accounts;
expected_accounts.push_back(MakeAccountToken(account_id1));
expected_accounts.push_back(MakeAccountToken(account1));
VerifyAccountTokens(expected_accounts, driver()->accounts());
}
TEST_F(GCMAccountTrackerTest, AccountRemovedWhileRequestsPending) {
CoreAccountId account_id1 = AddPrimaryAccount(kEmail1);
CoreAccountId account_id2 = AddAccount(kEmail2);
CoreAccountInfo account1 = SetPrimaryAccount(kEmail1);
CoreAccountInfo account2 = AddAccount(kEmail2);
tracker()->Start();
IssueAccessToken(account_id1);
IssueAccessToken(account1.account_id);
EXPECT_FALSE(driver()->update_accounts_called());
RemoveAccount(account_id2);
IssueAccessToken(account_id2);
RemoveAccount(account2.account_id);
IssueAccessToken(account2.account_id);
EXPECT_TRUE(driver()->update_accounts_called());
std::vector<GCMClient::AccountTokenInfo> expected_accounts;
expected_accounts.push_back(MakeAccountToken(account_id1));
expected_accounts.push_back(MakeAccountToken(account1));
VerifyAccountTokens(expected_accounts, driver()->accounts());
}
......@@ -456,9 +400,8 @@ TEST_F(GCMAccountTrackerTest, TrackerObservesConnection) {
// Makes sure that token fetching happens only after connection is established.
TEST_F(GCMAccountTrackerTest, PostponeTokenFetchingUntilConnected) {
driver()->SetConnected(false);
CoreAccountId account_id1 = StartPrimaryAccountAddition(kEmail1);
CoreAccountInfo account1 = SetPrimaryAccount(kEmail1);
tracker()->Start();
FinishAccountAddition(account_id1);
EXPECT_EQ(0UL, tracker()->get_pending_token_request_count());
driver()->SetConnected(true);
......@@ -467,16 +410,14 @@ TEST_F(GCMAccountTrackerTest, PostponeTokenFetchingUntilConnected) {
}
TEST_F(GCMAccountTrackerTest, InvalidateExpiredTokens) {
CoreAccountId account_id1 = StartPrimaryAccountAddition(kEmail1);
CoreAccountId account_id2 = StartAccountAddition(kEmail2);
CoreAccountInfo account1 = SetPrimaryAccount(kEmail1);
CoreAccountInfo account2 = AddAccount(kEmail2);
tracker()->Start();
FinishAccountAddition(account_id1);
FinishAccountAddition(account_id2);
EXPECT_EQ(2UL, tracker()->get_pending_token_request_count());
IssueExpiredAccessToken(account_id1);
IssueAccessToken(account_id2);
IssueExpiredAccessToken(account1.account_id);
IssueAccessToken(account2.account_id);
// Because the first token is expired, we expect the sanitize to kick in and
// clean it up before the SetAccessToken is called. This also means a new
// token request will be issued
......@@ -491,17 +432,15 @@ TEST_F(GCMAccountTrackerTest, IsTokenFetchingRequired) {
tracker()->Start();
driver()->SetConnected(false);
EXPECT_FALSE(IsFetchingRequired());
CoreAccountId account_id1 = StartPrimaryAccountAddition(kEmail1);
FinishAccountAddition(account_id1);
CoreAccountInfo account1 = SetPrimaryAccount(kEmail1);
EXPECT_TRUE(IsFetchingRequired());
driver()->SetConnected(true);
EXPECT_FALSE(IsFetchingRequired()); // Indicates that fetching has started.
IssueAccessToken(account_id1);
IssueAccessToken(account1.account_id);
EXPECT_FALSE(IsFetchingRequired());
CoreAccountId account_id2 = StartAccountAddition(kEmail2);
FinishAccountAddition(account_id2);
CoreAccountInfo account2 = AddAccount(kEmail2);
EXPECT_FALSE(IsFetchingRequired()); // Indicates that fetching has started.
// Disconnect the driver again so that the access token request being
......@@ -511,7 +450,7 @@ TEST_F(GCMAccountTrackerTest, IsTokenFetchingRequired) {
// because GCMAccountTracker didn't detect that a new access token needs to be
// fetched).
driver()->SetConnected(false);
IssueExpiredAccessToken(account_id2);
IssueExpiredAccessToken(account2.account_id);
// Make sure that if the token was expired it is marked as being needed again.
EXPECT_TRUE(IsFetchingRequired());
......@@ -551,12 +490,12 @@ TEST_F(GCMAccountTrackerTest, IsTokenReportingRequired) {
driver()->SetLastTokenFetchTime(base::Time::Now());
EXPECT_FALSE(IsTokenReportingRequired());
CoreAccountId account_id1 = AddPrimaryAccount(kEmail1);
IssueAccessToken(account_id1);
CoreAccountInfo account1 = SetPrimaryAccount(kEmail1);
IssueAccessToken(account1.account_id);
driver()->ResetResults();
// Reporting was triggered, which means testing for required will give false,
// but we have the update call.
RemoveAccount(account_id1);
RemoveAccount(account1.account_id);
EXPECT_TRUE(driver()->update_accounts_called());
EXPECT_FALSE(IsTokenReportingRequired());
}
......
......@@ -112,7 +112,7 @@ void GCMProfileService::IdentityObserver::StartAccountTracker(
return;
std::unique_ptr<AccountTracker> gaia_account_tracker(
new AccountTracker(identity_manager_, std::move(url_loader_factory)));
new AccountTracker(identity_manager_));
gcm_account_tracker_.reset(new GCMAccountTracker(
std::move(gaia_account_tracker), identity_manager_, driver_));
......
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