Home | History | Annotate | Download | only in browser
      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 <algorithm>
      6 #include <vector>
      7 
      8 #include "base/message_loop/message_loop.h"
      9 #include "base/prefs/pref_registry_simple.h"
     10 #include "base/prefs/testing_pref_service.h"
     11 #include "base/strings/stringprintf.h"
     12 #include "components/signin/core/browser/account_tracker_service.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 enum TrackingEventType {
     24   UPDATED,
     25   REMOVED,
     26 };
     27 
     28 std::string AccountIdToEmail(const std::string account_id) {
     29   return account_id + "@gmail.com";
     30 }
     31 
     32 std::string AccountIdToGaiaId(const std::string account_id) {
     33   return "gaia-" + account_id;
     34 }
     35 
     36 class TrackingEvent {
     37  public:
     38   TrackingEvent(TrackingEventType type,
     39                 const std::string& account_id,
     40                 const std::string& gaia_id)
     41       : type_(type),
     42         account_id_(account_id),
     43         gaia_id_(gaia_id) {}
     44 
     45   TrackingEvent(TrackingEventType type,
     46                 const std::string& account_id)
     47       : type_(type),
     48         account_id_(account_id),
     49         gaia_id_(AccountIdToGaiaId(account_id)) {}
     50 
     51   bool operator==(const TrackingEvent& event) const {
     52     return type_ == event.type_ && account_id_ == event.account_id_ &&
     53         gaia_id_ == event.gaia_id_;
     54   }
     55 
     56   std::string ToString() const {
     57     const char * typestr = "INVALID";
     58     switch (type_) {
     59       case UPDATED:
     60         typestr = "UPD";
     61         break;
     62       case REMOVED:
     63         typestr = "REM";
     64         break;
     65     }
     66     return base::StringPrintf("{ type: %s, account_id: %s, gaia: %s }",
     67                               typestr,
     68                               account_id_.c_str(),
     69                               gaia_id_.c_str());
     70   }
     71 
     72  private:
     73   friend bool CompareByUser(TrackingEvent a, TrackingEvent b);
     74 
     75   TrackingEventType type_;
     76   std::string account_id_;
     77   std::string gaia_id_;
     78 };
     79 
     80 bool CompareByUser(TrackingEvent a, TrackingEvent b) {
     81   return a.account_id_ < b.account_id_;
     82 }
     83 
     84 std::string Str(const std::vector<TrackingEvent>& events) {
     85   std::string str = "[";
     86   bool needs_comma = false;
     87   for (std::vector<TrackingEvent>::const_iterator it =
     88        events.begin(); it != events.end(); ++it) {
     89     if (needs_comma)
     90       str += ",\n ";
     91     needs_comma = true;
     92     str += it->ToString();
     93   }
     94   str += "]";
     95   return str;
     96 }
     97 
     98 class AccountTrackerObserver : public AccountTrackerService::Observer {
     99  public:
    100   AccountTrackerObserver() {}
    101   virtual ~AccountTrackerObserver() {}
    102 
    103   void Clear();
    104   void SortEventsByUser();
    105 
    106   testing::AssertionResult CheckEvents();
    107   testing::AssertionResult CheckEvents(const TrackingEvent& e1);
    108   testing::AssertionResult CheckEvents(const TrackingEvent& e1,
    109                                        const TrackingEvent& e2);
    110   testing::AssertionResult CheckEvents(const TrackingEvent& e1,
    111                                        const TrackingEvent& e2,
    112                                        const TrackingEvent& e3);
    113 
    114  private:
    115   // AccountTrackerService::Observer implementation
    116   virtual void OnAccountUpdated(
    117       const AccountTrackerService::AccountInfo& ids) OVERRIDE;
    118   virtual void OnAccountRemoved(
    119       const AccountTrackerService::AccountInfo& ids) OVERRIDE;
    120 
    121   testing::AssertionResult CheckEvents(
    122       const std::vector<TrackingEvent>& events);
    123 
    124   std::vector<TrackingEvent> events_;
    125 };
    126 
    127 void AccountTrackerObserver::OnAccountUpdated(
    128     const AccountTrackerService::AccountInfo& ids) {
    129   events_.push_back(TrackingEvent(UPDATED, ids.account_id, ids.gaia));
    130 }
    131 
    132 void AccountTrackerObserver::OnAccountRemoved(
    133     const AccountTrackerService::AccountInfo& ids) {
    134   events_.push_back(TrackingEvent(REMOVED, ids.account_id, ids.gaia));
    135 }
    136 
    137 void AccountTrackerObserver::Clear() {
    138   events_.clear();
    139 }
    140 
    141 void AccountTrackerObserver::SortEventsByUser() {
    142   std::stable_sort(events_.begin(), events_.end(), CompareByUser);
    143 }
    144 
    145 testing::AssertionResult AccountTrackerObserver::CheckEvents() {
    146   std::vector<TrackingEvent> events;
    147   return CheckEvents(events);
    148 }
    149 
    150 testing::AssertionResult AccountTrackerObserver::CheckEvents(
    151     const TrackingEvent& e1) {
    152   std::vector<TrackingEvent> events;
    153   events.push_back(e1);
    154   return CheckEvents(events);
    155 }
    156 
    157 testing::AssertionResult AccountTrackerObserver::CheckEvents(
    158     const TrackingEvent& e1,
    159     const TrackingEvent& e2) {
    160   std::vector<TrackingEvent> events;
    161   events.push_back(e1);
    162   events.push_back(e2);
    163   return CheckEvents(events);
    164 }
    165 
    166 testing::AssertionResult AccountTrackerObserver::CheckEvents(
    167     const TrackingEvent& e1,
    168     const TrackingEvent& e2,
    169     const TrackingEvent& e3) {
    170   std::vector<TrackingEvent> events;
    171   events.push_back(e1);
    172   events.push_back(e2);
    173   events.push_back(e3);
    174   return CheckEvents(events);
    175 }
    176 
    177 testing::AssertionResult AccountTrackerObserver::CheckEvents(
    178     const std::vector<TrackingEvent>& events) {
    179   std::string maybe_newline = (events.size() + events_.size()) > 2 ? "\n" : "";
    180   testing::AssertionResult result(
    181       (events_ == events)
    182           ? testing::AssertionSuccess()
    183           : (testing::AssertionFailure()
    184              << "Expected " << maybe_newline << Str(events) << ", "
    185              << maybe_newline << "Got " << maybe_newline << Str(events_)));
    186   events_.clear();
    187   return result;
    188 }
    189 
    190 }  // namespace
    191 
    192 class AccountTrackerServiceTest : public testing::Test {
    193  public:
    194   AccountTrackerServiceTest() {}
    195 
    196   virtual ~AccountTrackerServiceTest() {}
    197 
    198   virtual void SetUp() OVERRIDE {
    199     fake_oauth2_token_service_.reset(new FakeOAuth2TokenService());
    200 
    201     pref_service_.registry()->RegisterListPref(
    202         AccountTrackerService::kAccountInfoPref);
    203 
    204     account_tracker_.reset(new AccountTrackerService());
    205     account_tracker_->Initialize(fake_oauth2_token_service_.get(),
    206                                  &pref_service_,
    207                                  new net::TestURLRequestContextGetter(
    208                                      message_loop_.message_loop_proxy()));
    209     account_tracker_->AddObserver(&observer_);
    210   }
    211 
    212   virtual void TearDown() OVERRIDE {
    213     account_tracker_->RemoveObserver(&observer_);
    214     account_tracker_->Shutdown();
    215   }
    216 
    217   void SimulateTokenAvailable(const std::string& account_id) {
    218     fake_oauth2_token_service_->AddAccount(account_id);
    219   }
    220 
    221   void SimulateTokenRevoked(const std::string& account_id) {
    222     fake_oauth2_token_service_->RemoveAccount(account_id);
    223   }
    224 
    225   // Helpers to fake access token and user info fetching
    226   void IssueAccessToken(const std::string& account_id) {
    227     fake_oauth2_token_service_->IssueAllTokensForAccount(
    228         account_id, "access_token-" + account_id, base::Time::Max());
    229   }
    230 
    231   std::string GenerateValidTokenInfoResponse(const std::string& account_id) {
    232     return base::StringPrintf("{\"id\": \"%s\", \"email\": \"%s\"}",
    233                               AccountIdToGaiaId(account_id).c_str(),
    234                               AccountIdToEmail(account_id).c_str());
    235   }
    236 
    237   void ReturnOAuthUrlFetchSuccess(const std::string& account_id);
    238   void ReturnOAuthUrlFetchFailure(const std::string& account_id);
    239 
    240   base::MessageLoopForIO* message_loop() { return &message_loop_; }
    241   AccountTrackerService* account_tracker() { return account_tracker_.get(); }
    242   AccountTrackerObserver* observer() { return &observer_; }
    243   OAuth2TokenService* token_service() {
    244     return fake_oauth2_token_service_.get();
    245   }
    246   TestingPrefServiceSimple* pref_service() { return &pref_service_; }
    247 
    248  private:
    249   void ReturnOAuthUrlFetchResults(int fetcher_id,
    250                                   net::HttpStatusCode response_code,
    251                                   const std::string& response_string);
    252 
    253   base::MessageLoopForIO message_loop_;
    254   net::TestURLFetcherFactory test_fetcher_factory_;
    255   scoped_ptr<FakeOAuth2TokenService> fake_oauth2_token_service_;
    256   TestingPrefServiceSimple pref_service_;
    257   scoped_ptr<AccountTrackerService> account_tracker_;
    258   AccountTrackerObserver observer_;
    259 };
    260 
    261 void AccountTrackerServiceTest::ReturnOAuthUrlFetchResults(
    262     int fetcher_id,
    263     net::HttpStatusCode response_code,
    264     const std::string&  response_string) {
    265   net::TestURLFetcher* fetcher =
    266       test_fetcher_factory_.GetFetcherByID(fetcher_id);
    267   ASSERT_TRUE(fetcher);
    268   fetcher->set_response_code(response_code);
    269   fetcher->SetResponseString(response_string);
    270   fetcher->delegate()->OnURLFetchComplete(fetcher);
    271 }
    272 
    273 void AccountTrackerServiceTest::ReturnOAuthUrlFetchSuccess(
    274     const std::string& account_id) {
    275   IssueAccessToken(account_id);
    276   ReturnOAuthUrlFetchResults(gaia::GaiaOAuthClient::kUrlFetcherId,
    277                              net::HTTP_OK,
    278                              GenerateValidTokenInfoResponse(account_id));
    279 }
    280 
    281 void AccountTrackerServiceTest::ReturnOAuthUrlFetchFailure(
    282     const std::string& account_id) {
    283   IssueAccessToken(account_id);
    284   ReturnOAuthUrlFetchResults(
    285       gaia::GaiaOAuthClient::kUrlFetcherId, net::HTTP_BAD_REQUEST, "");
    286 }
    287 
    288 TEST_F(AccountTrackerServiceTest, Basic) {
    289 }
    290 
    291 TEST_F(AccountTrackerServiceTest, TokenAvailable) {
    292   SimulateTokenAvailable("alpha");
    293   ASSERT_FALSE(account_tracker()->IsAllUserInfoFetched());
    294   ASSERT_TRUE(observer()->CheckEvents());
    295 }
    296 
    297 TEST_F(AccountTrackerServiceTest, TokenAvailable_Revoked) {
    298   SimulateTokenAvailable("alpha");
    299   SimulateTokenRevoked("alpha");
    300   ASSERT_TRUE(account_tracker()->IsAllUserInfoFetched());
    301   ASSERT_TRUE(observer()->CheckEvents());
    302 }
    303 
    304 TEST_F(AccountTrackerServiceTest, TokenAvailable_UserInfo) {
    305   SimulateTokenAvailable("alpha");
    306   ReturnOAuthUrlFetchSuccess("alpha");
    307   ASSERT_TRUE(account_tracker()->IsAllUserInfoFetched());
    308   ASSERT_TRUE(observer()->CheckEvents(TrackingEvent(UPDATED, "alpha")));
    309 }
    310 
    311 TEST_F(AccountTrackerServiceTest, TokenAvailable_UserInfo_Revoked) {
    312   SimulateTokenAvailable("alpha");
    313   ReturnOAuthUrlFetchSuccess("alpha");
    314   ASSERT_TRUE(account_tracker()->IsAllUserInfoFetched());
    315   ASSERT_TRUE(observer()->CheckEvents(TrackingEvent(UPDATED, "alpha")));
    316   SimulateTokenRevoked("alpha");
    317   ASSERT_TRUE(observer()->CheckEvents(TrackingEvent(REMOVED, "alpha")));
    318 }
    319 
    320 TEST_F(AccountTrackerServiceTest, TokenAvailable_UserInfoFailed) {
    321   SimulateTokenAvailable("alpha");
    322   ReturnOAuthUrlFetchFailure("alpha");
    323   ASSERT_TRUE(account_tracker()->IsAllUserInfoFetched());
    324   ASSERT_TRUE(observer()->CheckEvents());
    325 }
    326 
    327 TEST_F(AccountTrackerServiceTest, TokenAlreadyExists) {
    328   SimulateTokenAvailable("alpha");
    329   AccountTrackerService tracker;
    330   AccountTrackerObserver observer;
    331   tracker.AddObserver(&observer);
    332   tracker.Initialize(token_service(),
    333                      pref_service(),
    334                      new net::TestURLRequestContextGetter(
    335                          message_loop()->message_loop_proxy()));
    336   ASSERT_FALSE(tracker.IsAllUserInfoFetched());
    337   ASSERT_TRUE(observer.CheckEvents());
    338   tracker.RemoveObserver(&observer);
    339   tracker.Shutdown();
    340 }
    341 
    342 TEST_F(AccountTrackerServiceTest, TwoTokenAvailable_TwoUserInfo) {
    343   SimulateTokenAvailable("alpha");
    344   SimulateTokenAvailable("beta");
    345   ReturnOAuthUrlFetchSuccess("alpha");
    346   ReturnOAuthUrlFetchSuccess("beta");
    347   ASSERT_TRUE(account_tracker()->IsAllUserInfoFetched());
    348   ASSERT_TRUE(observer()->CheckEvents(TrackingEvent(UPDATED, "alpha"),
    349                                       TrackingEvent(UPDATED, "beta")));
    350 }
    351 
    352 TEST_F(AccountTrackerServiceTest, TwoTokenAvailable_OneUserInfo) {
    353   SimulateTokenAvailable("alpha");
    354   SimulateTokenAvailable("beta");
    355   ReturnOAuthUrlFetchSuccess("beta");
    356   ASSERT_FALSE(account_tracker()->IsAllUserInfoFetched());
    357   ASSERT_TRUE(observer()->CheckEvents(TrackingEvent(UPDATED, "beta")));
    358   ReturnOAuthUrlFetchSuccess("alpha");
    359   ASSERT_TRUE(account_tracker()->IsAllUserInfoFetched());
    360   ASSERT_TRUE(observer()->CheckEvents(TrackingEvent(UPDATED, "alpha")));
    361 }
    362 
    363 TEST_F(AccountTrackerServiceTest, GetAccounts) {
    364   SimulateTokenAvailable("alpha");
    365   SimulateTokenAvailable("beta");
    366   SimulateTokenAvailable("gamma");
    367   ReturnOAuthUrlFetchSuccess("alpha");
    368   ReturnOAuthUrlFetchSuccess("beta");
    369   ReturnOAuthUrlFetchSuccess("gamma");
    370 
    371   std::vector<AccountTrackerService::AccountInfo> infos =
    372       account_tracker()->GetAccounts();
    373 
    374   EXPECT_EQ(3u, infos.size());
    375   EXPECT_EQ("alpha", infos[0].account_id);
    376   EXPECT_EQ(AccountIdToGaiaId("alpha"), infos[0].gaia);
    377   EXPECT_EQ(AccountIdToEmail("alpha"), infos[0].email);
    378   EXPECT_EQ("beta", infos[1].account_id);
    379   EXPECT_EQ(AccountIdToGaiaId("beta"), infos[1].gaia);
    380   EXPECT_EQ(AccountIdToEmail("beta"), infos[1].email);
    381   EXPECT_EQ("gamma", infos[2].account_id);
    382   EXPECT_EQ(AccountIdToGaiaId("gamma"), infos[2].gaia);
    383   EXPECT_EQ(AccountIdToEmail("gamma"), infos[2].email);
    384 }
    385 
    386 TEST_F(AccountTrackerServiceTest, GetAccountInfo_Empty) {
    387   AccountTrackerService::AccountInfo info =
    388       account_tracker()->GetAccountInfo("alpha");
    389   ASSERT_EQ("", info.account_id);
    390 }
    391 
    392 TEST_F(AccountTrackerServiceTest, GetAccountInfo_TokenAvailable) {
    393   SimulateTokenAvailable("alpha");
    394   AccountTrackerService::AccountInfo info =
    395       account_tracker()->GetAccountInfo("alpha");
    396   ASSERT_EQ("alpha", info.account_id);
    397   ASSERT_EQ("", info.gaia);
    398   ASSERT_EQ("", info.email);
    399 }
    400 
    401 TEST_F(AccountTrackerServiceTest, GetAccountInfo_TokenAvailable_UserInfo) {
    402   SimulateTokenAvailable("alpha");
    403   ReturnOAuthUrlFetchSuccess("alpha");
    404   AccountTrackerService::AccountInfo info =
    405       account_tracker()->GetAccountInfo("alpha");
    406   ASSERT_EQ("alpha", info.account_id);
    407   ASSERT_EQ(AccountIdToGaiaId("alpha"), info.gaia);
    408   ASSERT_EQ(AccountIdToEmail("alpha"), info.email);
    409 }
    410 
    411 TEST_F(AccountTrackerServiceTest, FindAccountInfoByGaiaId) {
    412   SimulateTokenAvailable("alpha");
    413   ReturnOAuthUrlFetchSuccess("alpha");
    414 
    415   std::string gaia_id = AccountIdToGaiaId("alpha");
    416   AccountTrackerService::AccountInfo info =
    417       account_tracker()->FindAccountInfoByGaiaId(gaia_id);
    418   ASSERT_EQ("alpha", info.account_id);
    419   ASSERT_EQ(gaia_id, info.gaia);
    420 
    421   gaia_id = AccountIdToGaiaId("beta");
    422   info = account_tracker()->FindAccountInfoByGaiaId(gaia_id);
    423   ASSERT_EQ("", info.account_id);
    424 }
    425 
    426 TEST_F(AccountTrackerServiceTest, FindAccountInfoByEmail) {
    427   SimulateTokenAvailable("alpha");
    428   ReturnOAuthUrlFetchSuccess("alpha");
    429 
    430   std::string email = AccountIdToEmail("alpha");
    431   AccountTrackerService::AccountInfo info =
    432       account_tracker()->FindAccountInfoByEmail(email);
    433   ASSERT_EQ("alpha", info.account_id);
    434   ASSERT_EQ(email, info.email);
    435 
    436   // Should also work with "canonically-equal" email addresses.
    437   info = account_tracker()->FindAccountInfoByEmail("Alpha (at) Gmail.COM");
    438   ASSERT_EQ("alpha", info.account_id);
    439   ASSERT_EQ(email, info.email);
    440   info = account_tracker()->FindAccountInfoByEmail("al.pha (at) gmail.com");
    441   ASSERT_EQ("alpha", info.account_id);
    442   ASSERT_EQ(email, info.email);
    443 
    444   email = AccountIdToEmail("beta");
    445   info = account_tracker()->FindAccountInfoByEmail(email);
    446   ASSERT_EQ("", info.account_id);
    447 }
    448 
    449 TEST_F(AccountTrackerServiceTest, Persistence) {
    450   // Create a tracker and add two accounts.  This should cause the accounts
    451   // to be saved to persistence.
    452   {
    453     AccountTrackerService tracker;
    454     tracker.Initialize(token_service(),
    455                        pref_service(),
    456                        new net::TestURLRequestContextGetter(
    457                            message_loop()->message_loop_proxy()));
    458     SimulateTokenAvailable("alpha");
    459     ReturnOAuthUrlFetchSuccess("alpha");
    460     SimulateTokenAvailable("beta");
    461     ReturnOAuthUrlFetchSuccess("beta");
    462     tracker.Shutdown();
    463   }
    464 
    465   // Create a new tracker and make sure it loads the accounts corectly from
    466   // persistence.
    467   {
    468     AccountTrackerService tracker;
    469     tracker.AddObserver(observer());
    470     tracker.Initialize(token_service(),
    471                        pref_service(),
    472                        new net::TestURLRequestContextGetter(
    473                            message_loop()->message_loop_proxy()));
    474     ASSERT_TRUE(observer()->CheckEvents(TrackingEvent(UPDATED, "alpha"),
    475                                         TrackingEvent(UPDATED, "beta")));
    476 
    477     std::vector<AccountTrackerService::AccountInfo> infos =
    478         tracker.GetAccounts();
    479     ASSERT_EQ(2u, infos.size());
    480     EXPECT_EQ(AccountIdToGaiaId("alpha"), infos[0].gaia);
    481     EXPECT_EQ(AccountIdToEmail("alpha"), infos[0].email);
    482     EXPECT_EQ("beta", infos[1].account_id);
    483     EXPECT_EQ(AccountIdToGaiaId("beta"), infos[1].gaia);
    484     EXPECT_EQ(AccountIdToEmail("beta"), infos[1].email);
    485 
    486     // Remove account.
    487     SimulateTokenRevoked("alpha");
    488     tracker.RemoveObserver(observer());
    489     tracker.Shutdown();
    490  }
    491 
    492   // Create a new tracker and make sure it loads the single account from
    493   // persistence.
    494   {
    495     AccountTrackerService tracker;
    496     tracker.Initialize(token_service(),
    497                        pref_service(),
    498                        new net::TestURLRequestContextGetter(
    499                            message_loop()->message_loop_proxy()));
    500 
    501     std::vector<AccountTrackerService::AccountInfo> infos =
    502         tracker.GetAccounts();
    503     ASSERT_EQ(1u, infos.size());
    504     EXPECT_EQ("beta", infos[0].account_id);
    505     EXPECT_EQ(AccountIdToGaiaId("beta"), infos[0].gaia);
    506     EXPECT_EQ(AccountIdToEmail("beta"), infos[0].email);
    507     tracker.Shutdown();
    508   }
    509 }
    510