123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539 |
- // Copyright 2014 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "components/gcm_driver/account_tracker.h"
- #include <algorithm>
- #include <memory>
- #include <vector>
- #include "base/strings/stringprintf.h"
- #include "base/test/task_environment.h"
- #include "build/build_config.h"
- #include "build/chromeos_buildflags.h"
- #include "components/signin/public/identity_manager/identity_test_environment.h"
- #include "testing/gtest/include/gtest/gtest.h"
- namespace {
- const char kPrimaryAccountEmail[] = "primary_account@example.com";
- enum TrackingEventType { SIGN_IN, SIGN_OUT };
- class TrackingEvent {
- public:
- TrackingEvent(TrackingEventType type,
- const CoreAccountId& account_id,
- const std::string& gaia_id)
- : type_(type), account_id_(account_id), gaia_id_(gaia_id) {}
- TrackingEvent(TrackingEventType type, const CoreAccountInfo& account_info)
- : type_(type),
- 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_ &&
- gaia_id_ == event.gaia_id_;
- }
- std::string ToString() const {
- const char* typestr = "INVALID";
- switch (type_) {
- case SIGN_IN:
- typestr = " IN";
- break;
- case SIGN_OUT:
- typestr = "OUT";
- break;
- }
- return base::StringPrintf("{ type: %s, account_id: %s, gaia: %s }", typestr,
- account_id_.ToString().c_str(), gaia_id_.c_str());
- }
- private:
- friend bool CompareByUser(TrackingEvent a, TrackingEvent b);
- TrackingEventType type_;
- CoreAccountId account_id_;
- std::string gaia_id_;
- };
- bool CompareByUser(TrackingEvent a, TrackingEvent b) {
- return a.account_id_ < b.account_id_;
- }
- std::string Str(const std::vector<TrackingEvent>& events) {
- std::string str = "[";
- bool needs_comma = false;
- for (auto it = events.begin(); it != events.end(); ++it) {
- if (needs_comma)
- str += ",\n ";
- needs_comma = true;
- str += it->ToString();
- }
- str += "]";
- return str;
- }
- } // namespace
- namespace gcm {
- class AccountTrackerObserver : public AccountTracker::Observer {
- public:
- AccountTrackerObserver() {}
- virtual ~AccountTrackerObserver() {}
- testing::AssertionResult CheckEvents();
- testing::AssertionResult CheckEvents(const TrackingEvent& e1);
- testing::AssertionResult CheckEvents(const TrackingEvent& e1,
- const TrackingEvent& e2);
- testing::AssertionResult CheckEvents(const TrackingEvent& e1,
- const TrackingEvent& e2,
- const TrackingEvent& e3);
- testing::AssertionResult CheckEvents(const TrackingEvent& e1,
- const TrackingEvent& e2,
- const TrackingEvent& e3,
- const TrackingEvent& e4);
- testing::AssertionResult CheckEvents(const TrackingEvent& e1,
- const TrackingEvent& e2,
- const TrackingEvent& e3,
- const TrackingEvent& e4,
- const TrackingEvent& e5);
- testing::AssertionResult CheckEvents(const TrackingEvent& e1,
- const TrackingEvent& e2,
- const TrackingEvent& e3,
- const TrackingEvent& e4,
- const TrackingEvent& e5,
- const TrackingEvent& e6);
- void Clear();
- void SortEventsByUser();
- // AccountTracker::Observer implementation
- void OnAccountSignInChanged(const CoreAccountInfo& account,
- bool is_signed_in) override;
- private:
- testing::AssertionResult CheckEvents(
- const std::vector<TrackingEvent>& events);
- std::vector<TrackingEvent> events_;
- };
- void AccountTrackerObserver::OnAccountSignInChanged(
- const CoreAccountInfo& account,
- bool is_signed_in) {
- events_.push_back(TrackingEvent(is_signed_in ? SIGN_IN : SIGN_OUT,
- account.account_id, account.gaia));
- }
- void AccountTrackerObserver::Clear() {
- events_.clear();
- }
- void AccountTrackerObserver::SortEventsByUser() {
- std::stable_sort(events_.begin(), events_.end(), CompareByUser);
- }
- testing::AssertionResult AccountTrackerObserver::CheckEvents() {
- std::vector<TrackingEvent> events;
- return CheckEvents(events);
- }
- testing::AssertionResult AccountTrackerObserver::CheckEvents(
- const TrackingEvent& e1) {
- std::vector<TrackingEvent> events;
- events.push_back(e1);
- return CheckEvents(events);
- }
- testing::AssertionResult AccountTrackerObserver::CheckEvents(
- const TrackingEvent& e1,
- const TrackingEvent& e2) {
- std::vector<TrackingEvent> events;
- events.push_back(e1);
- events.push_back(e2);
- return CheckEvents(events);
- }
- testing::AssertionResult AccountTrackerObserver::CheckEvents(
- const TrackingEvent& e1,
- const TrackingEvent& e2,
- const TrackingEvent& e3) {
- std::vector<TrackingEvent> events;
- events.push_back(e1);
- events.push_back(e2);
- events.push_back(e3);
- return CheckEvents(events);
- }
- testing::AssertionResult AccountTrackerObserver::CheckEvents(
- const TrackingEvent& e1,
- const TrackingEvent& e2,
- const TrackingEvent& e3,
- const TrackingEvent& e4) {
- std::vector<TrackingEvent> events;
- events.push_back(e1);
- events.push_back(e2);
- events.push_back(e3);
- events.push_back(e4);
- return CheckEvents(events);
- }
- testing::AssertionResult AccountTrackerObserver::CheckEvents(
- const TrackingEvent& e1,
- const TrackingEvent& e2,
- const TrackingEvent& e3,
- const TrackingEvent& e4,
- const TrackingEvent& e5) {
- std::vector<TrackingEvent> events;
- events.push_back(e1);
- events.push_back(e2);
- events.push_back(e3);
- events.push_back(e4);
- events.push_back(e5);
- return CheckEvents(events);
- }
- testing::AssertionResult AccountTrackerObserver::CheckEvents(
- const TrackingEvent& e1,
- const TrackingEvent& e2,
- const TrackingEvent& e3,
- const TrackingEvent& e4,
- const TrackingEvent& e5,
- const TrackingEvent& e6) {
- std::vector<TrackingEvent> events;
- events.push_back(e1);
- events.push_back(e2);
- events.push_back(e3);
- events.push_back(e4);
- events.push_back(e5);
- events.push_back(e6);
- return CheckEvents(events);
- }
- testing::AssertionResult AccountTrackerObserver::CheckEvents(
- const std::vector<TrackingEvent>& events) {
- std::string maybe_newline = (events.size() + events_.size()) > 2 ? "\n" : "";
- testing::AssertionResult result(
- (events_ == events)
- ? testing::AssertionSuccess()
- : (testing::AssertionFailure()
- << "Expected " << maybe_newline << Str(events) << ", "
- << maybe_newline << "Got " << maybe_newline << Str(events_)));
- events_.clear();
- return result;
- }
- class AccountTrackerTest : public testing::Test {
- public:
- AccountTrackerTest() {}
- ~AccountTrackerTest() override {}
- void SetUp() override {
- account_tracker_ =
- std::make_unique<AccountTracker>(identity_test_env_.identity_manager());
- account_tracker_->AddObserver(&observer_);
- }
- void TearDown() override {
- account_tracker_->RemoveObserver(&observer_);
- account_tracker_->Shutdown();
- }
- AccountTrackerObserver* observer() { return &observer_; }
- AccountTracker* account_tracker() { return account_tracker_.get(); }
- // Helpers to pass fake events to the tracker.
- // Sets the primary account info. Returns the account ID of the
- // newly-set account.
- // NOTE: On ChromeOS, the login callback is never fired in production (since
- // 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.
- CoreAccountInfo SetActiveAccount(const std::string& email) {
- return identity_test_env_.SetPrimaryAccount(email,
- signin::ConsentLevel::kSync);
- }
- // Helpers that go through a logout flow.
- // NOTE: On ChromeOS, the logout callback is never fired in production (since
- // the underlying GoogleSignedOut 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.
- #if !BUILDFLAG(IS_CHROMEOS_ASH)
- void NotifyLogoutOfAllAccounts() { identity_test_env_.ClearPrimaryAccount(); }
- #endif
- CoreAccountInfo AddAccountWithToken(const std::string& email) {
- return identity_test_env_.MakeAccountAvailable(email);
- }
- void NotifyTokenAvailable(const CoreAccountId& account_id) {
- identity_test_env_.SetRefreshTokenForAccount(account_id);
- }
- void NotifyTokenRevoked(const CoreAccountId& account_id) {
- identity_test_env_.RemoveRefreshTokenForAccount(account_id);
- }
- CoreAccountInfo SetupPrimaryLogin() {
- // Initial setup for tests that start with a signed in profile.
- CoreAccountInfo primary_account = SetActiveAccount(kPrimaryAccountEmail);
- NotifyTokenAvailable(primary_account.account_id);
- observer()->Clear();
- return primary_account;
- }
- private:
- // net:: stuff needs IO message loop.
- base::test::SingleThreadTaskEnvironment task_environment_{
- base::test::SingleThreadTaskEnvironment::MainThreadType::IO};
- signin::IdentityTestEnvironment identity_test_env_;
- std::unique_ptr<AccountTracker> account_tracker_;
- AccountTrackerObserver observer_;
- };
- // Primary tests just involve the Active account
- TEST_F(AccountTrackerTest, PrimaryNoEventsBeforeLogin) {
- CoreAccountInfo account = AddAccountWithToken("me@dummy.com");
- NotifyTokenRevoked(account.account_id);
- // Logout is not possible on ChromeOS.
- #if !BUILDFLAG(IS_CHROMEOS_ASH)
- NotifyLogoutOfAllAccounts();
- #endif
- EXPECT_TRUE(observer()->CheckEvents());
- }
- TEST_F(AccountTrackerTest, PrimaryLoginThenTokenAvailable) {
- CoreAccountInfo primary_account = SetActiveAccount(kPrimaryAccountEmail);
- NotifyTokenAvailable(primary_account.account_id);
- EXPECT_TRUE(observer()->CheckEvents(TrackingEvent(SIGN_IN, primary_account)));
- }
- TEST_F(AccountTrackerTest, PrimaryRevoke) {
- CoreAccountInfo primary_account = SetActiveAccount(kPrimaryAccountEmail);
- NotifyTokenAvailable(primary_account.account_id);
- observer()->Clear();
- NotifyTokenRevoked(primary_account.account_id);
- EXPECT_TRUE(
- observer()->CheckEvents(TrackingEvent(SIGN_OUT, primary_account)));
- }
- TEST_F(AccountTrackerTest, PrimaryRevokeThenTokenAvailable) {
- CoreAccountInfo primary_account = SetActiveAccount(kPrimaryAccountEmail);
- NotifyTokenAvailable(primary_account.account_id);
- NotifyTokenRevoked(primary_account.account_id);
- observer()->Clear();
- 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.
- #if !BUILDFLAG(IS_CHROMEOS_ASH)
- TEST_F(AccountTrackerTest, PrimaryTokenAvailableThenLogin) {
- AddAccountWithToken(kPrimaryAccountEmail);
- EXPECT_TRUE(observer()->CheckEvents());
- CoreAccountInfo primary_account = SetActiveAccount(kPrimaryAccountEmail);
- EXPECT_TRUE(observer()->CheckEvents(TrackingEvent(SIGN_IN, primary_account)));
- }
- TEST_F(AccountTrackerTest, PrimaryTokenAvailableAndRevokedThenLogin) {
- CoreAccountInfo primary_account = AddAccountWithToken(kPrimaryAccountEmail);
- EXPECT_TRUE(observer()->CheckEvents());
- NotifyTokenRevoked(primary_account.account_id);
- EXPECT_TRUE(observer()->CheckEvents());
- SetActiveAccount(kPrimaryAccountEmail);
- EXPECT_TRUE(observer()->CheckEvents());
- }
- TEST_F(AccountTrackerTest, PrimaryRevokeThenLogin) {
- CoreAccountInfo primary_account = SetActiveAccount(kPrimaryAccountEmail);
- NotifyTokenAvailable(primary_account.account_id);
- NotifyLogoutOfAllAccounts();
- observer()->Clear();
- SetActiveAccount(kPrimaryAccountEmail);
- EXPECT_TRUE(observer()->CheckEvents());
- }
- TEST_F(AccountTrackerTest, PrimaryLogoutThenRevoke) {
- CoreAccountInfo primary_account = SetActiveAccount(kPrimaryAccountEmail);
- NotifyTokenAvailable(primary_account.account_id);
- observer()->Clear();
- NotifyLogoutOfAllAccounts();
- EXPECT_TRUE(
- observer()->CheckEvents(TrackingEvent(SIGN_OUT, primary_account)));
- NotifyTokenRevoked(primary_account.account_id);
- EXPECT_TRUE(observer()->CheckEvents());
- }
- #endif
- // Non-primary accounts
- TEST_F(AccountTrackerTest, Available) {
- SetupPrimaryLogin();
- CoreAccountInfo account = AddAccountWithToken("user@example.com");
- EXPECT_TRUE(observer()->CheckEvents(TrackingEvent(SIGN_IN, account)));
- }
- TEST_F(AccountTrackerTest, AvailableRevokeAvailable) {
- SetupPrimaryLogin();
- CoreAccountInfo account = AddAccountWithToken("user@example.com");
- NotifyTokenRevoked(account.account_id);
- EXPECT_TRUE(observer()->CheckEvents(TrackingEvent(SIGN_IN, account),
- TrackingEvent(SIGN_OUT, account)));
- NotifyTokenAvailable(account.account_id);
- EXPECT_TRUE(observer()->CheckEvents(TrackingEvent(SIGN_IN, account)));
- }
- TEST_F(AccountTrackerTest, AvailableRevokeRevoke) {
- SetupPrimaryLogin();
- CoreAccountInfo account = AddAccountWithToken("user@example.com");
- NotifyTokenRevoked(account.account_id);
- EXPECT_TRUE(observer()->CheckEvents(TrackingEvent(SIGN_IN, account),
- TrackingEvent(SIGN_OUT, account)));
- NotifyTokenRevoked(account.account_id);
- EXPECT_TRUE(observer()->CheckEvents());
- }
- TEST_F(AccountTrackerTest, AvailableAvailable) {
- SetupPrimaryLogin();
- CoreAccountInfo account = AddAccountWithToken("user@example.com");
- EXPECT_TRUE(observer()->CheckEvents(TrackingEvent(SIGN_IN, account)));
- NotifyTokenAvailable(account.account_id);
- EXPECT_TRUE(observer()->CheckEvents());
- }
- TEST_F(AccountTrackerTest, TwoAccounts) {
- SetupPrimaryLogin();
- CoreAccountInfo alpha_account = AddAccountWithToken("alpha@example.com");
- EXPECT_TRUE(observer()->CheckEvents(TrackingEvent(SIGN_IN, alpha_account)));
- CoreAccountInfo beta_account = AddAccountWithToken("beta@example.com");
- EXPECT_TRUE(observer()->CheckEvents(TrackingEvent(SIGN_IN, beta_account)));
- NotifyTokenRevoked(alpha_account.account_id);
- EXPECT_TRUE(observer()->CheckEvents(TrackingEvent(SIGN_OUT, alpha_account)));
- NotifyTokenRevoked(beta_account.account_id);
- EXPECT_TRUE(observer()->CheckEvents(TrackingEvent(SIGN_OUT, beta_account)));
- }
- // Primary/non-primary interactions
- TEST_F(AccountTrackerTest, MultiNoEventsBeforeLogin) {
- 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 !BUILDFLAG(IS_CHROMEOS_ASH)
- NotifyLogoutOfAllAccounts();
- #endif
- EXPECT_TRUE(observer()->CheckEvents());
- }
- TEST_F(AccountTrackerTest, MultiRevokePrimaryDoesNotRemoveAllAccounts) {
- CoreAccountInfo primary_account = SetActiveAccount(kPrimaryAccountEmail);
- NotifyTokenAvailable(primary_account.account_id);
- CoreAccountInfo account = AddAccountWithToken("user@example.com");
- observer()->Clear();
- NotifyTokenRevoked(primary_account.account_id);
- observer()->SortEventsByUser();
- EXPECT_TRUE(
- observer()->CheckEvents(TrackingEvent(SIGN_OUT, primary_account)));
- }
- TEST_F(AccountTrackerTest, GetAccountsPrimary) {
- CoreAccountInfo primary_account = SetupPrimaryLogin();
- 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<CoreAccountInfo> accounts = account_tracker()->GetAccounts();
- EXPECT_EQ(0ul, accounts.size());
- }
- TEST_F(AccountTrackerTest, GetMultipleAccounts) {
- CoreAccountInfo primary_account = SetupPrimaryLogin();
- CoreAccountInfo alpha_account = AddAccountWithToken("alpha@example.com");
- CoreAccountInfo beta_account = AddAccountWithToken("beta@example.com");
- 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);
- 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);
- 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) {
- CoreAccountInfo primary_account = SetupPrimaryLogin();
- CoreAccountInfo zeta_account = AddAccountWithToken("zeta@example.com");
- CoreAccountInfo alpha_account = AddAccountWithToken("alpha@example.com");
- NotifyTokenRevoked(primary_account.account_id);
- 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 !BUILDFLAG(IS_CHROMEOS_ASH)
- TEST_F(AccountTrackerTest, MultiLogoutRemovesAllAccounts) {
- 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),
- TrackingEvent(SIGN_OUT, account)));
- }
- #endif
- } // namespace gcm
|