blob: 660d7fe0e1215ffaad80c8377ccf44846d9fc518 [file] [log] [blame]
// Copyright 2014 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/bind.h"
#include "base/location.h"
#include "base/memory/ref_counted.h"
#include "base/run_loop.h"
#include "base/test/null_task_runner.h"
#include "chrome/test/base/testing_profile.h"
#include "chromeos/login/auth/auth_attempt_state.h"
#include "chromeos/login/auth/mock_auth_attempt_state_resolver.h"
#include "chromeos/login/auth/mock_url_fetchers.h"
#include "chromeos/login/auth/online_attempt.h"
#include "chromeos/login/auth/test_attempt_state.h"
#include "chromeos/login/auth/user_context.h"
#include "google_apis/gaia/gaia_auth_consumer.h"
#include "google_apis/gaia/mock_url_fetcher_factory.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
using ::testing::AnyNumber;
using ::testing::Invoke;
using ::testing::Return;
using ::testing::_;
namespace {
class TestContextURLRequestContextGetter : public net::URLRequestContextGetter {
public:
TestContextURLRequestContextGetter()
: null_task_runner_(new base::NullTaskRunner) {}
virtual net::URLRequestContext* GetURLRequestContext() override {
return &context_;
}
virtual scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner()
const override {
return null_task_runner_;
}
private:
virtual ~TestContextURLRequestContextGetter() {}
net::TestURLRequestContext context_;
scoped_refptr<base::SingleThreadTaskRunner> null_task_runner_;
};
} // namespace
namespace chromeos {
class OnlineAttemptTest : public testing::Test {
public:
OnlineAttemptTest()
: state_(UserContext(), false),
attempt_(new OnlineAttempt(&state_, &resolver_)) {}
virtual void SetUp() override {
message_loop_ = base::MessageLoopProxy::current();
request_context_ = new TestContextURLRequestContextGetter();
}
void RunFailureTest(const GoogleServiceAuthError& error) {
EXPECT_CALL(resolver_, Resolve()).Times(1).RetiresOnSaturation();
message_loop_->PostTask(FROM_HERE,
base::Bind(&OnlineAttempt::OnClientLoginFailure,
attempt_->weak_factory_.GetWeakPtr(),
error));
// Force UI thread to finish tasks so I can verify |state_|.
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(error == state_.online_outcome().error());
}
void CancelLogin(OnlineAttempt* auth) {
message_loop_->PostTask(FROM_HERE,
base::Bind(&OnlineAttempt::CancelClientLogin,
auth->weak_factory_.GetWeakPtr()));
}
scoped_refptr<base::MessageLoopProxy> message_loop_;
scoped_refptr<net::URLRequestContextGetter> request_context_;
base::MessageLoop loop_;
TestAttemptState state_;
MockAuthAttemptStateResolver resolver_;
scoped_ptr<OnlineAttempt> attempt_;
};
TEST_F(OnlineAttemptTest, LoginSuccess) {
EXPECT_CALL(resolver_, Resolve()).Times(1).RetiresOnSaturation();
message_loop_->PostTask(FROM_HERE,
base::Bind(&OnlineAttempt::OnClientLoginSuccess,
attempt_->weak_factory_.GetWeakPtr(),
GaiaAuthConsumer::ClientLoginResult()));
// Force UI thread to finish tasks so I can verify |state_|.
base::RunLoop().RunUntilIdle();
}
TEST_F(OnlineAttemptTest, LoginCancelRetry) {
GoogleServiceAuthError error(GoogleServiceAuthError::REQUEST_CANCELED);
TestingProfile profile;
base::RunLoop run_loop;
EXPECT_CALL(resolver_, Resolve())
.WillOnce(Invoke(&run_loop, &base::RunLoop::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 UI thread saying they've been canceled.
MockURLFetcherFactory<GotCanceledFetcher> factory;
attempt_->Initiate(request_context_.get());
run_loop.Run();
EXPECT_TRUE(error == state_.online_outcome().error());
EXPECT_EQ(AuthFailure::NETWORK_AUTH_FAILED, state_.online_outcome().reason());
}
TEST_F(OnlineAttemptTest, LoginTimeout) {
AuthFailure error(AuthFailure::LOGIN_TIMED_OUT);
TestingProfile profile;
base::RunLoop run_loop;
EXPECT_CALL(resolver_, Resolve())
.WillOnce(Invoke(&run_loop, &base::RunLoop::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 UI thread saying they've been canceled.
MockURLFetcherFactory<ExpectCanceledFetcher> factory;
attempt_->Initiate(request_context_.get());
// Post a task to cancel the login attempt.
CancelLogin(attempt_.get());
run_loop.Run();
EXPECT_EQ(AuthFailure::LOGIN_TIMED_OUT, state_.online_outcome().reason());
}
TEST_F(OnlineAttemptTest, HostedLoginRejected) {
AuthFailure error(AuthFailure::FromNetworkAuthFailure(
GoogleServiceAuthError(GoogleServiceAuthError::HOSTED_NOT_ALLOWED)));
TestingProfile profile;
base::RunLoop run_loop;
EXPECT_CALL(resolver_, Resolve())
.WillOnce(Invoke(&run_loop, &base::RunLoop::Quit))
.RetiresOnSaturation();
// This is how we inject fake URLFetcher objects, with a factory.
MockURLFetcherFactory<HostedFetcher> factory;
TestAttemptState local_state(UserContext(), true);
attempt_.reset(new OnlineAttempt(&local_state, &resolver_));
attempt_->Initiate(request_context_.get());
run_loop.Run();
EXPECT_EQ(error, local_state.online_outcome());
EXPECT_EQ(AuthFailure::NETWORK_AUTH_FAILED,
local_state.online_outcome().reason());
}
TEST_F(OnlineAttemptTest, FullLogin) {
TestingProfile profile;
base::RunLoop run_loop;
EXPECT_CALL(resolver_, Resolve())
.WillOnce(Invoke(&run_loop, &base::RunLoop::Quit))
.RetiresOnSaturation();
// This is how we inject fake URLFetcher objects, with a factory.
MockURLFetcherFactory<SuccessFetcher> factory;
TestAttemptState local_state(UserContext(), true);
attempt_.reset(new OnlineAttempt(&local_state, &resolver_));
attempt_->Initiate(request_context_.get());
run_loop.Run();
EXPECT_EQ(AuthFailure::AuthFailureNone(), local_state.online_outcome());
}
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::FromClientLoginCaptchaChallenge(
"CCTOKEN",
GURL("http://accounts.google.com/Captcha?ctoken=CCTOKEN"),
GURL("http://www.google.com/login/captcha"));
RunFailureTest(auth_error);
}
TEST_F(OnlineAttemptTest, TwoFactorSuccess) {
EXPECT_CALL(resolver_, Resolve()).Times(1).RetiresOnSaturation();
GoogleServiceAuthError error(GoogleServiceAuthError::TWO_FACTOR);
message_loop_->PostTask(FROM_HERE,
base::Bind(&OnlineAttempt::OnClientLoginFailure,
attempt_->weak_factory_.GetWeakPtr(),
error));
// Force UI thread to finish tasks so I can verify |state_|.
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(GoogleServiceAuthError::AuthErrorNone() ==
state_.online_outcome().error());
}
} // namespace chromeos