Home | History | Annotate | Download | only in gaia
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "google_apis/gaia/account_tracker.h"
      6 
      7 #include <algorithm>
      8 #include <vector>
      9 
     10 #include "base/message_loop/message_loop.h"
     11 #include "base/strings/stringprintf.h"
     12 #include "google_apis/gaia/fake_identity_provider.h"
     13 #include "google_apis/gaia/fake_oauth2_token_service.h"
     14 #include "google_apis/gaia/gaia_oauth_client.h"
     15 #include "net/http/http_status_code.h"
     16 #include "net/url_request/test_url_fetcher_factory.h"
     17 #include "net/url_request/url_fetcher_delegate.h"
     18 #include "net/url_request/url_request_test_util.h"
     19 #include "testing/gtest/include/gtest/gtest.h"
     20 
     21 namespace {
     22 
     23 const char kPrimaryAccountKey[] = "primary_account (at) example.com";
     24 
     25 enum TrackingEventType {
     26   ADDED,
     27   REMOVED,
     28   SIGN_IN,
     29   SIGN_OUT
     30 };
     31 
     32 std::string AccountKeyToObfuscatedId(const std::string email) {
     33   return "obfid-" + email;
     34 }
     35 
     36 class TrackingEvent {
     37  public:
     38   TrackingEvent(TrackingEventType type,
     39                 const std::string& account_key,
     40                 const std::string& gaia_id)
     41       : type_(type),
     42         account_key_(account_key),
     43         gaia_id_(gaia_id) {}
     44 
     45   TrackingEvent(TrackingEventType type,
     46                 const std::string& account_key)
     47       : type_(type),
     48         account_key_(account_key),
     49         gaia_id_(AccountKeyToObfuscatedId(account_key)) {}
     50 
     51   bool operator==(const TrackingEvent& event) const {
     52     return type_ == event.type_ && account_key_ == event.account_key_ &&
     53         gaia_id_ == event.gaia_id_;
     54   }
     55 
     56   std::string ToString() const {
     57     const char * typestr = "INVALID";
     58     switch (type_) {
     59       case ADDED:
     60         typestr = "ADD";
     61         break;
     62       case REMOVED:
     63         typestr = "REM";
     64         break;
     65       case SIGN_IN:
     66         typestr = " IN";
     67         break;
     68       case SIGN_OUT:
     69         typestr = "OUT";
     70         break;
     71     }
     72     return base::StringPrintf("{ type: %s, email: %s, gaia: %s }",
     73                               typestr,
     74                               account_key_.c_str(),
     75                               gaia_id_.c_str());
     76   }
     77 
     78  private:
     79   friend bool CompareByUser(TrackingEvent a, TrackingEvent b);
     80 
     81   TrackingEventType type_;
     82   std::string account_key_;
     83   std::string gaia_id_;
     84 };
     85 
     86 bool CompareByUser(TrackingEvent a, TrackingEvent b) {
     87   return a.account_key_ < b.account_key_;
     88 }
     89 
     90 std::string Str(const std::vector<TrackingEvent>& events) {
     91   std::string str = "[";
     92   bool needs_comma = false;
     93   for (std::vector<TrackingEvent>::const_iterator it =
     94        events.begin(); it != events.end(); ++it) {
     95     if (needs_comma)
     96       str += ",\n ";
     97     needs_comma = true;
     98     str += it->ToString();
     99   }
    100   str += "]";
    101   return str;
    102 }
    103 
    104 }  // namespace
    105 
    106 namespace gaia {
    107 
    108 class AccountTrackerObserver : public AccountTracker::Observer {
    109  public:
    110   AccountTrackerObserver() {}
    111   virtual ~AccountTrackerObserver() {}
    112 
    113   testing::AssertionResult CheckEvents();
    114   testing::AssertionResult CheckEvents(const TrackingEvent& e1);
    115   testing::AssertionResult CheckEvents(const TrackingEvent& e1,
    116                                        const TrackingEvent& e2);
    117   testing::AssertionResult CheckEvents(const TrackingEvent& e1,
    118                                        const TrackingEvent& e2,
    119                                        const TrackingEvent& e3);
    120   testing::AssertionResult CheckEvents(const TrackingEvent& e1,
    121                                        const TrackingEvent& e2,
    122                                        const TrackingEvent& e3,
    123                                        const TrackingEvent& e4);
    124   testing::AssertionResult CheckEvents(const TrackingEvent& e1,
    125                                        const TrackingEvent& e2,
    126                                        const TrackingEvent& e3,
    127                                        const TrackingEvent& e4,
    128                                        const TrackingEvent& e5);
    129   testing::AssertionResult CheckEvents(const TrackingEvent& e1,
    130                                        const TrackingEvent& e2,
    131                                        const TrackingEvent& e3,
    132                                        const TrackingEvent& e4,
    133                                        const TrackingEvent& e5,
    134                                        const TrackingEvent& e6);
    135   void Clear();
    136   void SortEventsByUser();
    137 
    138   // AccountTracker::Observer implementation
    139   virtual void OnAccountAdded(const AccountIds& ids) OVERRIDE;
    140   virtual void OnAccountRemoved(const AccountIds& ids) OVERRIDE;
    141   virtual void OnAccountSignInChanged(const AccountIds& ids, bool is_signed_in)
    142       OVERRIDE;
    143 
    144  private:
    145   testing::AssertionResult CheckEvents(
    146       const std::vector<TrackingEvent>& events);
    147 
    148   std::vector<TrackingEvent> events_;
    149 };
    150 
    151 void AccountTrackerObserver::OnAccountAdded(const AccountIds& ids) {
    152   events_.push_back(TrackingEvent(ADDED, ids.email, ids.gaia));
    153 }
    154 
    155 void AccountTrackerObserver::OnAccountRemoved(const AccountIds& ids) {
    156   events_.push_back(TrackingEvent(REMOVED, ids.email, ids.gaia));
    157 }
    158 
    159 void AccountTrackerObserver::OnAccountSignInChanged(const AccountIds& ids,
    160                                                     bool is_signed_in) {
    161   events_.push_back(
    162       TrackingEvent(is_signed_in ? SIGN_IN : SIGN_OUT, ids.email, ids.gaia));
    163 }
    164 
    165 void AccountTrackerObserver::Clear() {
    166   events_.clear();
    167 }
    168 
    169 void AccountTrackerObserver::SortEventsByUser() {
    170   std::stable_sort(events_.begin(), events_.end(), CompareByUser);
    171 }
    172 
    173 testing::AssertionResult AccountTrackerObserver::CheckEvents() {
    174   std::vector<TrackingEvent> events;
    175   return CheckEvents(events);
    176 }
    177 
    178 testing::AssertionResult AccountTrackerObserver::CheckEvents(
    179     const TrackingEvent& e1) {
    180   std::vector<TrackingEvent> events;
    181   events.push_back(e1);
    182   return CheckEvents(events);
    183 }
    184 
    185 testing::AssertionResult AccountTrackerObserver::CheckEvents(
    186     const TrackingEvent& e1,
    187     const TrackingEvent& e2) {
    188   std::vector<TrackingEvent> events;
    189   events.push_back(e1);
    190   events.push_back(e2);
    191   return CheckEvents(events);
    192 }
    193 
    194 testing::AssertionResult AccountTrackerObserver::CheckEvents(
    195     const TrackingEvent& e1,
    196     const TrackingEvent& e2,
    197     const TrackingEvent& e3) {
    198   std::vector<TrackingEvent> events;
    199   events.push_back(e1);
    200   events.push_back(e2);
    201   events.push_back(e3);
    202   return CheckEvents(events);
    203 }
    204 
    205 testing::AssertionResult AccountTrackerObserver::CheckEvents(
    206     const TrackingEvent& e1,
    207     const TrackingEvent& e2,
    208     const TrackingEvent& e3,
    209     const TrackingEvent& e4) {
    210   std::vector<TrackingEvent> events;
    211   events.push_back(e1);
    212   events.push_back(e2);
    213   events.push_back(e3);
    214   events.push_back(e4);
    215   return CheckEvents(events);
    216 }
    217 
    218 testing::AssertionResult AccountTrackerObserver::CheckEvents(
    219     const TrackingEvent& e1,
    220     const TrackingEvent& e2,
    221     const TrackingEvent& e3,
    222     const TrackingEvent& e4,
    223     const TrackingEvent& e5) {
    224   std::vector<TrackingEvent> events;
    225   events.push_back(e1);
    226   events.push_back(e2);
    227   events.push_back(e3);
    228   events.push_back(e4);
    229   events.push_back(e5);
    230   return CheckEvents(events);
    231 }
    232 
    233 testing::AssertionResult AccountTrackerObserver::CheckEvents(
    234     const TrackingEvent& e1,
    235     const TrackingEvent& e2,
    236     const TrackingEvent& e3,
    237     const TrackingEvent& e4,
    238     const TrackingEvent& e5,
    239     const TrackingEvent& e6) {
    240   std::vector<TrackingEvent> events;
    241   events.push_back(e1);
    242   events.push_back(e2);
    243   events.push_back(e3);
    244   events.push_back(e4);
    245   events.push_back(e5);
    246   events.push_back(e6);
    247   return CheckEvents(events);
    248 }
    249 
    250 testing::AssertionResult AccountTrackerObserver::CheckEvents(
    251     const std::vector<TrackingEvent>& events) {
    252   std::string maybe_newline = (events.size() + events_.size()) > 2 ? "\n" : "";
    253   testing::AssertionResult result(
    254       (events_ == events)
    255           ? testing::AssertionSuccess()
    256           : (testing::AssertionFailure()
    257              << "Expected " << maybe_newline << Str(events) << ", "
    258              << maybe_newline << "Got " << maybe_newline << Str(events_)));
    259   events_.clear();
    260   return result;
    261 }
    262 
    263 class IdentityAccountTrackerTest : public testing::Test {
    264  public:
    265   IdentityAccountTrackerTest() {}
    266 
    267   virtual ~IdentityAccountTrackerTest() {}
    268 
    269   virtual void SetUp() OVERRIDE {
    270 
    271     fake_oauth2_token_service_.reset(new FakeOAuth2TokenService());
    272 
    273     fake_identity_provider_.reset(
    274         new FakeIdentityProvider(fake_oauth2_token_service_.get()));
    275 
    276     account_tracker_.reset(
    277         new AccountTracker(fake_identity_provider_.get(),
    278                            new net::TestURLRequestContextGetter(
    279                                message_loop_.message_loop_proxy())));
    280     account_tracker_->AddObserver(&observer_);
    281   }
    282 
    283   virtual void TearDown() OVERRIDE {
    284     account_tracker_->RemoveObserver(&observer_);
    285     account_tracker_->Shutdown();
    286   }
    287 
    288   AccountTrackerObserver* observer() {
    289     return &observer_;
    290   }
    291 
    292   AccountTracker* account_tracker() {
    293     return account_tracker_.get();
    294   }
    295 
    296   // Helpers to pass fake events to the tracker.
    297 
    298   void NotifyLogin(const std::string account_key) {
    299     identity_provider()->LogIn(account_key);
    300   }
    301 
    302   void NotifyLogout() { identity_provider()->LogOut(); }
    303 
    304   void NotifyTokenAvailable(const std::string& username) {
    305     fake_oauth2_token_service_->AddAccount(username);
    306   }
    307 
    308   void NotifyTokenRevoked(const std::string& username) {
    309     fake_oauth2_token_service_->RemoveAccount(username);
    310   }
    311 
    312   // Helpers to fake access token and user info fetching
    313   void IssueAccessToken(const std::string& username) {
    314     fake_oauth2_token_service_->IssueAllTokensForAccount(
    315         username, "access_token-" + username, base::Time::Max());
    316   }
    317 
    318   std::string GetValidTokenInfoResponse(const std::string account_key) {
    319     return std::string("{ \"id\": \"") + AccountKeyToObfuscatedId(account_key) +
    320            "\" }";
    321   }
    322 
    323   void ReturnOAuthUrlFetchResults(int fetcher_id,
    324                                   net::HttpStatusCode response_code,
    325                                   const std::string& response_string);
    326 
    327   void ReturnOAuthUrlFetchSuccess(const std::string& account_key);
    328   void ReturnOAuthUrlFetchFailure(const std::string& account_key);
    329 
    330   void SetupPrimaryLogin() {
    331     // Initial setup for tests that start with a signed in profile.
    332     NotifyLogin(kPrimaryAccountKey);
    333     NotifyTokenAvailable(kPrimaryAccountKey);
    334     ReturnOAuthUrlFetchSuccess(kPrimaryAccountKey);
    335     observer()->Clear();
    336   }
    337 
    338   std::string active_account_id() {
    339     return identity_provider()->GetActiveAccountId();
    340   }
    341 
    342  private:
    343   FakeIdentityProvider* identity_provider() {
    344     return static_cast<FakeIdentityProvider*>(
    345         account_tracker_->identity_provider());
    346   }
    347 
    348   base::MessageLoopForIO message_loop_;  // net:: stuff needs IO message loop.
    349   net::TestURLFetcherFactory test_fetcher_factory_;
    350   scoped_ptr<FakeOAuth2TokenService> fake_oauth2_token_service_;
    351   scoped_ptr<FakeIdentityProvider> fake_identity_provider_;
    352 
    353   scoped_ptr<AccountTracker> account_tracker_;
    354   AccountTrackerObserver observer_;
    355 };
    356 
    357 void IdentityAccountTrackerTest::ReturnOAuthUrlFetchResults(
    358     int fetcher_id,
    359     net::HttpStatusCode response_code,
    360     const std::string&  response_string) {
    361 
    362   net::TestURLFetcher* fetcher =
    363       test_fetcher_factory_.GetFetcherByID(fetcher_id);
    364   ASSERT_TRUE(fetcher);
    365   fetcher->set_response_code(response_code);
    366   fetcher->SetResponseString(response_string);
    367   fetcher->delegate()->OnURLFetchComplete(fetcher);
    368 }
    369 
    370 void IdentityAccountTrackerTest::ReturnOAuthUrlFetchSuccess(
    371     const std::string& account_key) {
    372   IssueAccessToken(account_key);
    373   ReturnOAuthUrlFetchResults(gaia::GaiaOAuthClient::kUrlFetcherId,
    374                              net::HTTP_OK,
    375                              GetValidTokenInfoResponse(account_key));
    376 }
    377 
    378 void IdentityAccountTrackerTest::ReturnOAuthUrlFetchFailure(
    379     const std::string& account_key) {
    380   IssueAccessToken(account_key);
    381   ReturnOAuthUrlFetchResults(
    382       gaia::GaiaOAuthClient::kUrlFetcherId, net::HTTP_BAD_REQUEST, "");
    383 }
    384 
    385 // Primary tests just involve the Active account
    386 
    387 TEST_F(IdentityAccountTrackerTest, PrimaryNoEventsBeforeLogin) {
    388   NotifyTokenAvailable(kPrimaryAccountKey);
    389   NotifyTokenRevoked(kPrimaryAccountKey);
    390   NotifyLogout();
    391   EXPECT_TRUE(observer()->CheckEvents());
    392 }
    393 
    394 TEST_F(IdentityAccountTrackerTest, PrimaryLoginThenTokenAvailable) {
    395   NotifyLogin(kPrimaryAccountKey);
    396   NotifyTokenAvailable(kPrimaryAccountKey);
    397   EXPECT_TRUE(observer()->CheckEvents());
    398 
    399   ReturnOAuthUrlFetchSuccess(kPrimaryAccountKey);
    400   EXPECT_TRUE(
    401       observer()->CheckEvents(TrackingEvent(ADDED, kPrimaryAccountKey),
    402                               TrackingEvent(SIGN_IN, kPrimaryAccountKey)));
    403 }
    404 
    405 TEST_F(IdentityAccountTrackerTest, PrimaryTokenAvailableThenLogin) {
    406   NotifyTokenAvailable(kPrimaryAccountKey);
    407   EXPECT_TRUE(observer()->CheckEvents());
    408 
    409   NotifyLogin(kPrimaryAccountKey);
    410   ReturnOAuthUrlFetchSuccess(kPrimaryAccountKey);
    411   EXPECT_TRUE(
    412       observer()->CheckEvents(TrackingEvent(ADDED, kPrimaryAccountKey),
    413                               TrackingEvent(SIGN_IN, kPrimaryAccountKey)));
    414 }
    415 
    416 TEST_F(IdentityAccountTrackerTest, PrimaryTokenAvailableAndRevokedThenLogin) {
    417   NotifyTokenAvailable(kPrimaryAccountKey);
    418   EXPECT_TRUE(observer()->CheckEvents());
    419 
    420   NotifyLogin(kPrimaryAccountKey);
    421   ReturnOAuthUrlFetchSuccess(kPrimaryAccountKey);
    422   EXPECT_TRUE(
    423       observer()->CheckEvents(TrackingEvent(ADDED, kPrimaryAccountKey),
    424                               TrackingEvent(SIGN_IN, kPrimaryAccountKey)));
    425 }
    426 
    427 TEST_F(IdentityAccountTrackerTest, PrimaryRevokeThenLogout) {
    428   NotifyLogin(kPrimaryAccountKey);
    429   NotifyTokenAvailable(kPrimaryAccountKey);
    430   ReturnOAuthUrlFetchSuccess(kPrimaryAccountKey);
    431   observer()->Clear();
    432 
    433   NotifyTokenRevoked(kPrimaryAccountKey);
    434   EXPECT_TRUE(
    435       observer()->CheckEvents(TrackingEvent(SIGN_OUT, kPrimaryAccountKey)));
    436 
    437   NotifyLogout();
    438   EXPECT_TRUE(
    439       observer()->CheckEvents(TrackingEvent(REMOVED, kPrimaryAccountKey)));
    440 }
    441 
    442 TEST_F(IdentityAccountTrackerTest, PrimaryRevokeThenLogin) {
    443   NotifyLogin(kPrimaryAccountKey);
    444   NotifyTokenAvailable(kPrimaryAccountKey);
    445   ReturnOAuthUrlFetchSuccess(kPrimaryAccountKey);
    446   NotifyTokenRevoked(kPrimaryAccountKey);
    447   observer()->Clear();
    448 
    449   NotifyLogin(kPrimaryAccountKey);
    450   EXPECT_TRUE(observer()->CheckEvents());
    451 }
    452 
    453 TEST_F(IdentityAccountTrackerTest, PrimaryRevokeThenTokenAvailable) {
    454   NotifyLogin(kPrimaryAccountKey);
    455   NotifyTokenAvailable(kPrimaryAccountKey);
    456   ReturnOAuthUrlFetchSuccess(kPrimaryAccountKey);
    457   NotifyTokenRevoked(kPrimaryAccountKey);
    458   observer()->Clear();
    459 
    460   NotifyTokenAvailable(kPrimaryAccountKey);
    461   EXPECT_TRUE(
    462       observer()->CheckEvents(TrackingEvent(SIGN_IN, kPrimaryAccountKey)));
    463 }
    464 
    465 TEST_F(IdentityAccountTrackerTest, PrimaryLogoutThenRevoke) {
    466   NotifyLogin(kPrimaryAccountKey);
    467   NotifyTokenAvailable(kPrimaryAccountKey);
    468   ReturnOAuthUrlFetchSuccess(kPrimaryAccountKey);
    469   observer()->Clear();
    470 
    471   NotifyLogout();
    472   EXPECT_TRUE(
    473       observer()->CheckEvents(TrackingEvent(SIGN_OUT, kPrimaryAccountKey),
    474                               TrackingEvent(REMOVED, kPrimaryAccountKey)));
    475 
    476   NotifyTokenRevoked(kPrimaryAccountKey);
    477   EXPECT_TRUE(observer()->CheckEvents());
    478 }
    479 
    480 TEST_F(IdentityAccountTrackerTest, PrimaryLogoutFetchCancelAvailable) {
    481   NotifyLogin(kPrimaryAccountKey);
    482   NotifyTokenAvailable(kPrimaryAccountKey);
    483   // TokenAvailable kicks off a fetch. Logout without satisfying it.
    484   NotifyLogout();
    485   EXPECT_TRUE(observer()->CheckEvents());
    486 
    487   NotifyLogin(kPrimaryAccountKey);
    488   NotifyTokenAvailable(kPrimaryAccountKey);
    489   ReturnOAuthUrlFetchSuccess(kPrimaryAccountKey);
    490   EXPECT_TRUE(observer()->CheckEvents(
    491       TrackingEvent(ADDED, kPrimaryAccountKey),
    492       TrackingEvent(SIGN_IN, kPrimaryAccountKey)));
    493 }
    494 
    495 // Non-primary accounts
    496 
    497 TEST_F(IdentityAccountTrackerTest, Available) {
    498   SetupPrimaryLogin();
    499 
    500   NotifyTokenAvailable("user (at) example.com");
    501   EXPECT_TRUE(observer()->CheckEvents());
    502 
    503   ReturnOAuthUrlFetchSuccess("user (at) example.com");
    504   EXPECT_TRUE(observer()->CheckEvents(
    505       TrackingEvent(ADDED, "user (at) example.com"),
    506       TrackingEvent(SIGN_IN, "user (at) example.com")));
    507 }
    508 
    509 TEST_F(IdentityAccountTrackerTest, Revoke) {
    510   SetupPrimaryLogin();
    511 
    512   account_tracker()->OnRefreshTokenRevoked("user (at) example.com");
    513   EXPECT_TRUE(observer()->CheckEvents());
    514 }
    515 
    516 TEST_F(IdentityAccountTrackerTest, AvailableRevokeAvailable) {
    517   SetupPrimaryLogin();
    518 
    519   NotifyTokenAvailable("user (at) example.com");
    520   ReturnOAuthUrlFetchSuccess("user (at) example.com");
    521   NotifyTokenRevoked("user (at) example.com");
    522   EXPECT_TRUE(observer()->CheckEvents(
    523       TrackingEvent(ADDED, "user (at) example.com"),
    524       TrackingEvent(SIGN_IN, "user (at) example.com"),
    525       TrackingEvent(SIGN_OUT, "user (at) example.com")));
    526 
    527   NotifyTokenAvailable("user (at) example.com");
    528   EXPECT_TRUE(observer()->CheckEvents(
    529       TrackingEvent(SIGN_IN, "user (at) example.com")));
    530 }
    531 
    532 TEST_F(IdentityAccountTrackerTest, AvailableRevokeAvailableWithPendingFetch) {
    533   SetupPrimaryLogin();
    534 
    535   NotifyTokenAvailable("user (at) example.com");
    536   NotifyTokenRevoked("user (at) example.com");
    537   EXPECT_TRUE(observer()->CheckEvents());
    538 
    539   NotifyTokenAvailable("user (at) example.com");
    540   ReturnOAuthUrlFetchSuccess("user (at) example.com");
    541   EXPECT_TRUE(observer()->CheckEvents(
    542       TrackingEvent(ADDED, "user (at) example.com"),
    543       TrackingEvent(SIGN_IN, "user (at) example.com")));
    544 }
    545 
    546 TEST_F(IdentityAccountTrackerTest, AvailableRevokeRevoke) {
    547   SetupPrimaryLogin();
    548 
    549   NotifyTokenAvailable("user (at) example.com");
    550   ReturnOAuthUrlFetchSuccess("user (at) example.com");
    551   NotifyTokenRevoked("user (at) example.com");
    552   EXPECT_TRUE(observer()->CheckEvents(
    553       TrackingEvent(ADDED, "user (at) example.com"),
    554       TrackingEvent(SIGN_IN, "user (at) example.com"),
    555       TrackingEvent(SIGN_OUT, "user (at) example.com")));
    556 
    557   NotifyTokenRevoked("user (at) example.com");
    558   EXPECT_TRUE(observer()->CheckEvents());
    559 }
    560 
    561 TEST_F(IdentityAccountTrackerTest, AvailableAvailable) {
    562   SetupPrimaryLogin();
    563 
    564   NotifyTokenAvailable("user (at) example.com");
    565   ReturnOAuthUrlFetchSuccess("user (at) example.com");
    566   EXPECT_TRUE(observer()->CheckEvents(
    567       TrackingEvent(ADDED, "user (at) example.com"),
    568       TrackingEvent(SIGN_IN, "user (at) example.com")));
    569 
    570   NotifyTokenAvailable("user (at) example.com");
    571   EXPECT_TRUE(observer()->CheckEvents());
    572 }
    573 
    574 TEST_F(IdentityAccountTrackerTest, TwoAccounts) {
    575   SetupPrimaryLogin();
    576 
    577   NotifyTokenAvailable("alpha (at) example.com");
    578   ReturnOAuthUrlFetchSuccess("alpha (at) example.com");
    579   EXPECT_TRUE(observer()->CheckEvents(
    580       TrackingEvent(ADDED, "alpha (at) example.com"),
    581       TrackingEvent(SIGN_IN, "alpha (at) example.com")));
    582 
    583   NotifyTokenAvailable("beta (at) example.com");
    584   ReturnOAuthUrlFetchSuccess("beta (at) example.com");
    585   EXPECT_TRUE(observer()->CheckEvents(
    586       TrackingEvent(ADDED, "beta (at) example.com"),
    587       TrackingEvent(SIGN_IN, "beta (at) example.com")));
    588 
    589   NotifyTokenRevoked("alpha (at) example.com");
    590   EXPECT_TRUE(
    591       observer()->CheckEvents(TrackingEvent(SIGN_OUT, "alpha (at) example.com")));
    592 
    593   NotifyTokenRevoked("beta (at) example.com");
    594   EXPECT_TRUE(observer()->CheckEvents(
    595       TrackingEvent(SIGN_OUT, "beta (at) example.com")));
    596 }
    597 
    598 TEST_F(IdentityAccountTrackerTest, AvailableTokenFetchFailAvailable) {
    599   SetupPrimaryLogin();
    600 
    601   NotifyTokenAvailable("user (at) example.com");
    602   ReturnOAuthUrlFetchFailure("user (at) example.com");
    603   EXPECT_TRUE(observer()->CheckEvents());
    604 
    605   NotifyTokenAvailable("user (at) example.com");
    606   ReturnOAuthUrlFetchSuccess("user (at) example.com");
    607   EXPECT_TRUE(observer()->CheckEvents(
    608       TrackingEvent(ADDED, "user (at) example.com"),
    609       TrackingEvent(SIGN_IN, "user (at) example.com")));
    610 }
    611 
    612 TEST_F(IdentityAccountTrackerTest, MultiSignOutSignIn) {
    613   SetupPrimaryLogin();
    614 
    615   NotifyTokenAvailable("alpha (at) example.com");
    616   ReturnOAuthUrlFetchSuccess("alpha (at) example.com");
    617   NotifyTokenAvailable("beta (at) example.com");
    618   ReturnOAuthUrlFetchSuccess("beta (at) example.com");
    619 
    620   observer()->SortEventsByUser();
    621   EXPECT_TRUE(observer()->CheckEvents(
    622       TrackingEvent(ADDED, "alpha (at) example.com"),
    623       TrackingEvent(SIGN_IN, "alpha (at) example.com"),
    624       TrackingEvent(ADDED, "beta (at) example.com"),
    625       TrackingEvent(SIGN_IN, "beta (at) example.com")));
    626 
    627   NotifyLogout();
    628   observer()->SortEventsByUser();
    629   EXPECT_TRUE(observer()->CheckEvents(
    630       TrackingEvent(SIGN_OUT, "alpha (at) example.com"),
    631       TrackingEvent(REMOVED, "alpha (at) example.com"),
    632       TrackingEvent(SIGN_OUT, "beta (at) example.com"),
    633       TrackingEvent(REMOVED, "beta (at) example.com"),
    634       TrackingEvent(SIGN_OUT, kPrimaryAccountKey),
    635       TrackingEvent(REMOVED, kPrimaryAccountKey)));
    636 
    637   // No events fire at all while profile is signed out.
    638   NotifyTokenRevoked("alpha (at) example.com");
    639   NotifyTokenAvailable("gamma (at) example.com");
    640   EXPECT_TRUE(observer()->CheckEvents());
    641 
    642   // Signing the profile in again will resume tracking all accounts.
    643   NotifyLogin(kPrimaryAccountKey);
    644   NotifyTokenAvailable(kPrimaryAccountKey);
    645   ReturnOAuthUrlFetchSuccess("beta (at) example.com");
    646   ReturnOAuthUrlFetchSuccess("gamma (at) example.com");
    647   ReturnOAuthUrlFetchSuccess(kPrimaryAccountKey);
    648   observer()->SortEventsByUser();
    649   EXPECT_TRUE(observer()->CheckEvents(
    650       TrackingEvent(ADDED, "beta (at) example.com"),
    651       TrackingEvent(SIGN_IN, "beta (at) example.com"),
    652       TrackingEvent(ADDED, "gamma (at) example.com"),
    653       TrackingEvent(SIGN_IN, "gamma (at) example.com"),
    654       TrackingEvent(ADDED, kPrimaryAccountKey),
    655       TrackingEvent(SIGN_IN, kPrimaryAccountKey)));
    656 
    657   // Revoking the primary token does not affect other accounts.
    658   NotifyTokenRevoked(kPrimaryAccountKey);
    659   EXPECT_TRUE(observer()->CheckEvents(
    660       TrackingEvent(SIGN_OUT, kPrimaryAccountKey)));
    661 
    662   NotifyTokenAvailable(kPrimaryAccountKey);
    663   EXPECT_TRUE(observer()->CheckEvents(
    664       TrackingEvent(SIGN_IN, kPrimaryAccountKey)));
    665 }
    666 
    667 // Primary/non-primary interactions
    668 
    669 TEST_F(IdentityAccountTrackerTest, MultiNoEventsBeforeLogin) {
    670   NotifyTokenAvailable(kPrimaryAccountKey);
    671   NotifyTokenAvailable("user (at) example.com");
    672   NotifyTokenRevoked("user (at) example.com");
    673   NotifyTokenRevoked(kPrimaryAccountKey);
    674   NotifyLogout();
    675   EXPECT_TRUE(observer()->CheckEvents());
    676 }
    677 
    678 TEST_F(IdentityAccountTrackerTest, MultiLogoutRemovesAllAccounts) {
    679   NotifyLogin(kPrimaryAccountKey);
    680   NotifyTokenAvailable(kPrimaryAccountKey);
    681   ReturnOAuthUrlFetchSuccess(kPrimaryAccountKey);
    682   NotifyTokenAvailable("user (at) example.com");
    683   ReturnOAuthUrlFetchSuccess("user (at) example.com");
    684   observer()->Clear();
    685 
    686   NotifyLogout();
    687   observer()->SortEventsByUser();
    688   EXPECT_TRUE(
    689       observer()->CheckEvents(TrackingEvent(SIGN_OUT, kPrimaryAccountKey),
    690                               TrackingEvent(REMOVED, kPrimaryAccountKey),
    691                               TrackingEvent(SIGN_OUT, "user (at) example.com"),
    692                               TrackingEvent(REMOVED, "user (at) example.com")));
    693 }
    694 
    695 TEST_F(IdentityAccountTrackerTest, MultiRevokePrimaryDoesNotRemoveAllAccounts) {
    696   NotifyLogin(kPrimaryAccountKey);
    697   NotifyTokenAvailable(kPrimaryAccountKey);
    698   ReturnOAuthUrlFetchSuccess(kPrimaryAccountKey);
    699   NotifyTokenAvailable("user (at) example.com");
    700   ReturnOAuthUrlFetchSuccess("user (at) example.com");
    701   observer()->Clear();
    702 
    703   NotifyTokenRevoked(kPrimaryAccountKey);
    704   observer()->SortEventsByUser();
    705   EXPECT_TRUE(
    706       observer()->CheckEvents(TrackingEvent(SIGN_OUT, kPrimaryAccountKey)));
    707 }
    708 
    709 TEST_F(IdentityAccountTrackerTest, GetAccountsPrimary) {
    710   SetupPrimaryLogin();
    711 
    712   std::vector<AccountIds> ids = account_tracker()->GetAccounts();
    713   EXPECT_EQ(1ul, ids.size());
    714   EXPECT_EQ(kPrimaryAccountKey, ids[0].account_key);
    715   EXPECT_EQ(AccountKeyToObfuscatedId(kPrimaryAccountKey), ids[0].gaia);
    716 }
    717 
    718 TEST_F(IdentityAccountTrackerTest, GetAccountsSignedOut) {
    719   std::vector<AccountIds> ids = account_tracker()->GetAccounts();
    720   EXPECT_EQ(0ul, ids.size());
    721 }
    722 
    723 TEST_F(IdentityAccountTrackerTest, GetAccountsOnlyReturnAccountsWithTokens) {
    724   SetupPrimaryLogin();
    725 
    726   NotifyTokenAvailable("alpha (at) example.com");
    727   NotifyTokenAvailable("beta (at) example.com");
    728   ReturnOAuthUrlFetchSuccess("beta (at) example.com");
    729 
    730   std::vector<AccountIds> ids = account_tracker()->GetAccounts();
    731   EXPECT_EQ(2ul, ids.size());
    732   EXPECT_EQ(kPrimaryAccountKey, ids[0].account_key);
    733   EXPECT_EQ(AccountKeyToObfuscatedId(kPrimaryAccountKey), ids[0].gaia);
    734   EXPECT_EQ("beta (at) example.com", ids[1].account_key);
    735   EXPECT_EQ(AccountKeyToObfuscatedId("beta (at) example.com"), ids[1].gaia);
    736 }
    737 
    738 TEST_F(IdentityAccountTrackerTest, GetAccountsSortOrder) {
    739   SetupPrimaryLogin();
    740 
    741   NotifyTokenAvailable("zeta (at) example.com");
    742   ReturnOAuthUrlFetchSuccess("zeta (at) example.com");
    743   NotifyTokenAvailable("alpha (at) example.com");
    744   ReturnOAuthUrlFetchSuccess("alpha (at) example.com");
    745 
    746   // The primary account will be first in the vector. Remaining accounts
    747   // will be sorted by gaia ID.
    748   std::vector<AccountIds> ids = account_tracker()->GetAccounts();
    749   EXPECT_EQ(3ul, ids.size());
    750   EXPECT_EQ(kPrimaryAccountKey, ids[0].account_key);
    751   EXPECT_EQ(AccountKeyToObfuscatedId(kPrimaryAccountKey), ids[0].gaia);
    752   EXPECT_EQ("alpha (at) example.com", ids[1].account_key);
    753   EXPECT_EQ(AccountKeyToObfuscatedId("alpha (at) example.com"), ids[1].gaia);
    754   EXPECT_EQ("zeta (at) example.com", ids[2].account_key);
    755   EXPECT_EQ(AccountKeyToObfuscatedId("zeta (at) example.com"), ids[2].gaia);
    756 }
    757 
    758 TEST_F(IdentityAccountTrackerTest,
    759        GetAccountsReturnNothingWhenPrimarySignedOut) {
    760   SetupPrimaryLogin();
    761 
    762   NotifyTokenAvailable("zeta (at) example.com");
    763   ReturnOAuthUrlFetchSuccess("zeta (at) example.com");
    764   NotifyTokenAvailable("alpha (at) example.com");
    765   ReturnOAuthUrlFetchSuccess("alpha (at) example.com");
    766 
    767   NotifyTokenRevoked(kPrimaryAccountKey);
    768 
    769   std::vector<AccountIds> ids = account_tracker()->GetAccounts();
    770   EXPECT_EQ(0ul, ids.size());
    771 }
    772 
    773 TEST_F(IdentityAccountTrackerTest, FindAccountIdsByGaiaIdPrimary) {
    774   SetupPrimaryLogin();
    775 
    776   AccountIds ids = account_tracker()->FindAccountIdsByGaiaId(
    777       AccountKeyToObfuscatedId(kPrimaryAccountKey));
    778   EXPECT_EQ(kPrimaryAccountKey, ids.account_key);
    779   EXPECT_EQ(kPrimaryAccountKey, ids.email);
    780   EXPECT_EQ(AccountKeyToObfuscatedId(kPrimaryAccountKey), ids.gaia);
    781 }
    782 
    783 TEST_F(IdentityAccountTrackerTest, FindAccountIdsByGaiaIdNotFound) {
    784   SetupPrimaryLogin();
    785 
    786   AccountIds ids = account_tracker()->FindAccountIdsByGaiaId(
    787       AccountKeyToObfuscatedId("notfound (at) example.com"));
    788   EXPECT_TRUE(ids.account_key.empty());
    789   EXPECT_TRUE(ids.email.empty());
    790   EXPECT_TRUE(ids.gaia.empty());
    791 }
    792 
    793 TEST_F(IdentityAccountTrackerTest,
    794        FindAccountIdsByGaiaIdReturnEmptyWhenPrimarySignedOut) {
    795   SetupPrimaryLogin();
    796 
    797   NotifyTokenAvailable("zeta (at) example.com");
    798   ReturnOAuthUrlFetchSuccess("zeta (at) example.com");
    799   NotifyTokenAvailable("alpha (at) example.com");
    800   ReturnOAuthUrlFetchSuccess("alpha (at) example.com");
    801 
    802   NotifyTokenRevoked(kPrimaryAccountKey);
    803 
    804   AccountIds ids =
    805       account_tracker()->FindAccountIdsByGaiaId(kPrimaryAccountKey);
    806   EXPECT_TRUE(ids.account_key.empty());
    807   EXPECT_TRUE(ids.email.empty());
    808   EXPECT_TRUE(ids.gaia.empty());
    809 
    810   ids = account_tracker()->FindAccountIdsByGaiaId("alpha (at) example.com");
    811   EXPECT_TRUE(ids.account_key.empty());
    812   EXPECT_TRUE(ids.email.empty());
    813   EXPECT_TRUE(ids.gaia.empty());
    814 }
    815 
    816 }  // namespace gaia
    817