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: 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() { 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 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 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 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 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 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 231 TEST_F(OnlineAttemptTest, LoginNetFailure) { 232 RunFailureTest( 233 GoogleServiceAuthError::FromConnectionError(net::ERR_CONNECTION_RESET)); 234 } 235 236 TEST_F(OnlineAttemptTest, LoginDenied) { 237 RunFailureTest( 238 GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS)); 239 } 240 241 TEST_F(OnlineAttemptTest, LoginAccountDisabled) { 242 RunFailureTest( 243 GoogleServiceAuthError(GoogleServiceAuthError::ACCOUNT_DISABLED)); 244 } 245 246 TEST_F(OnlineAttemptTest, LoginAccountDeleted) { 247 RunFailureTest( 248 GoogleServiceAuthError(GoogleServiceAuthError::ACCOUNT_DELETED)); 249 } 250 251 TEST_F(OnlineAttemptTest, LoginServiceUnavailable) { 252 RunFailureTest( 253 GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE)); 254 } 255 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 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