Home | History | Annotate | Download | only in identity
      1 // Copyright 2013 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 "chrome/browser/extensions/api/identity/account_tracker.h"
      6 
      7 #include <algorithm>
      8 #include <vector>
      9 
     10 #include "base/strings/stringprintf.h"
     11 #include "chrome/browser/signin/fake_profile_oauth2_token_service.h"
     12 #include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h"
     13 #include "chrome/browser/signin/fake_signin_manager.h"
     14 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
     15 #include "chrome/browser/signin/signin_manager_factory.h"
     16 #include "chrome/test/base/testing_profile.h"
     17 #include "components/signin/core/browser/signin_manager_base.h"
     18 #include "content/public/test/test_browser_thread_bundle.h"
     19 #include "google_apis/gaia/gaia_oauth_client.h"
     20 #include "net/http/http_status_code.h"
     21 #include "net/url_request/test_url_fetcher_factory.h"
     22 #include "net/url_request/url_fetcher_delegate.h"
     23 #include "net/url_request/url_request_test_util.h"
     24 #include "testing/gtest/include/gtest/gtest.h"
     25 
     26 // TODO(courage): Account removal really only applies to the primary account,
     27 // because that's the only account tracked by the SigninManager. Many of the
     28 // tests here remove non-primary accounts. They still properly test the account
     29 // state machine, but it may be confusing to readers. Update these tests to
     30 // avoid causing confusion.
     31 
     32 namespace {
     33 
     34 const char kPrimaryAccountKey[] = "primary_account (at) example.com";
     35 
     36 enum TrackingEventType {
     37   ADDED,
     38   REMOVED,
     39   SIGN_IN,
     40   SIGN_OUT
     41 };
     42 
     43 std::string AccountKeyToObfuscatedId(const std::string email) {
     44   return "obfid-" + email;
     45 }
     46 
     47 class TrackingEvent {
     48  public:
     49   TrackingEvent(TrackingEventType type,
     50                 const std::string& account_key,
     51                 const std::string& gaia_id)
     52       : type_(type),
     53         account_key_(account_key),
     54         gaia_id_(gaia_id) {}
     55 
     56   TrackingEvent(TrackingEventType type,
     57                 const std::string& account_key)
     58       : type_(type),
     59         account_key_(account_key),
     60         gaia_id_(AccountKeyToObfuscatedId(account_key)) {}
     61 
     62   bool operator==(const TrackingEvent& event) const {
     63     return type_ == event.type_ && account_key_ == event.account_key_ &&
     64         gaia_id_ == event.gaia_id_;
     65   }
     66 
     67   std::string ToString() const {
     68     const char * typestr = "INVALID";
     69     switch (type_) {
     70       case ADDED:
     71         typestr = "ADD";
     72         break;
     73       case REMOVED:
     74         typestr = "REM";
     75         break;
     76       case SIGN_IN:
     77         typestr = " IN";
     78         break;
     79       case SIGN_OUT:
     80         typestr = "OUT";
     81         break;
     82     }
     83     return base::StringPrintf("{ type: %s, email: %s, gaia: %s }",
     84                               typestr,
     85                               account_key_.c_str(),
     86                               gaia_id_.c_str());
     87   }
     88 
     89  private:
     90   friend bool CompareByUser(TrackingEvent a, TrackingEvent b);
     91 
     92   TrackingEventType type_;
     93   std::string account_key_;
     94   std::string gaia_id_;
     95 };
     96 
     97 bool CompareByUser(TrackingEvent a, TrackingEvent b) {
     98   return a.account_key_ < b.account_key_;
     99 }
    100 
    101 std::string Str(const std::vector<TrackingEvent>& events) {
    102   std::string str = "[";
    103   bool needs_comma = false;
    104   for (std::vector<TrackingEvent>::const_iterator it =
    105        events.begin(); it != events.end(); ++it) {
    106     if (needs_comma)
    107       str += ",\n ";
    108     needs_comma = true;
    109     str += it->ToString();
    110   }
    111   str += "]";
    112   return str;
    113 }
    114 
    115 }  // namespace
    116 
    117 namespace extensions {
    118 
    119 class AccountTrackerObserver : public AccountTracker::Observer {
    120  public:
    121   AccountTrackerObserver() {}
    122   virtual ~AccountTrackerObserver() {}
    123 
    124   testing::AssertionResult CheckEvents();
    125   testing::AssertionResult CheckEvents(const TrackingEvent& e1);
    126   testing::AssertionResult CheckEvents(const TrackingEvent& e1,
    127                                        const TrackingEvent& e2);
    128   testing::AssertionResult CheckEvents(const TrackingEvent& e1,
    129                                        const TrackingEvent& e2,
    130                                        const TrackingEvent& e3);
    131   testing::AssertionResult CheckEvents(const TrackingEvent& e1,
    132                                        const TrackingEvent& e2,
    133                                        const TrackingEvent& e3,
    134                                        const TrackingEvent& e4);
    135   testing::AssertionResult CheckEvents(const TrackingEvent& e1,
    136                                        const TrackingEvent& e2,
    137                                        const TrackingEvent& e3,
    138                                        const TrackingEvent& e4,
    139                                        const TrackingEvent& e5);
    140   testing::AssertionResult CheckEvents(const TrackingEvent& e1,
    141                                        const TrackingEvent& e2,
    142                                        const TrackingEvent& e3,
    143                                        const TrackingEvent& e4,
    144                                        const TrackingEvent& e5,
    145                                        const TrackingEvent& e6);
    146   void Clear();
    147   void SortEventsByUser();
    148 
    149   // AccountTracker::Observer implementation
    150   virtual void OnAccountAdded(const AccountIds& ids) OVERRIDE;
    151   virtual void OnAccountRemoved(const AccountIds& ids) OVERRIDE;
    152   virtual void OnAccountSignInChanged(const AccountIds& ids, bool is_signed_in)
    153       OVERRIDE;
    154 
    155  private:
    156   testing::AssertionResult CheckEvents(
    157       const std::vector<TrackingEvent>& events);
    158 
    159   std::vector<TrackingEvent> events_;
    160 };
    161 
    162 void AccountTrackerObserver::OnAccountAdded(const AccountIds& ids) {
    163   events_.push_back(TrackingEvent(ADDED, ids.email, ids.gaia));
    164 }
    165 
    166 void AccountTrackerObserver::OnAccountRemoved(const AccountIds& ids) {
    167   events_.push_back(TrackingEvent(REMOVED, ids.email, ids.gaia));
    168 }
    169 
    170 void AccountTrackerObserver::OnAccountSignInChanged(const AccountIds& ids,
    171                                                     bool is_signed_in) {
    172   events_.push_back(
    173       TrackingEvent(is_signed_in ? SIGN_IN : SIGN_OUT, ids.email, ids.gaia));
    174 }
    175 
    176 void AccountTrackerObserver::Clear() {
    177   events_.clear();
    178 }
    179 
    180 void AccountTrackerObserver::SortEventsByUser() {
    181   std::stable_sort(events_.begin(), events_.end(), CompareByUser);
    182 }
    183 
    184 testing::AssertionResult AccountTrackerObserver::CheckEvents() {
    185   std::vector<TrackingEvent> events;
    186   return CheckEvents(events);
    187 }
    188 
    189 testing::AssertionResult AccountTrackerObserver::CheckEvents(
    190     const TrackingEvent& e1) {
    191   std::vector<TrackingEvent> events;
    192   events.push_back(e1);
    193   return CheckEvents(events);
    194 }
    195 
    196 testing::AssertionResult AccountTrackerObserver::CheckEvents(
    197     const TrackingEvent& e1,
    198     const TrackingEvent& e2) {
    199   std::vector<TrackingEvent> events;
    200   events.push_back(e1);
    201   events.push_back(e2);
    202   return CheckEvents(events);
    203 }
    204 
    205 testing::AssertionResult AccountTrackerObserver::CheckEvents(
    206     const TrackingEvent& e1,
    207     const TrackingEvent& e2,
    208     const TrackingEvent& e3) {
    209   std::vector<TrackingEvent> events;
    210   events.push_back(e1);
    211   events.push_back(e2);
    212   events.push_back(e3);
    213   return CheckEvents(events);
    214 }
    215 
    216 testing::AssertionResult AccountTrackerObserver::CheckEvents(
    217     const TrackingEvent& e1,
    218     const TrackingEvent& e2,
    219     const TrackingEvent& e3,
    220     const TrackingEvent& e4) {
    221   std::vector<TrackingEvent> events;
    222   events.push_back(e1);
    223   events.push_back(e2);
    224   events.push_back(e3);
    225   events.push_back(e4);
    226   return CheckEvents(events);
    227 }
    228 
    229 testing::AssertionResult AccountTrackerObserver::CheckEvents(
    230     const TrackingEvent& e1,
    231     const TrackingEvent& e2,
    232     const TrackingEvent& e3,
    233     const TrackingEvent& e4,
    234     const TrackingEvent& e5) {
    235   std::vector<TrackingEvent> events;
    236   events.push_back(e1);
    237   events.push_back(e2);
    238   events.push_back(e3);
    239   events.push_back(e4);
    240   events.push_back(e5);
    241   return CheckEvents(events);
    242 }
    243 
    244 testing::AssertionResult AccountTrackerObserver::CheckEvents(
    245     const TrackingEvent& e1,
    246     const TrackingEvent& e2,
    247     const TrackingEvent& e3,
    248     const TrackingEvent& e4,
    249     const TrackingEvent& e5,
    250     const TrackingEvent& e6) {
    251   std::vector<TrackingEvent> events;
    252   events.push_back(e1);
    253   events.push_back(e2);
    254   events.push_back(e3);
    255   events.push_back(e4);
    256   events.push_back(e5);
    257   events.push_back(e6);
    258   return CheckEvents(events);
    259 }
    260 
    261 testing::AssertionResult AccountTrackerObserver::CheckEvents(
    262     const std::vector<TrackingEvent>& events) {
    263   std::string maybe_newline = (events.size() + events_.size()) > 2 ? "\n" : "";
    264   testing::AssertionResult result(
    265       (events_ == events)
    266           ? testing::AssertionSuccess()
    267           : (testing::AssertionFailure()
    268              << "Expected " << maybe_newline << Str(events) << ", "
    269              << maybe_newline << "Got " << maybe_newline << Str(events_)));
    270   events_.clear();
    271   return result;
    272 }
    273 
    274 class IdentityAccountTrackerTest : public testing::Test {
    275  public:
    276   IdentityAccountTrackerTest() {}
    277 
    278   virtual ~IdentityAccountTrackerTest() {}
    279 
    280   virtual void SetUp() OVERRIDE {
    281     TestingProfile::Builder builder;
    282     builder.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(),
    283                               BuildFakeProfileOAuth2TokenService);
    284     builder.AddTestingFactory(SigninManagerFactory::GetInstance(),
    285                               FakeSigninManagerBase::Build);
    286 
    287     test_profile_ = builder.Build();
    288 
    289     fake_oauth2_token_service_ = static_cast<FakeProfileOAuth2TokenService*>(
    290         ProfileOAuth2TokenServiceFactory::GetForProfile(test_profile_.get()));
    291 
    292     fake_signin_manager_ = static_cast<FakeSigninManagerForTesting*>(
    293         SigninManagerFactory::GetForProfile(test_profile_.get()));
    294 #if defined(OS_CHROMEOS)
    295     // We don't sign the primary user in and out on ChromeOS, so set the
    296     // username once in setup.
    297     fake_signin_manager_->SetAuthenticatedUsername(kPrimaryAccountKey);
    298 #endif
    299 
    300     account_tracker_.reset(new AccountTracker(test_profile_.get()));
    301     account_tracker_->AddObserver(&observer_);
    302 
    303     // Start off signed into the primary account, because most tests need the
    304     // profile to be signed in. Remove the initial sign-in events that the
    305     // tests don't care about.
    306     NotifyTokenAvailable(kPrimaryAccountKey);
    307     ReturnOAuthUrlFetchSuccess(kPrimaryAccountKey);
    308     observer()->Clear();
    309   }
    310 
    311   virtual void TearDown() OVERRIDE {
    312     account_tracker_->RemoveObserver(&observer_);
    313     account_tracker_->Shutdown();
    314   }
    315 
    316   Profile* profile() {
    317     return test_profile_.get();
    318   }
    319 
    320   AccountTrackerObserver* observer() {
    321     return &observer_;
    322   }
    323 
    324   AccountTracker* account_tracker() {
    325     return account_tracker_.get();
    326   }
    327 
    328   // Helpers to pass fake events to the tracker.
    329 
    330   void NotifyRemoveAccount(const std::string& username) {
    331 #if !defined(OS_CHROMEOS)
    332     if (username == kPrimaryAccountKey)
    333       fake_signin_manager_->SignOut(signin_metrics::SIGNOUT_TEST);
    334     else
    335       account_tracker()->GoogleSignedOut(username);
    336 #else
    337     account_tracker()->GoogleSignedOut(username);
    338 #endif
    339   }
    340 
    341   void NotifyTokenAvailable(const std::string& username) {
    342     fake_oauth2_token_service_->IssueRefreshTokenForUser(username,
    343                                                          "refresh_token");
    344 #if !defined(OS_CHROMEOS)
    345     if (username == kPrimaryAccountKey)
    346       fake_signin_manager_->OnExternalSigninCompleted(username);
    347 #endif
    348   }
    349 
    350   void NotifyTokenRevoked(const std::string& username) {
    351     fake_oauth2_token_service_->IssueRefreshTokenForUser(username,
    352                                                          std::string());
    353   }
    354 
    355   // Helpers to fake access token and user info fetching
    356   void IssueAccessToken(const std::string& username) {
    357     fake_oauth2_token_service_->IssueAllTokensForAccount(
    358         username, "access_token-" + username, base::Time::Max());
    359   }
    360 
    361   std::string GetValidTokenInfoResponse(const std::string account_key) {
    362     return std::string("{ \"id\": \"") + AccountKeyToObfuscatedId(account_key) +
    363            "\" }";
    364   }
    365 
    366   void ReturnOAuthUrlFetchResults(int fetcher_id,
    367                                   net::HttpStatusCode response_code,
    368                                   const std::string& response_string);
    369 
    370   void ReturnOAuthUrlFetchSuccess(const std::string& account_key);
    371   void ReturnOAuthUrlFetchFailure(const std::string& account_key);
    372 
    373  private:
    374   scoped_ptr<TestingProfile> test_profile_;
    375   net::TestURLFetcherFactory test_fetcher_factory_;
    376   FakeProfileOAuth2TokenService* fake_oauth2_token_service_;
    377   FakeSigninManagerForTesting* fake_signin_manager_;
    378   content::TestBrowserThreadBundle thread_bundle_;
    379 
    380   scoped_ptr<AccountTracker> account_tracker_;
    381   AccountTrackerObserver observer_;
    382 };
    383 
    384 void IdentityAccountTrackerTest::ReturnOAuthUrlFetchResults(
    385     int fetcher_id,
    386     net::HttpStatusCode response_code,
    387     const std::string&  response_string) {
    388 
    389   net::TestURLFetcher* fetcher =
    390       test_fetcher_factory_.GetFetcherByID(fetcher_id);
    391   ASSERT_TRUE(fetcher);
    392   fetcher->set_response_code(response_code);
    393   fetcher->SetResponseString(response_string);
    394   fetcher->delegate()->OnURLFetchComplete(fetcher);
    395 }
    396 
    397 void IdentityAccountTrackerTest::ReturnOAuthUrlFetchSuccess(
    398     const std::string& account_key) {
    399   IssueAccessToken(account_key);
    400   ReturnOAuthUrlFetchResults(gaia::GaiaOAuthClient::kUrlFetcherId,
    401                              net::HTTP_OK,
    402                              GetValidTokenInfoResponse(account_key));
    403 }
    404 
    405 void IdentityAccountTrackerTest::ReturnOAuthUrlFetchFailure(
    406     const std::string& account_key) {
    407   IssueAccessToken(account_key);
    408   ReturnOAuthUrlFetchResults(
    409       gaia::GaiaOAuthClient::kUrlFetcherId, net::HTTP_BAD_REQUEST, "");
    410 }
    411 
    412 TEST_F(IdentityAccountTrackerTest, Available) {
    413   NotifyTokenAvailable("user (at) example.com");
    414   EXPECT_TRUE(observer()->CheckEvents());
    415 
    416   ReturnOAuthUrlFetchSuccess("user (at) example.com");
    417   EXPECT_TRUE(observer()->CheckEvents(
    418       TrackingEvent(ADDED, "user (at) example.com"),
    419       TrackingEvent(SIGN_IN, "user (at) example.com")));
    420 }
    421 
    422 TEST_F(IdentityAccountTrackerTest, Revoke) {
    423   account_tracker()->OnRefreshTokenRevoked("user (at) example.com");
    424   EXPECT_TRUE(observer()->CheckEvents());
    425 }
    426 
    427 TEST_F(IdentityAccountTrackerTest, Remove) {
    428   NotifyRemoveAccount("user (at) example.com");
    429   EXPECT_TRUE(observer()->CheckEvents());
    430 }
    431 
    432 TEST_F(IdentityAccountTrackerTest, AvailableRemoveFetchCancelAvailable) {
    433   NotifyTokenAvailable("user (at) example.com");
    434   NotifyRemoveAccount("user (at) example.com");
    435   EXPECT_TRUE(observer()->CheckEvents());
    436 
    437   NotifyTokenAvailable("user (at) example.com");
    438   ReturnOAuthUrlFetchSuccess("user (at) example.com");
    439   EXPECT_TRUE(observer()->CheckEvents(
    440       TrackingEvent(ADDED, "user (at) example.com"),
    441       TrackingEvent(SIGN_IN, "user (at) example.com")));
    442 }
    443 
    444 TEST_F(IdentityAccountTrackerTest, AvailableRemoveAvailable) {
    445   NotifyTokenAvailable("user (at) example.com");
    446   ReturnOAuthUrlFetchSuccess("user (at) example.com");
    447   NotifyRemoveAccount("user (at) example.com");
    448   EXPECT_TRUE(observer()->CheckEvents(
    449       TrackingEvent(ADDED, "user (at) example.com"),
    450       TrackingEvent(SIGN_IN, "user (at) example.com"),
    451       TrackingEvent(SIGN_OUT, "user (at) example.com"),
    452       TrackingEvent(REMOVED, "user (at) example.com")));
    453 
    454   NotifyTokenAvailable("user (at) example.com");
    455   ReturnOAuthUrlFetchSuccess("user (at) example.com");
    456   EXPECT_TRUE(observer()->CheckEvents(
    457       TrackingEvent(ADDED, "user (at) example.com"),
    458       TrackingEvent(SIGN_IN, "user (at) example.com")));
    459 }
    460 
    461 TEST_F(IdentityAccountTrackerTest, AvailableRevokeAvailable) {
    462   NotifyTokenAvailable("user (at) example.com");
    463   ReturnOAuthUrlFetchSuccess("user (at) example.com");
    464   NotifyTokenRevoked("user (at) example.com");
    465   EXPECT_TRUE(observer()->CheckEvents(
    466       TrackingEvent(ADDED, "user (at) example.com"),
    467       TrackingEvent(SIGN_IN, "user (at) example.com"),
    468       TrackingEvent(SIGN_OUT, "user (at) example.com")));
    469 
    470   NotifyTokenAvailable("user (at) example.com");
    471   EXPECT_TRUE(observer()->CheckEvents(
    472       TrackingEvent(SIGN_IN, "user (at) example.com")));
    473 }
    474 
    475 TEST_F(IdentityAccountTrackerTest, AvailableRevokeAvailableWithPendingFetch) {
    476   NotifyTokenAvailable("user (at) example.com");
    477   NotifyTokenRevoked("user (at) example.com");
    478   EXPECT_TRUE(observer()->CheckEvents());
    479 
    480   NotifyTokenAvailable("user (at) example.com");
    481   ReturnOAuthUrlFetchSuccess("user (at) example.com");
    482   EXPECT_TRUE(observer()->CheckEvents(
    483       TrackingEvent(ADDED, "user (at) example.com"),
    484       TrackingEvent(SIGN_IN, "user (at) example.com")));
    485 }
    486 
    487 TEST_F(IdentityAccountTrackerTest, AvailableRevokeRemove) {
    488   NotifyTokenAvailable("user (at) example.com");
    489   ReturnOAuthUrlFetchSuccess("user (at) example.com");
    490   NotifyTokenRevoked("user (at) example.com");
    491   EXPECT_TRUE(observer()->CheckEvents(
    492       TrackingEvent(ADDED, "user (at) example.com"),
    493       TrackingEvent(SIGN_IN, "user (at) example.com"),
    494       TrackingEvent(SIGN_OUT, "user (at) example.com")));
    495 
    496   NotifyRemoveAccount("user (at) example.com");
    497   EXPECT_TRUE(observer()->CheckEvents(
    498       TrackingEvent(REMOVED, "user (at) example.com")));
    499 }
    500 
    501 TEST_F(IdentityAccountTrackerTest, AvailableRevokeRevoke) {
    502   NotifyTokenAvailable("user (at) example.com");
    503   ReturnOAuthUrlFetchSuccess("user (at) example.com");
    504   NotifyTokenRevoked("user (at) example.com");
    505   EXPECT_TRUE(observer()->CheckEvents(
    506       TrackingEvent(ADDED, "user (at) example.com"),
    507       TrackingEvent(SIGN_IN, "user (at) example.com"),
    508       TrackingEvent(SIGN_OUT, "user (at) example.com")));
    509 
    510   NotifyTokenRevoked("user (at) example.com");
    511   EXPECT_TRUE(observer()->CheckEvents());
    512 }
    513 
    514 TEST_F(IdentityAccountTrackerTest, AvailableAvailable) {
    515   NotifyTokenAvailable("user (at) example.com");
    516   ReturnOAuthUrlFetchSuccess("user (at) example.com");
    517   EXPECT_TRUE(observer()->CheckEvents(
    518       TrackingEvent(ADDED, "user (at) example.com"),
    519       TrackingEvent(SIGN_IN, "user (at) example.com")));
    520 
    521   NotifyTokenAvailable("user (at) example.com");
    522   EXPECT_TRUE(observer()->CheckEvents());
    523 }
    524 
    525 TEST_F(IdentityAccountTrackerTest, TwoAccounts) {
    526   NotifyTokenAvailable("alpha (at) example.com");
    527   ReturnOAuthUrlFetchSuccess("alpha (at) example.com");
    528   EXPECT_TRUE(observer()->CheckEvents(
    529       TrackingEvent(ADDED, "alpha (at) example.com"),
    530       TrackingEvent(SIGN_IN, "alpha (at) example.com")));
    531 
    532   NotifyTokenAvailable("beta (at) example.com");
    533   ReturnOAuthUrlFetchSuccess("beta (at) example.com");
    534   EXPECT_TRUE(observer()->CheckEvents(
    535       TrackingEvent(ADDED, "beta (at) example.com"),
    536       TrackingEvent(SIGN_IN, "beta (at) example.com")));
    537 
    538   NotifyRemoveAccount("alpha (at) example.com");
    539   EXPECT_TRUE(observer()->CheckEvents(
    540       TrackingEvent(SIGN_OUT, "alpha (at) example.com"),
    541       TrackingEvent(REMOVED, "alpha (at) example.com")));
    542 
    543   NotifyRemoveAccount("beta (at) example.com");
    544   EXPECT_TRUE(observer()->CheckEvents(
    545       TrackingEvent(SIGN_OUT, "beta (at) example.com"),
    546       TrackingEvent(REMOVED, "beta (at) example.com")));
    547 }
    548 
    549 TEST_F(IdentityAccountTrackerTest, GlobalErrors) {
    550   NotifyTokenAvailable("alpha (at) example.com");
    551   ReturnOAuthUrlFetchSuccess("alpha (at) example.com");
    552   EXPECT_TRUE(observer()->CheckEvents(
    553       TrackingEvent(ADDED, "alpha (at) example.com"),
    554       TrackingEvent(SIGN_IN, "alpha (at) example.com")));
    555   NotifyTokenAvailable("beta (at) example.com");
    556   ReturnOAuthUrlFetchSuccess("beta (at) example.com");
    557   EXPECT_TRUE(observer()->CheckEvents(
    558       TrackingEvent(ADDED, "beta (at) example.com"),
    559       TrackingEvent(SIGN_IN, "beta (at) example.com")));
    560 
    561   EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
    562             account_tracker()->GetAuthStatus());
    563 
    564   account_tracker()->ReportAuthError(
    565       "beta (at) example.com",
    566       GoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED));
    567   EXPECT_TRUE(observer()->CheckEvents(
    568       TrackingEvent(SIGN_OUT, "beta (at) example.com")));
    569   EXPECT_EQ(GoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED),
    570             account_tracker()->GetAuthStatus());
    571 
    572   account_tracker()->ReportAuthError(
    573       "alpha (at) example.com",
    574       GoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED));
    575   EXPECT_TRUE(observer()->CheckEvents(
    576       TrackingEvent(SIGN_OUT, "alpha (at) example.com")));
    577   EXPECT_EQ(GoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED),
    578             account_tracker()->GetAuthStatus());
    579 
    580   NotifyRemoveAccount("alpha (at) example.com");
    581   EXPECT_EQ(GoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED),
    582             account_tracker()->GetAuthStatus());
    583 
    584   NotifyTokenAvailable("beta (at) example.com");
    585   EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
    586             account_tracker()->GetAuthStatus());
    587 }
    588 
    589 TEST_F(IdentityAccountTrackerTest, AvailableTokenFetchFailAvailable) {
    590   NotifyTokenAvailable("alpha (at) example.com");
    591   ReturnOAuthUrlFetchFailure("alpha (at) example.com");
    592   EXPECT_TRUE(observer()->CheckEvents());
    593 
    594   NotifyTokenAvailable("user (at) example.com");
    595   ReturnOAuthUrlFetchSuccess("user (at) example.com");
    596   EXPECT_TRUE(observer()->CheckEvents(
    597       TrackingEvent(ADDED, "user (at) example.com"),
    598       TrackingEvent(SIGN_IN, "user (at) example.com")));
    599 }
    600 
    601 // The Chrome OS fake sign-in manager doesn't do sign-in or sign-out.
    602 #if !defined(OS_CHROMEOS)
    603 
    604 TEST_F(IdentityAccountTrackerTest, PrimarySignOutSignIn) {
    605   NotifyRemoveAccount(kPrimaryAccountKey);
    606   EXPECT_TRUE(observer()->CheckEvents(
    607       TrackingEvent(SIGN_OUT, kPrimaryAccountKey),
    608       TrackingEvent(REMOVED, kPrimaryAccountKey)));
    609 
    610   NotifyTokenAvailable(kPrimaryAccountKey);
    611   ReturnOAuthUrlFetchSuccess(kPrimaryAccountKey);
    612   EXPECT_TRUE(observer()->CheckEvents(
    613       TrackingEvent(ADDED, kPrimaryAccountKey),
    614       TrackingEvent(SIGN_IN, kPrimaryAccountKey)));
    615 }
    616 
    617 TEST_F(IdentityAccountTrackerTest, PrimarySignOutSignInTwoAccounts) {
    618   NotifyTokenAvailable("alpha (at) example.com");
    619   ReturnOAuthUrlFetchSuccess("alpha (at) example.com");
    620   NotifyTokenAvailable("beta (at) example.com");
    621   ReturnOAuthUrlFetchSuccess("beta (at) example.com");
    622 
    623   observer()->SortEventsByUser();
    624   EXPECT_TRUE(observer()->CheckEvents(
    625       TrackingEvent(ADDED, "alpha (at) example.com"),
    626       TrackingEvent(SIGN_IN, "alpha (at) example.com"),
    627       TrackingEvent(ADDED, "beta (at) example.com"),
    628       TrackingEvent(SIGN_IN, "beta (at) example.com")));
    629 
    630   NotifyRemoveAccount(kPrimaryAccountKey);
    631   observer()->SortEventsByUser();
    632   EXPECT_TRUE(observer()->CheckEvents(
    633       TrackingEvent(SIGN_OUT, "alpha (at) example.com"),
    634       TrackingEvent(REMOVED, "alpha (at) example.com"),
    635       TrackingEvent(SIGN_OUT, "beta (at) example.com"),
    636       TrackingEvent(REMOVED, "beta (at) example.com"),
    637       TrackingEvent(SIGN_OUT, kPrimaryAccountKey),
    638       TrackingEvent(REMOVED, kPrimaryAccountKey)));
    639 
    640   // No events fire at all while profile is signed out.
    641   NotifyTokenRevoked("alpha (at) example.com");
    642   NotifyTokenAvailable("gamma (at) example.com");
    643   EXPECT_TRUE(observer()->CheckEvents());
    644 
    645   // Signing the profile in again will resume tracking all accounts.
    646   NotifyTokenAvailable(kPrimaryAccountKey);
    647   ReturnOAuthUrlFetchSuccess("beta (at) example.com");
    648   ReturnOAuthUrlFetchSuccess("gamma (at) example.com");
    649   ReturnOAuthUrlFetchSuccess(kPrimaryAccountKey);
    650   observer()->SortEventsByUser();
    651   EXPECT_TRUE(observer()->CheckEvents(
    652       TrackingEvent(ADDED, "beta (at) example.com"),
    653       TrackingEvent(SIGN_IN, "beta (at) example.com"),
    654       TrackingEvent(ADDED, "gamma (at) example.com"),
    655       TrackingEvent(SIGN_IN, "gamma (at) example.com"),
    656       TrackingEvent(ADDED, kPrimaryAccountKey),
    657       TrackingEvent(SIGN_IN, kPrimaryAccountKey)));
    658 
    659   // Revoking the primary token does not affect other accounts.
    660   NotifyTokenRevoked(kPrimaryAccountKey);
    661   EXPECT_TRUE(observer()->CheckEvents(
    662       TrackingEvent(SIGN_OUT, kPrimaryAccountKey)));
    663 
    664   NotifyTokenAvailable(kPrimaryAccountKey);
    665   EXPECT_TRUE(observer()->CheckEvents(
    666       TrackingEvent(SIGN_IN, kPrimaryAccountKey)));
    667 }
    668 
    669 #endif  // !defined(OS_CHROMEOS)
    670 
    671 TEST_F(IdentityAccountTrackerTest, GetAccountsPrimary) {
    672   std::vector<AccountIds> ids = account_tracker()->GetAccounts();
    673   EXPECT_EQ(1ul, ids.size());
    674   EXPECT_EQ(kPrimaryAccountKey, ids[0].account_key);
    675   EXPECT_EQ(AccountKeyToObfuscatedId(kPrimaryAccountKey), ids[0].gaia);
    676 }
    677 
    678 TEST_F(IdentityAccountTrackerTest, GetAccountsSignedOut) {
    679   NotifyTokenRevoked(kPrimaryAccountKey);
    680 
    681   std::vector<AccountIds> ids = account_tracker()->GetAccounts();
    682   EXPECT_EQ(0ul, ids.size());
    683 }
    684 
    685 TEST_F(IdentityAccountTrackerTest, GetAccountsOnlyReturnAccountsWithTokens) {
    686   NotifyTokenAvailable("alpha (at) example.com");
    687   NotifyTokenAvailable("beta (at) example.com");
    688   ReturnOAuthUrlFetchSuccess("beta (at) example.com");
    689 
    690   std::vector<AccountIds> ids = account_tracker()->GetAccounts();
    691   EXPECT_EQ(2ul, ids.size());
    692   EXPECT_EQ(kPrimaryAccountKey, ids[0].account_key);
    693   EXPECT_EQ(AccountKeyToObfuscatedId(kPrimaryAccountKey), ids[0].gaia);
    694   EXPECT_EQ("beta (at) example.com", ids[1].account_key);
    695   EXPECT_EQ(AccountKeyToObfuscatedId("beta (at) example.com"), ids[1].gaia);
    696 }
    697 
    698 TEST_F(IdentityAccountTrackerTest, GetAccountsSortOrder) {
    699   NotifyTokenAvailable("zeta (at) example.com");
    700   ReturnOAuthUrlFetchSuccess("zeta (at) example.com");
    701   NotifyTokenAvailable("alpha (at) example.com");
    702   ReturnOAuthUrlFetchSuccess("alpha (at) example.com");
    703 
    704   // The primary account will be first in the vector. Remaining accounts
    705   // will be sorted by gaia ID.
    706   std::vector<AccountIds> ids = account_tracker()->GetAccounts();
    707   EXPECT_EQ(3ul, ids.size());
    708   EXPECT_EQ(kPrimaryAccountKey, ids[0].account_key);
    709   EXPECT_EQ(AccountKeyToObfuscatedId(kPrimaryAccountKey), ids[0].gaia);
    710   EXPECT_EQ("alpha (at) example.com", ids[1].account_key);
    711   EXPECT_EQ(AccountKeyToObfuscatedId("alpha (at) example.com"), ids[1].gaia);
    712   EXPECT_EQ("zeta (at) example.com", ids[2].account_key);
    713   EXPECT_EQ(AccountKeyToObfuscatedId("zeta (at) example.com"), ids[2].gaia);
    714 }
    715 
    716 TEST_F(IdentityAccountTrackerTest,
    717        GetAccountsReturnNothingWhenPrimarySignedOut) {
    718   NotifyTokenAvailable("zeta (at) example.com");
    719   ReturnOAuthUrlFetchSuccess("zeta (at) example.com");
    720   NotifyTokenAvailable("alpha (at) example.com");
    721   ReturnOAuthUrlFetchSuccess("alpha (at) example.com");
    722 
    723   NotifyTokenRevoked(kPrimaryAccountKey);
    724 
    725   std::vector<AccountIds> ids = account_tracker()->GetAccounts();
    726   EXPECT_EQ(0ul, ids.size());
    727 }
    728 
    729 }  // namespace extensions
    730