Home | History | Annotate | Download | only in signin
      1 // Copyright (c) 2012 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/signin/signin_tracker.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/bind_helpers.h"
      9 #include "base/compiler_specific.h"
     10 #include "chrome/browser/chrome_notification_types.h"
     11 #include "chrome/browser/profiles/profile.h"
     12 #include "chrome/browser/signin/fake_auth_status_provider.h"
     13 #include "chrome/browser/signin/fake_signin_manager.h"
     14 #include "chrome/browser/signin/signin_manager.h"
     15 #include "chrome/browser/signin/signin_manager_factory.h"
     16 #include "chrome/browser/signin/token_service.h"
     17 #include "chrome/browser/signin/token_service_factory.h"
     18 #include "chrome/browser/sync/profile_sync_service_factory.h"
     19 #include "chrome/browser/sync/profile_sync_service_mock.h"
     20 #include "content/public/browser/notification_service.h"
     21 #include "content/public/test/test_browser_thread_bundle.h"
     22 #include "google_apis/gaia/gaia_constants.h"
     23 #include "google_apis/gaia/google_service_auth_error.h"
     24 
     25 #include "testing/gmock/include/gmock/gmock.h"
     26 #include "testing/gtest/include/gtest/gtest.h"
     27 
     28 using ::testing::_;
     29 using ::testing::AnyNumber;
     30 using ::testing::Mock;
     31 using ::testing::Return;
     32 using ::testing::ReturnRef;
     33 
     34 namespace {
     35 
     36 class MockTokenService : public TokenService {
     37  public:
     38   MockTokenService() { }
     39   virtual ~MockTokenService() { }
     40 
     41   MOCK_CONST_METHOD1(HasTokenForService, bool(const char*));
     42 };
     43 
     44 BrowserContextKeyedService* BuildMockTokenService(
     45     content::BrowserContext* profile) {
     46   return new MockTokenService;
     47 }
     48 
     49 class MockObserver : public SigninTracker::Observer {
     50  public:
     51   MockObserver() {}
     52   ~MockObserver() {}
     53 
     54   MOCK_METHOD1(SigninFailed, void(const GoogleServiceAuthError&));
     55   MOCK_METHOD0(SigninSuccess, void(void));
     56 };
     57 
     58 }  // namespace
     59 
     60 class SigninTrackerTest : public testing::Test {
     61  public:
     62   SigninTrackerTest() {}
     63   virtual void SetUp() OVERRIDE {
     64     profile_.reset(new TestingProfile());
     65     mock_token_service_ = static_cast<MockTokenService*>(
     66         TokenServiceFactory::GetInstance()->SetTestingFactoryAndUse(
     67             profile_.get(), BuildMockTokenService));
     68 
     69     mock_signin_manager_ = static_cast<FakeSigninManagerBase*>(
     70         SigninManagerFactory::GetInstance()->SetTestingFactoryAndUse(
     71             profile_.get(), FakeSigninManagerBase::Build));
     72     mock_signin_manager_->Initialize(profile_.get(), NULL);
     73     tracker_.reset(new SigninTracker(profile_.get(), &observer_));
     74   }
     75   virtual void TearDown() OVERRIDE {
     76     tracker_.reset();
     77     profile_.reset();
     78   }
     79 
     80   void SendSigninSuccessful() {
     81     mock_signin_manager_->SetAuthenticatedUsername("username (at) gmail.com");
     82     GoogleServiceSigninSuccessDetails details("username (at) gmail.com", "password");
     83     content::NotificationService::current()->Notify(
     84         chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL,
     85         content::Source<Profile>(profile_.get()),
     86         content::Details<const GoogleServiceSigninSuccessDetails>(&details));
     87   }
     88 
     89   content::TestBrowserThreadBundle thread_bundle_;
     90   scoped_ptr<SigninTracker> tracker_;
     91   scoped_ptr<TestingProfile> profile_;
     92   FakeSigninManagerBase* mock_signin_manager_;
     93   MockTokenService* mock_token_service_;
     94   MockObserver observer_;
     95 };
     96 
     97 TEST_F(SigninTrackerTest, GaiaSignInFailed) {
     98   // SIGNIN_FAILED notification should result in a SigninFailed callback.
     99   GoogleServiceAuthError error(
    100       GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
    101   EXPECT_CALL(observer_, SigninFailed(error));
    102   content::NotificationService::current()->Notify(
    103       chrome::NOTIFICATION_GOOGLE_SIGNIN_FAILED,
    104       content::Source<Profile>(profile_.get()),
    105       content::Details<const GoogleServiceAuthError>(&error));
    106 }
    107 
    108 TEST_F(SigninTrackerTest, GaiaSignInSucceeded) {
    109   // SIGNIN_SUCCEEDED notification should lead us to get a SigninSuccess()
    110   // callback.
    111   EXPECT_CALL(observer_, SigninSuccess());
    112   EXPECT_CALL(*mock_token_service_, HasTokenForService(_))
    113       .WillRepeatedly(Return(true));
    114   SendSigninSuccessful();
    115 }
    116 
    117 TEST_F(SigninTrackerTest, NoGaiaSigninWhenOAuthTokensNotAvailable) {
    118   // SIGNIN_SUCCESSFUL notification should not result in a SigninSuccess()
    119   // callback if our oauth token hasn't been fetched.
    120   EXPECT_CALL(observer_, SigninSuccess()).Times(0);
    121   EXPECT_CALL(observer_, SigninFailed(_)).Times(0);
    122   EXPECT_CALL(*mock_token_service_,
    123               HasTokenForService(GaiaConstants::kSyncService))
    124       .WillRepeatedly(Return(true));
    125   EXPECT_CALL(*mock_token_service_,
    126               HasTokenForService(GaiaConstants::kGaiaOAuth2LoginRefreshToken))
    127       .WillRepeatedly(Return(false));
    128   SendSigninSuccessful();
    129 }
    130 
    131 TEST_F(SigninTrackerTest, GaiaSigninAfterOAuthTokenBecomesAvailable) {
    132   // SIGNIN_SUCCESSFUL notification should not result in a SigninSuccess()
    133   // callback until after our oauth token has been fetched.
    134   EXPECT_CALL(observer_, SigninSuccess()).Times(0);
    135   EXPECT_CALL(*mock_token_service_,
    136               HasTokenForService(GaiaConstants::kSyncService))
    137       .WillRepeatedly(Return(true));
    138   EXPECT_CALL(*mock_token_service_,
    139               HasTokenForService(GaiaConstants::kGaiaOAuth2LoginRefreshToken))
    140       .WillRepeatedly(Return(false));
    141   SendSigninSuccessful();
    142   Mock::VerifyAndClearExpectations(mock_token_service_);
    143   EXPECT_CALL(observer_, SigninSuccess());
    144   TokenService::TokenAvailableDetails available(
    145       GaiaConstants::kGaiaOAuth2LoginRefreshToken, "foo_token");
    146   EXPECT_CALL(*mock_token_service_, HasTokenForService(_))
    147       .WillRepeatedly(Return(true));
    148   content::NotificationService::current()->Notify(
    149       chrome::NOTIFICATION_TOKEN_AVAILABLE,
    150       content::Source<TokenService>(mock_token_service_),
    151       content::Details<const TokenService::TokenAvailableDetails>(&available));
    152 }
    153 
    154 TEST_F(SigninTrackerTest, SigninFailedWhenTokenFetchFails) {
    155   // TOKEN_REQUEST_FAILED notification should result in SigninFailed() callback.
    156   // We should not get any SigninFailed() callbacks until we issue the
    157   // TOKEN_REQUEST_FAILED notification.
    158   EXPECT_CALL(observer_, SigninFailed(_)).Times(0);
    159   EXPECT_CALL(*mock_token_service_,
    160               HasTokenForService(GaiaConstants::kSyncService))
    161       .WillRepeatedly(Return(true));
    162   EXPECT_CALL(*mock_token_service_,
    163               HasTokenForService(GaiaConstants::kGaiaOAuth2LoginRefreshToken))
    164       .WillRepeatedly(Return(false));
    165   SendSigninSuccessful();
    166 
    167   Mock::VerifyAndClearExpectations(&observer_);
    168   GoogleServiceAuthError error(
    169       GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
    170   EXPECT_CALL(observer_, SigninFailed(error));
    171   TokenService::TokenRequestFailedDetails failed(
    172       GaiaConstants::kGaiaOAuth2LoginRefreshToken, error);
    173   content::NotificationService::current()->Notify(
    174       chrome::NOTIFICATION_TOKEN_REQUEST_FAILED,
    175       content::Source<TokenService>(mock_token_service_),
    176       content::Details<const TokenService::TokenRequestFailedDetails>(&failed));
    177 }
    178