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 <string> 6 7 #include "base/bind.h" 8 #include "base/memory/ref_counted.h" 9 #include "base/run_loop.h" 10 #include "chrome/browser/chromeos/cros/network_library.h" 11 #include "chrome/browser/chromeos/login/auth_attempt_state.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/online_attempt.h" 15 #include "chrome/browser/chromeos/login/test_attempt_state.h" 16 #include "chrome/browser/chromeos/login/user.h" 17 #include "chrome/test/base/testing_profile.h" 18 #include "content/public/browser/browser_thread.h" 19 #include "content/public/test/test_browser_thread_bundle.h" 20 #include "google_apis/gaia/gaia_auth_consumer.h" 21 #include "google_apis/gaia/mock_url_fetcher_factory.h" 22 #include "testing/gmock/include/gmock/gmock.h" 23 #include "testing/gtest/include/gtest/gtest.h" 24 #include "url/gurl.h" 25 26 using ::testing::AnyNumber; 27 using ::testing::Invoke; 28 using ::testing::Return; 29 using ::testing::_; 30 using content::BrowserThread; 31 32 namespace chromeos { 33 34 class OnlineAttemptTest : public testing::Test { 35 public: 36 OnlineAttemptTest() 37 : state_(UserContext(), "", "", "", User::USER_TYPE_REGULAR, false), 38 attempt_(new OnlineAttempt(&state_, &resolver_)) { 39 } 40 41 void RunFailureTest(const GoogleServiceAuthError& error) { 42 EXPECT_CALL(resolver_, Resolve()) 43 .Times(1) 44 .RetiresOnSaturation(); 45 46 BrowserThread::PostTask( 47 BrowserThread::UI, FROM_HERE, 48 base::Bind(&OnlineAttempt::OnClientLoginFailure, 49 attempt_->weak_factory_.GetWeakPtr(), 50 error)); 51 // Force UI thread to finish tasks so I can verify |state_|. 52 base::RunLoop().RunUntilIdle(); 53 EXPECT_TRUE(error == state_.online_outcome().error()); 54 } 55 56 void CancelLogin(OnlineAttempt* auth) { 57 BrowserThread::PostTask( 58 BrowserThread::UI, FROM_HERE, 59 base::Bind(&OnlineAttempt::CancelClientLogin, 60 auth->weak_factory_.GetWeakPtr())); 61 } 62 63 content::TestBrowserThreadBundle thread_bundle_; 64 TestAttemptState state_; 65 MockAuthAttemptStateResolver resolver_; 66 scoped_ptr<OnlineAttempt> attempt_; 67 68 // Initializes / shuts down a stub NetworkLibrary. 69 ScopedStubNetworkLibraryEnabler stub_network_library_enabler_; 70 }; 71 72 TEST_F(OnlineAttemptTest, LoginSuccess) { 73 EXPECT_CALL(resolver_, Resolve()) 74 .Times(1) 75 .RetiresOnSaturation(); 76 77 BrowserThread::PostTask( 78 BrowserThread::UI, FROM_HERE, 79 base::Bind(&OnlineAttempt::OnClientLoginSuccess, 80 attempt_->weak_factory_.GetWeakPtr(), 81 GaiaAuthConsumer::ClientLoginResult())); 82 // Force UI thread to finish tasks so I can verify |state_|. 83 base::RunLoop().RunUntilIdle(); 84 } 85 86 TEST_F(OnlineAttemptTest, LoginCancelRetry) { 87 GoogleServiceAuthError error(GoogleServiceAuthError::REQUEST_CANCELED); 88 TestingProfile profile; 89 90 base::RunLoop run_loop; 91 EXPECT_CALL(resolver_, Resolve()) 92 .WillOnce(Invoke(&run_loop, &base::RunLoop::Quit)) 93 .RetiresOnSaturation(); 94 95 // This is how we inject fake URLFetcher objects, with a factory. 96 // This factory creates fake URLFetchers that Start() a fake fetch attempt 97 // and then come back on the UI thread saying they've been canceled. 98 MockURLFetcherFactory<GotCanceledFetcher> factory; 99 100 attempt_->Initiate(&profile); 101 102 run_loop.Run(); 103 104 EXPECT_TRUE(error == state_.online_outcome().error()); 105 EXPECT_EQ(LoginFailure::NETWORK_AUTH_FAILED, 106 state_.online_outcome().reason()); 107 } 108 109 TEST_F(OnlineAttemptTest, LoginTimeout) { 110 LoginFailure error(LoginFailure::LOGIN_TIMED_OUT); 111 TestingProfile profile; 112 113 base::RunLoop run_loop; 114 EXPECT_CALL(resolver_, Resolve()) 115 .WillOnce(Invoke(&run_loop, &base::RunLoop::Quit)) 116 .RetiresOnSaturation(); 117 118 // This is how we inject fake URLFetcher objects, with a factory. 119 // This factory creates fake URLFetchers that Start() a fake fetch attempt 120 // and then come back on the UI thread saying they've been canceled. 121 MockURLFetcherFactory<ExpectCanceledFetcher> factory; 122 123 attempt_->Initiate(&profile); 124 125 // Post a task to cancel the login attempt. 126 CancelLogin(attempt_.get()); 127 128 run_loop.Run(); 129 130 EXPECT_EQ(LoginFailure::LOGIN_TIMED_OUT, state_.online_outcome().reason()); 131 } 132 133 TEST_F(OnlineAttemptTest, HostedLoginRejected) { 134 LoginFailure error( 135 LoginFailure::FromNetworkAuthFailure( 136 GoogleServiceAuthError( 137 GoogleServiceAuthError::HOSTED_NOT_ALLOWED))); 138 TestingProfile profile; 139 140 base::RunLoop run_loop; 141 EXPECT_CALL(resolver_, Resolve()) 142 .WillOnce(Invoke(&run_loop, &base::RunLoop::Quit)) 143 .RetiresOnSaturation(); 144 145 // This is how we inject fake URLFetcher objects, with a factory. 146 MockURLFetcherFactory<HostedFetcher> factory; 147 148 TestAttemptState local_state(UserContext(), "", "", "", 149 User::USER_TYPE_REGULAR, true); 150 attempt_.reset(new OnlineAttempt(&local_state, &resolver_)); 151 attempt_->Initiate(&profile); 152 153 run_loop.Run(); 154 155 EXPECT_EQ(error, local_state.online_outcome()); 156 EXPECT_EQ(LoginFailure::NETWORK_AUTH_FAILED, 157 local_state.online_outcome().reason()); 158 } 159 160 TEST_F(OnlineAttemptTest, FullLogin) { 161 TestingProfile profile; 162 163 base::RunLoop run_loop; 164 EXPECT_CALL(resolver_, Resolve()) 165 .WillOnce(Invoke(&run_loop, &base::RunLoop::Quit)) 166 .RetiresOnSaturation(); 167 168 // This is how we inject fake URLFetcher objects, with a factory. 169 MockURLFetcherFactory<SuccessFetcher> factory; 170 171 TestAttemptState local_state(UserContext(), "", "", "", 172 User::USER_TYPE_REGULAR, true); 173 attempt_.reset(new OnlineAttempt(&local_state, &resolver_)); 174 attempt_->Initiate(&profile); 175 176 run_loop.Run(); 177 178 EXPECT_EQ(LoginFailure::LoginFailureNone(), local_state.online_outcome()); 179 } 180 181 TEST_F(OnlineAttemptTest, LoginNetFailure) { 182 RunFailureTest( 183 GoogleServiceAuthError::FromConnectionError(net::ERR_CONNECTION_RESET)); 184 } 185 186 TEST_F(OnlineAttemptTest, LoginDenied) { 187 RunFailureTest( 188 GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS)); 189 } 190 191 TEST_F(OnlineAttemptTest, LoginAccountDisabled) { 192 RunFailureTest( 193 GoogleServiceAuthError(GoogleServiceAuthError::ACCOUNT_DISABLED)); 194 } 195 196 TEST_F(OnlineAttemptTest, LoginAccountDeleted) { 197 RunFailureTest( 198 GoogleServiceAuthError(GoogleServiceAuthError::ACCOUNT_DELETED)); 199 } 200 201 TEST_F(OnlineAttemptTest, LoginServiceUnavailable) { 202 RunFailureTest( 203 GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE)); 204 } 205 206 TEST_F(OnlineAttemptTest, CaptchaErrorOutputted) { 207 GoogleServiceAuthError auth_error = 208 GoogleServiceAuthError::FromClientLoginCaptchaChallenge( 209 "CCTOKEN", 210 GURL("http://accounts.google.com/Captcha?ctoken=CCTOKEN"), 211 GURL("http://www.google.com/login/captcha")); 212 RunFailureTest(auth_error); 213 } 214 215 TEST_F(OnlineAttemptTest, TwoFactorSuccess) { 216 EXPECT_CALL(resolver_, Resolve()) 217 .Times(1) 218 .RetiresOnSaturation(); 219 GoogleServiceAuthError error(GoogleServiceAuthError::TWO_FACTOR); 220 BrowserThread::PostTask( 221 BrowserThread::UI, FROM_HERE, 222 base::Bind(&OnlineAttempt::OnClientLoginFailure, 223 attempt_->weak_factory_.GetWeakPtr(), 224 error)); 225 226 // Force UI thread to finish tasks so I can verify |state_|. 227 base::RunLoop().RunUntilIdle(); 228 EXPECT_TRUE(GoogleServiceAuthError::AuthErrorNone() == 229 state_.online_outcome().error()); 230 } 231 232 } // namespace chromeos 233