blob: 12d402883eddae838e1f8b80fc896647ecbcfa66 [file] [log] [blame]
// Copyright 2015 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 "remoting/test/access_token_fetcher.h"
#include <string>
#include "base/bind.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/test/scoped_task_environment.h"
#include "google_apis/gaia/gaia_urls.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/test/test_url_loader_factory.h"
#include "services/network/test/test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
const char kAuthCodeValue[] = "test_auth_code_value";
const char kAccessTokenValue[] = "test_access_token_value";
const char kRefreshTokenValue[] = "test_refresh_token_value";
const char kAuthCodeExchangeValidResponse[] =
"{"
" \"refresh_token\": \"test_refresh_token_value\","
" \"access_token\": \"test_access_token_value\","
" \"expires_in\": 3600,"
" \"token_type\": \"Bearer\""
"}";
const char kAuthCodeExchangeEmptyResponse[] = "{}";
const char kRefreshTokenExchangeValidResponse[] =
"{"
" \"access_token\": \"test_access_token_value\","
" \"expires_in\": 3600,"
" \"token_type\": \"Bearer\""
"}";
const char kRefreshTokenExchangeEmptyResponse[] = "{}";
const char kValidTokenInfoResponse[] =
"{"
" \"audience\": \"blah.apps.googleusercontent.blah.com\","
" \"used_id\": \"1234567890\","
" \"scope\": \"all the things\","
" \"expires_in\": \"1800\","
" \"token_type\": \"Bearer\""
"}";
const char kInvalidTokenInfoResponse[] =
"{"
" \"error\": \"invalid_token\""
"}";
} // namespace
namespace remoting {
namespace test {
// Provides base functionality for the AccessTokenFetcher Tests below. The
// FakeURLFetcherFactory allows us to override the response data and payload for
// specified URLs. We use this to stub out network calls made by the
// AccessTokenFetcher. This fixture also creates an IO MessageLoop, if
// necessary, for use by the AccessTokenFetcher.
class AccessTokenFetcherTest : public ::testing::Test {
public:
AccessTokenFetcherTest();
~AccessTokenFetcherTest() override;
void OnAccessTokenRetrieved(base::Closure done_closure,
const std::string& access_token,
const std::string& refresh_token);
protected:
void SetFakeResponse(const GURL& url,
const std::string& data,
net::HttpStatusCode code,
int net_error);
scoped_refptr<network::SharedURLLoaderFactory> shared_factory() {
return shared_factory_;
}
// Used for result verification
std::string access_token_retrieved_;
std::string refresh_token_retrieved_;
private:
base::test::ScopedTaskEnvironment scoped_task_environment_;
network::TestURLLoaderFactory test_url_loader_factory_;
scoped_refptr<network::SharedURLLoaderFactory> shared_factory_;
DISALLOW_COPY_AND_ASSIGN(AccessTokenFetcherTest);
};
AccessTokenFetcherTest::AccessTokenFetcherTest()
: scoped_task_environment_(
base::test::ScopedTaskEnvironment::MainThreadType::IO),
shared_factory_(
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&test_url_loader_factory_)) {}
AccessTokenFetcherTest::~AccessTokenFetcherTest() = default;
void AccessTokenFetcherTest::OnAccessTokenRetrieved(
base::Closure done_closure,
const std::string& access_token,
const std::string& refresh_token) {
access_token_retrieved_ = access_token;
refresh_token_retrieved_ = refresh_token;
done_closure.Run();
}
void AccessTokenFetcherTest::SetFakeResponse(const GURL& url,
const std::string& data,
net::HttpStatusCode code,
int net_error) {
test_url_loader_factory_.AddResponse(
url, network::CreateResourceResponseHead(code), data,
network::URLLoaderCompletionStatus(net_error));
}
TEST_F(AccessTokenFetcherTest, ExchangeAuthCodeForAccessToken) {
SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_url(),
kAuthCodeExchangeValidResponse, net::HTTP_OK, net::OK);
SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_info_url(),
kValidTokenInfoResponse, net::HTTP_OK, net::OK);
base::RunLoop run_loop;
AccessTokenCallback access_token_callback =
base::Bind(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
base::Unretained(this), run_loop.QuitClosure());
AccessTokenFetcher access_token_fetcher;
access_token_fetcher.SetURLLoaderFactoryForTesting(shared_factory());
access_token_fetcher.GetAccessTokenFromAuthCode(kAuthCodeValue,
access_token_callback);
run_loop.Run();
EXPECT_EQ(access_token_retrieved_.compare(kAccessTokenValue), 0);
EXPECT_EQ(refresh_token_retrieved_.compare(kRefreshTokenValue), 0);
}
TEST_F(AccessTokenFetcherTest, ExchangeRefreshTokenForAccessToken) {
SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_url(),
kRefreshTokenExchangeValidResponse, net::HTTP_OK, net::OK);
SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_info_url(),
kValidTokenInfoResponse, net::HTTP_OK, net::OK);
base::RunLoop run_loop;
AccessTokenCallback access_token_callback =
base::Bind(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
base::Unretained(this), run_loop.QuitClosure());
AccessTokenFetcher access_token_fetcher;
access_token_fetcher.SetURLLoaderFactoryForTesting(shared_factory());
access_token_fetcher.GetAccessTokenFromRefreshToken(kRefreshTokenValue,
access_token_callback);
run_loop.Run();
EXPECT_EQ(access_token_retrieved_.compare(kAccessTokenValue), 0);
EXPECT_EQ(refresh_token_retrieved_.compare(kRefreshTokenValue), 0);
}
TEST_F(AccessTokenFetcherTest, MultipleAccessTokenCalls) {
SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_url(),
kAuthCodeExchangeValidResponse, net::HTTP_OK, net::OK);
SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_info_url(),
kValidTokenInfoResponse, net::HTTP_OK, net::OK);
std::unique_ptr<base::RunLoop> run_loop;
run_loop.reset(new base::RunLoop());
AccessTokenCallback access_token_callback =
base::Bind(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
base::Unretained(this), run_loop->QuitClosure());
AccessTokenFetcher access_token_fetcher;
access_token_fetcher.SetURLLoaderFactoryForTesting(shared_factory());
access_token_fetcher.GetAccessTokenFromAuthCode(kAuthCodeValue,
access_token_callback);
run_loop->Run();
EXPECT_EQ(access_token_retrieved_.compare(kAccessTokenValue), 0);
EXPECT_EQ(refresh_token_retrieved_.compare(kRefreshTokenValue), 0);
// Reset our token data for the next iteration.
access_token_retrieved_.clear();
refresh_token_retrieved_.clear();
// Update the response since we will call the refresh token method next.
SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_url(),
kRefreshTokenExchangeValidResponse, net::HTTP_OK, net::OK);
run_loop.reset(new base::RunLoop());
access_token_callback =
base::Bind(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
base::Unretained(this), run_loop->QuitClosure());
access_token_fetcher.GetAccessTokenFromRefreshToken(kRefreshTokenValue,
access_token_callback);
run_loop->Run();
EXPECT_EQ(access_token_retrieved_.compare(kAccessTokenValue), 0);
EXPECT_EQ(refresh_token_retrieved_.compare(kRefreshTokenValue), 0);
run_loop.reset(new base::RunLoop());
access_token_callback =
base::Bind(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
base::Unretained(this), run_loop->QuitClosure());
// Reset our token data for the next iteration.
access_token_retrieved_.clear();
refresh_token_retrieved_.clear();
access_token_fetcher.GetAccessTokenFromRefreshToken(kRefreshTokenValue,
access_token_callback);
run_loop->Run();
EXPECT_EQ(access_token_retrieved_.compare(kAccessTokenValue), 0);
EXPECT_EQ(refresh_token_retrieved_.compare(kRefreshTokenValue), 0);
}
TEST_F(AccessTokenFetcherTest, ExchangeAuthCode_Unauthorized_Error) {
SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_url(),
kAuthCodeExchangeValidResponse, net::HTTP_UNAUTHORIZED,
net::ERR_FAILED);
base::RunLoop run_loop;
AccessTokenCallback access_token_callback =
base::Bind(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
base::Unretained(this), run_loop.QuitClosure());
AccessTokenFetcher access_token_fetcher;
access_token_fetcher.SetURLLoaderFactoryForTesting(shared_factory());
access_token_fetcher.GetAccessTokenFromAuthCode(kAuthCodeValue,
access_token_callback);
run_loop.Run();
// Our callback should have been called with empty strings.
EXPECT_TRUE(access_token_retrieved_.empty());
EXPECT_TRUE(refresh_token_retrieved_.empty());
}
TEST_F(AccessTokenFetcherTest, ExchangeRefreshToken_Unauthorized_Error) {
SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_url(),
kRefreshTokenExchangeValidResponse, net::HTTP_UNAUTHORIZED,
net::ERR_FAILED);
base::RunLoop run_loop;
AccessTokenCallback access_token_callback =
base::Bind(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
base::Unretained(this), run_loop.QuitClosure());
AccessTokenFetcher access_token_fetcher;
access_token_fetcher.SetURLLoaderFactoryForTesting(shared_factory());
access_token_fetcher.GetAccessTokenFromRefreshToken(kRefreshTokenValue,
access_token_callback);
run_loop.Run();
// Our callback should have been called with empty strings.
EXPECT_TRUE(access_token_retrieved_.empty());
EXPECT_TRUE(refresh_token_retrieved_.empty());
}
TEST_F(AccessTokenFetcherTest, ExchangeAuthCode_NetworkError) {
SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_url(),
kAuthCodeExchangeValidResponse, net::HTTP_NOT_FOUND,
net::ERR_FAILED);
base::RunLoop run_loop;
AccessTokenCallback access_token_callback =
base::Bind(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
base::Unretained(this), run_loop.QuitClosure());
AccessTokenFetcher access_token_fetcher;
access_token_fetcher.SetURLLoaderFactoryForTesting(shared_factory());
access_token_fetcher.GetAccessTokenFromAuthCode(kAuthCodeValue,
access_token_callback);
run_loop.Run();
// Our callback should have been called with empty strings.
EXPECT_TRUE(access_token_retrieved_.empty());
EXPECT_TRUE(refresh_token_retrieved_.empty());
}
TEST_F(AccessTokenFetcherTest, ExchangeRefreshToken_NetworkError) {
SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_url(),
kRefreshTokenExchangeValidResponse, net::HTTP_NOT_FOUND,
net::ERR_FAILED);
base::RunLoop run_loop;
AccessTokenCallback access_token_callback =
base::Bind(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
base::Unretained(this), run_loop.QuitClosure());
AccessTokenFetcher access_token_fetcher;
access_token_fetcher.SetURLLoaderFactoryForTesting(shared_factory());
access_token_fetcher.GetAccessTokenFromRefreshToken(kRefreshTokenValue,
access_token_callback);
run_loop.Run();
// Our callback should have been called with empty strings.
EXPECT_TRUE(access_token_retrieved_.empty());
EXPECT_TRUE(refresh_token_retrieved_.empty());
}
TEST_F(AccessTokenFetcherTest, AuthCode_GetTokenInfoResponse_InvalidToken) {
SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_url(),
kAuthCodeExchangeValidResponse, net::HTTP_OK, net::OK);
SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_info_url(),
kInvalidTokenInfoResponse, net::HTTP_OK, net::OK);
base::RunLoop run_loop;
AccessTokenCallback access_token_callback =
base::Bind(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
base::Unretained(this), run_loop.QuitClosure());
AccessTokenFetcher access_token_fetcher;
access_token_fetcher.SetURLLoaderFactoryForTesting(shared_factory());
access_token_fetcher.GetAccessTokenFromAuthCode(kAuthCodeValue,
access_token_callback);
run_loop.Run();
// Our callback should have been called with empty strings.
EXPECT_TRUE(access_token_retrieved_.empty());
EXPECT_TRUE(refresh_token_retrieved_.empty());
}
TEST_F(AccessTokenFetcherTest, ExchangeAuthCodeForAccessToken_EmptyToken) {
SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_url(),
kAuthCodeExchangeEmptyResponse, net::HTTP_OK, net::OK);
base::RunLoop run_loop;
AccessTokenCallback access_token_callback =
base::Bind(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
base::Unretained(this), run_loop.QuitClosure());
AccessTokenFetcher access_token_fetcher;
access_token_fetcher.SetURLLoaderFactoryForTesting(shared_factory());
access_token_fetcher.GetAccessTokenFromAuthCode(kAuthCodeValue,
access_token_callback);
run_loop.Run();
// Our callback should have been called with empty strings.
EXPECT_TRUE(access_token_retrieved_.empty());
EXPECT_TRUE(refresh_token_retrieved_.empty());
}
TEST_F(AccessTokenFetcherTest, RefreshToken_GetTokenInfoResponse_InvalidToken) {
SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_url(),
kRefreshTokenExchangeValidResponse, net::HTTP_OK, net::OK);
SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_info_url(),
kInvalidTokenInfoResponse, net::HTTP_OK, net::OK);
base::RunLoop run_loop;
AccessTokenCallback access_token_callback =
base::Bind(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
base::Unretained(this), run_loop.QuitClosure());
AccessTokenFetcher access_token_fetcher;
access_token_fetcher.SetURLLoaderFactoryForTesting(shared_factory());
access_token_fetcher.GetAccessTokenFromRefreshToken(kRefreshTokenValue,
access_token_callback);
run_loop.Run();
// Our callback should have been called with empty strings.
EXPECT_TRUE(access_token_retrieved_.empty());
EXPECT_TRUE(refresh_token_retrieved_.empty());
}
TEST_F(AccessTokenFetcherTest, ExchangeRefreshTokenForAccessToken_EmptyToken) {
SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_url(),
kRefreshTokenExchangeEmptyResponse, net::HTTP_OK, net::OK);
base::RunLoop run_loop;
AccessTokenCallback access_token_callback =
base::Bind(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
base::Unretained(this), run_loop.QuitClosure());
AccessTokenFetcher access_token_fetcher;
access_token_fetcher.SetURLLoaderFactoryForTesting(shared_factory());
access_token_fetcher.GetAccessTokenFromRefreshToken(kRefreshTokenValue,
access_token_callback);
run_loop.Run();
// Our callback should have been called with empty strings.
EXPECT_TRUE(access_token_retrieved_.empty());
EXPECT_TRUE(refresh_token_retrieved_.empty());
}
} // namespace test
} // namespace remoting