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