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
28using ::testing::_;
29using ::testing::AnyNumber;
30using ::testing::Mock;
31using ::testing::Return;
32using ::testing::ReturnRef;
33
34namespace {
35
36class MockTokenService : public TokenService {
37 public:
38  MockTokenService() { }
39  virtual ~MockTokenService() { }
40
41  MOCK_CONST_METHOD1(HasTokenForService, bool(const char*));
42};
43
44BrowserContextKeyedService* BuildMockTokenService(
45    content::BrowserContext* profile) {
46  return new MockTokenService;
47}
48
49class 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
60class 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@gmail.com");
82    GoogleServiceSigninSuccessDetails details("username@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
97TEST_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
108TEST_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
117TEST_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
131TEST_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
154TEST_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