// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include <string> #include "base/memory/ref_counted.h" #include "base/message_loop.h" #include "chrome/browser/chromeos/cros/mock_library_loader.h" #include "chrome/browser/chromeos/login/auth_attempt_state.h" #include "chrome/browser/chromeos/login/online_attempt.h" #include "chrome/browser/chromeos/login/mock_auth_attempt_state_resolver.h" #include "chrome/browser/chromeos/login/mock_url_fetchers.h" #include "chrome/browser/chromeos/login/test_attempt_state.h" #include "chrome/common/net/gaia/gaia_auth_consumer.h" #include "chrome/common/net/gaia/gaia_auth_fetcher_unittest.h" #include "chrome/test/testing_profile.h" #include "content/browser/browser_thread.h" #include "googleurl/src/gurl.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" using ::testing::AnyNumber; using ::testing::Invoke; using ::testing::Return; using ::testing::_; namespace chromeos { class OnlineAttemptTest : public ::testing::Test { public: OnlineAttemptTest() : message_loop_(MessageLoop::TYPE_UI), ui_thread_(BrowserThread::UI, &message_loop_), io_thread_(BrowserThread::IO), state_("", "", "", "", "", false), resolver_(new MockAuthAttemptStateResolver) { } virtual ~OnlineAttemptTest() {} virtual void SetUp() { CrosLibrary::TestApi* test_api = CrosLibrary::Get()->GetTestApi(); MockLibraryLoader* loader = new MockLibraryLoader(); ON_CALL(*loader, Load(_)) .WillByDefault(Return(true)); EXPECT_CALL(*loader, Load(_)) .Times(AnyNumber()); // Passes ownership of |loader| to CrosLibrary. test_api->SetLibraryLoader(loader, true); attempt_ = new OnlineAttempt(&state_, resolver_.get()); io_thread_.Start(); } virtual void TearDown() { // Prevent bogus gMock leak check from firing. chromeos::CrosLibrary::TestApi* test_api = chromeos::CrosLibrary::Get()->GetTestApi(); test_api->SetLibraryLoader(NULL, false); } void RunFailureTest(const GoogleServiceAuthError& error) { EXPECT_CALL(*(resolver_.get()), Resolve()) .Times(1) .RetiresOnSaturation(); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, NewRunnableMethod(attempt_.get(), &OnlineAttempt::OnClientLoginFailure, error)); // Force IO thread to finish tasks so I can verify |state_|. io_thread_.Stop(); EXPECT_TRUE(error == state_.online_outcome().error()); } void CancelLogin(OnlineAttempt* auth) { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, NewRunnableMethod(auth, &OnlineAttempt::CancelClientLogin)); } static void Quit() { BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, new MessageLoop::QuitTask()); } static void RunThreadTest() { MessageLoop::current()->RunAllPending(); } MessageLoop message_loop_; BrowserThread ui_thread_; BrowserThread io_thread_; TestAttemptState state_; scoped_ptr<MockAuthAttemptStateResolver> resolver_; scoped_refptr<OnlineAttempt> attempt_; }; TEST_F(OnlineAttemptTest, LoginSuccess) { GaiaAuthConsumer::ClientLoginResult result; EXPECT_CALL(*(resolver_.get()), Resolve()) .Times(1) .RetiresOnSaturation(); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, NewRunnableMethod(attempt_.get(), &OnlineAttempt::OnClientLoginSuccess, result)); // Force IO thread to finish tasks so I can verify |state_|. io_thread_.Stop(); EXPECT_TRUE(result == state_.credentials()); } TEST_F(OnlineAttemptTest, LoginCancelRetry) { GoogleServiceAuthError error(GoogleServiceAuthError::REQUEST_CANCELED); TestingProfile profile; EXPECT_CALL(*(resolver_.get()), Resolve()) .WillOnce(Invoke(OnlineAttemptTest::Quit)) .RetiresOnSaturation(); // This is how we inject fake URLFetcher objects, with a factory. // This factory creates fake URLFetchers that Start() a fake fetch attempt // and then come back on the IO thread saying they've been canceled. MockFactory<GotCanceledFetcher> factory; URLFetcher::set_factory(&factory); attempt_->Initiate(&profile); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, NewRunnableFunction(&OnlineAttemptTest::RunThreadTest)); MessageLoop::current()->Run(); EXPECT_TRUE(error == state_.online_outcome().error()); EXPECT_EQ(LoginFailure::NETWORK_AUTH_FAILED, state_.online_outcome().reason()); URLFetcher::set_factory(NULL); } TEST_F(OnlineAttemptTest, LoginTimeout) { LoginFailure error(LoginFailure::LOGIN_TIMED_OUT); TestingProfile profile; EXPECT_CALL(*(resolver_.get()), Resolve()) .WillOnce(Invoke(OnlineAttemptTest::Quit)) .RetiresOnSaturation(); // This is how we inject fake URLFetcher objects, with a factory. // This factory creates fake URLFetchers that Start() a fake fetch attempt // and then come back on the IO thread saying they've been canceled. MockFactory<ExpectCanceledFetcher> factory; URLFetcher::set_factory(&factory); attempt_->Initiate(&profile); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, NewRunnableFunction(&OnlineAttemptTest::RunThreadTest)); // Post a task to cancel the login attempt. CancelLogin(attempt_.get()); MessageLoop::current()->Run(); EXPECT_EQ(LoginFailure::LOGIN_TIMED_OUT, state_.online_outcome().reason()); URLFetcher::set_factory(NULL); } TEST_F(OnlineAttemptTest, HostedLoginRejected) { LoginFailure error( LoginFailure::FromNetworkAuthFailure( GoogleServiceAuthError( GoogleServiceAuthError::HOSTED_NOT_ALLOWED))); TestingProfile profile; EXPECT_CALL(*(resolver_.get()), Resolve()) .WillOnce(Invoke(OnlineAttemptTest::Quit)) .RetiresOnSaturation(); // This is how we inject fake URLFetcher objects, with a factory. MockFactory<HostedFetcher> factory; URLFetcher::set_factory(&factory); TestAttemptState local_state("", "", "", "", "", true); attempt_ = new OnlineAttempt(&local_state, resolver_.get()); attempt_->Initiate(&profile); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, NewRunnableFunction(&OnlineAttemptTest::RunThreadTest)); MessageLoop::current()->Run(); EXPECT_EQ(error, local_state.online_outcome()); EXPECT_EQ(LoginFailure::NETWORK_AUTH_FAILED, local_state.online_outcome().reason()); URLFetcher::set_factory(NULL); } TEST_F(OnlineAttemptTest, FullLogin) { TestingProfile profile; EXPECT_CALL(*(resolver_.get()), Resolve()) .WillOnce(Invoke(OnlineAttemptTest::Quit)) .RetiresOnSaturation(); // This is how we inject fake URLFetcher objects, with a factory. MockFactory<SuccessFetcher> factory; URLFetcher::set_factory(&factory); TestAttemptState local_state("", "", "", "", "", true); attempt_ = new OnlineAttempt(&local_state, resolver_.get()); attempt_->Initiate(&profile); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, NewRunnableFunction(&OnlineAttemptTest::RunThreadTest)); MessageLoop::current()->Run(); EXPECT_EQ(LoginFailure::None(), local_state.online_outcome()); URLFetcher::set_factory(NULL); } TEST_F(OnlineAttemptTest, LoginNetFailure) { RunFailureTest( GoogleServiceAuthError::FromConnectionError(net::ERR_CONNECTION_RESET)); } TEST_F(OnlineAttemptTest, LoginDenied) { RunFailureTest( GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS)); } TEST_F(OnlineAttemptTest, LoginAccountDisabled) { RunFailureTest( GoogleServiceAuthError(GoogleServiceAuthError::ACCOUNT_DISABLED)); } TEST_F(OnlineAttemptTest, LoginAccountDeleted) { RunFailureTest( GoogleServiceAuthError(GoogleServiceAuthError::ACCOUNT_DELETED)); } TEST_F(OnlineAttemptTest, LoginServiceUnavailable) { RunFailureTest( GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE)); } TEST_F(OnlineAttemptTest, CaptchaErrorOutputted) { GoogleServiceAuthError auth_error = GoogleServiceAuthError::FromCaptchaChallenge( "CCTOKEN", GURL("http://www.google.com/accounts/Captcha?ctoken=CCTOKEN"), GURL("http://www.google.com/login/captcha")); RunFailureTest(auth_error); } TEST_F(OnlineAttemptTest, TwoFactorSuccess) { EXPECT_CALL(*(resolver_.get()), Resolve()) .Times(1) .RetiresOnSaturation(); GoogleServiceAuthError error(GoogleServiceAuthError::TWO_FACTOR); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, NewRunnableMethod(attempt_.get(), &OnlineAttempt::OnClientLoginFailure, error)); // Force IO thread to finish tasks so I can verify |state_|. io_thread_.Stop(); EXPECT_TRUE(GoogleServiceAuthError::None() == state_.online_outcome().error()); EXPECT_TRUE(GaiaAuthConsumer::ClientLoginResult() == state_.credentials()); } } // namespace chromeos