online_attempt_unittest.cc revision 21d179b334e59e9a3bfcaed4c4430bef1bc5759d
1// Copyright (c) 2010 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 <string>
6
7#include "base/message_loop.h"
8#include "base/ref_counted.h"
9#include "chrome/browser/browser_thread.h"
10#include "chrome/browser/chromeos/cros/mock_library_loader.h"
11#include "chrome/browser/chromeos/login/auth_attempt_state.h"
12#include "chrome/browser/chromeos/login/online_attempt.h"
13#include "chrome/browser/chromeos/login/mock_auth_attempt_state_resolver.h"
14#include "chrome/browser/chromeos/login/mock_url_fetchers.h"
15#include "chrome/browser/chromeos/login/test_attempt_state.h"
16#include "chrome/common/net/gaia/gaia_auth_consumer.h"
17#include "chrome/common/net/gaia/gaia_auth_fetcher_unittest.h"
18#include "chrome/test/testing_profile.h"
19#include "googleurl/src/gurl.h"
20#include "testing/gmock/include/gmock/gmock.h"
21#include "testing/gtest/include/gtest/gtest.h"
22
23using ::testing::AnyNumber;
24using ::testing::Invoke;
25using ::testing::Return;
26using ::testing::_;
27
28namespace chromeos {
29
30class OnlineAttemptTest : public ::testing::Test {
31 public:
32  OnlineAttemptTest()
33      : message_loop_(MessageLoop::TYPE_UI),
34        ui_thread_(BrowserThread::UI, &message_loop_),
35        io_thread_(BrowserThread::IO),
36        state_("", "", "", "", "", false),
37        resolver_(new MockAuthAttemptStateResolver) {
38  }
39
40  virtual ~OnlineAttemptTest() {}
41
42  virtual void SetUp() {
43    CrosLibrary::TestApi* test_api = CrosLibrary::Get()->GetTestApi();
44
45    MockLibraryLoader* loader = new MockLibraryLoader();
46    ON_CALL(*loader, Load(_))
47        .WillByDefault(Return(true));
48    EXPECT_CALL(*loader, Load(_))
49        .Times(AnyNumber());
50
51    // Passes ownership of |loader| to CrosLibrary.
52    test_api->SetLibraryLoader(loader, true);
53
54    attempt_ = new OnlineAttempt(&state_, resolver_.get());
55
56    io_thread_.Start();
57  }
58
59  virtual void TearDown() {
60    // Prevent bogus gMock leak check from firing.
61    chromeos::CrosLibrary::TestApi* test_api =
62        chromeos::CrosLibrary::Get()->GetTestApi();
63    test_api->SetLibraryLoader(NULL, false);
64  }
65
66  void RunFailureTest(const GoogleServiceAuthError& error) {
67    EXPECT_CALL(*(resolver_.get()), Resolve())
68        .Times(1)
69        .RetiresOnSaturation();
70
71    BrowserThread::PostTask(
72        BrowserThread::IO, FROM_HERE,
73        NewRunnableMethod(attempt_.get(),
74                          &OnlineAttempt::OnClientLoginFailure,
75                          error));
76    // Force IO thread to finish tasks so I can verify |state_|.
77    io_thread_.Stop();
78    EXPECT_TRUE(error == state_.online_outcome().error());
79  }
80
81  void CancelLogin(OnlineAttempt* auth) {
82    BrowserThread::PostTask(
83        BrowserThread::IO,
84        FROM_HERE,
85        NewRunnableMethod(auth,
86                          &OnlineAttempt::CancelClientLogin));
87  }
88
89  static void Quit() {
90    BrowserThread::PostTask(
91        BrowserThread::UI, FROM_HERE, new MessageLoop::QuitTask());
92  }
93
94  static void RunThreadTest(OnlineAttempt* attempt, Profile* profile) {
95    attempt->Initiate(profile);
96    MessageLoop::current()->RunAllPending();
97  }
98
99  MessageLoop message_loop_;
100  BrowserThread ui_thread_;
101  BrowserThread io_thread_;
102  TestAttemptState state_;
103  scoped_ptr<MockAuthAttemptStateResolver> resolver_;
104  scoped_refptr<OnlineAttempt> attempt_;
105};
106
107TEST_F(OnlineAttemptTest, LoginSuccess) {
108  GaiaAuthConsumer::ClientLoginResult result;
109  EXPECT_CALL(*(resolver_.get()), Resolve())
110      .Times(1)
111      .RetiresOnSaturation();
112
113  BrowserThread::PostTask(
114      BrowserThread::IO, FROM_HERE,
115      NewRunnableMethod(attempt_.get(),
116                        &OnlineAttempt::OnClientLoginSuccess,
117                        result));
118  // Force IO thread to finish tasks so I can verify |state_|.
119  io_thread_.Stop();
120  EXPECT_TRUE(result == state_.credentials());
121}
122
123TEST_F(OnlineAttemptTest, LoginCancelRetry) {
124  GoogleServiceAuthError error(GoogleServiceAuthError::REQUEST_CANCELED);
125  TestingProfile profile;
126
127  EXPECT_CALL(*(resolver_.get()), Resolve())
128      .WillOnce(Invoke(OnlineAttemptTest::Quit))
129      .RetiresOnSaturation();
130
131  // This is how we inject fake URLFetcher objects, with a factory.
132  // This factory creates fake URLFetchers that Start() a fake fetch attempt
133  // and then come back on the IO thread saying they've been canceled.
134  MockFactory<GotCanceledFetcher> factory;
135  URLFetcher::set_factory(&factory);
136
137  BrowserThread::PostTask(
138      BrowserThread::IO, FROM_HERE,
139      NewRunnableFunction(&OnlineAttemptTest::RunThreadTest,
140                          attempt_, &profile));
141
142  MessageLoop::current()->Run();
143
144  EXPECT_TRUE(error == state_.online_outcome().error());
145  EXPECT_EQ(LoginFailure::NETWORK_AUTH_FAILED,
146            state_.online_outcome().reason());
147  URLFetcher::set_factory(NULL);
148}
149
150TEST_F(OnlineAttemptTest, LoginTimeout) {
151  LoginFailure error(LoginFailure::LOGIN_TIMED_OUT);
152  TestingProfile profile;
153
154  EXPECT_CALL(*(resolver_.get()), Resolve())
155      .WillOnce(Invoke(OnlineAttemptTest::Quit))
156      .RetiresOnSaturation();
157
158  // This is how we inject fake URLFetcher objects, with a factory.
159  // This factory creates fake URLFetchers that Start() a fake fetch attempt
160  // and then come back on the IO thread saying they've been canceled.
161  MockFactory<ExpectCanceledFetcher> factory;
162  URLFetcher::set_factory(&factory);
163
164  BrowserThread::PostTask(
165      BrowserThread::IO, FROM_HERE,
166      NewRunnableFunction(&OnlineAttemptTest::RunThreadTest,
167                          attempt_, &profile));
168
169  // Post a task to cancel the login attempt.
170  CancelLogin(attempt_.get());
171
172  MessageLoop::current()->Run();
173
174  EXPECT_EQ(LoginFailure::LOGIN_TIMED_OUT, state_.online_outcome().reason());
175  URLFetcher::set_factory(NULL);
176}
177
178TEST_F(OnlineAttemptTest, HostedLoginRejected) {
179  LoginFailure error(
180      LoginFailure::FromNetworkAuthFailure(
181          GoogleServiceAuthError(
182              GoogleServiceAuthError::HOSTED_NOT_ALLOWED)));
183  TestingProfile profile;
184
185  EXPECT_CALL(*(resolver_.get()), Resolve())
186      .WillOnce(Invoke(OnlineAttemptTest::Quit))
187      .RetiresOnSaturation();
188
189  // This is how we inject fake URLFetcher objects, with a factory.
190  MockFactory<HostedFetcher> factory;
191  URLFetcher::set_factory(&factory);
192
193  TestAttemptState local_state("", "", "", "", "", true);
194  attempt_ = new OnlineAttempt(&local_state, resolver_.get());
195  BrowserThread::PostTask(
196      BrowserThread::IO, FROM_HERE,
197      NewRunnableFunction(&OnlineAttemptTest::RunThreadTest,
198                          attempt_, &profile));
199
200  MessageLoop::current()->Run();
201
202  EXPECT_EQ(error, local_state.online_outcome());
203  EXPECT_EQ(LoginFailure::NETWORK_AUTH_FAILED,
204            local_state.online_outcome().reason());
205  URLFetcher::set_factory(NULL);
206}
207
208TEST_F(OnlineAttemptTest, FullLogin) {
209  TestingProfile profile;
210
211  EXPECT_CALL(*(resolver_.get()), Resolve())
212      .WillOnce(Invoke(OnlineAttemptTest::Quit))
213      .RetiresOnSaturation();
214
215  // This is how we inject fake URLFetcher objects, with a factory.
216  MockFactory<SuccessFetcher> factory;
217  URLFetcher::set_factory(&factory);
218
219  TestAttemptState local_state("", "", "", "", "", true);
220  attempt_ = new OnlineAttempt(&local_state, resolver_.get());
221  BrowserThread::PostTask(
222      BrowserThread::IO, FROM_HERE,
223      NewRunnableFunction(&OnlineAttemptTest::RunThreadTest,
224                          attempt_, &profile));
225
226  MessageLoop::current()->Run();
227
228  EXPECT_EQ(LoginFailure::None(), local_state.online_outcome());
229  URLFetcher::set_factory(NULL);
230}
231
232TEST_F(OnlineAttemptTest, LoginNetFailure) {
233  RunFailureTest(
234      GoogleServiceAuthError::FromConnectionError(net::ERR_CONNECTION_RESET));
235}
236
237TEST_F(OnlineAttemptTest, LoginDenied) {
238  RunFailureTest(
239      GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
240}
241
242TEST_F(OnlineAttemptTest, LoginAccountDisabled) {
243  RunFailureTest(
244      GoogleServiceAuthError(GoogleServiceAuthError::ACCOUNT_DISABLED));
245}
246
247TEST_F(OnlineAttemptTest, LoginAccountDeleted) {
248  RunFailureTest(
249      GoogleServiceAuthError(GoogleServiceAuthError::ACCOUNT_DELETED));
250}
251
252TEST_F(OnlineAttemptTest, LoginServiceUnavailable) {
253  RunFailureTest(
254      GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE));
255}
256
257TEST_F(OnlineAttemptTest, CaptchaErrorOutputted) {
258  GoogleServiceAuthError auth_error =
259      GoogleServiceAuthError::FromCaptchaChallenge(
260          "CCTOKEN",
261          GURL("http://www.google.com/accounts/Captcha?ctoken=CCTOKEN"),
262          GURL("http://www.google.com/login/captcha"));
263  RunFailureTest(auth_error);
264}
265
266TEST_F(OnlineAttemptTest, TwoFactorSuccess) {
267  EXPECT_CALL(*(resolver_.get()), Resolve())
268      .Times(1)
269      .RetiresOnSaturation();
270  GoogleServiceAuthError error(GoogleServiceAuthError::TWO_FACTOR);
271  BrowserThread::PostTask(
272      BrowserThread::IO, FROM_HERE,
273      NewRunnableMethod(attempt_.get(),
274                        &OnlineAttempt::OnClientLoginFailure,
275                        error));
276
277  // Force IO thread to finish tasks so I can verify |state_|.
278  io_thread_.Stop();
279  EXPECT_TRUE(GoogleServiceAuthError::None() ==
280              state_.online_outcome().error());
281  EXPECT_TRUE(GaiaAuthConsumer::ClientLoginResult() == state_.credentials());
282}
283
284}  // namespace chromeos
285