| Index: components/signin/core/browser/access_token_fetcher_unittest.cc
|
| diff --git a/components/signin/core/browser/access_token_fetcher_unittest.cc b/components/signin/core/browser/access_token_fetcher_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..89bb1c7d15b62453df54e8313d84ddba0fbd24af
|
| --- /dev/null
|
| +++ b/components/signin/core/browser/access_token_fetcher_unittest.cc
|
| @@ -0,0 +1,258 @@
|
| +// Copyright 2017 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 "components/signin/core/browser/access_token_fetcher.h"
|
| +
|
| +#include <memory>
|
| +#include <utility>
|
| +
|
| +#include "base/memory/ptr_util.h"
|
| +#include "base/message_loop/message_loop.h"
|
| +#include "base/run_loop.h"
|
| +#include "base/test/mock_callback.h"
|
| +#include "components/prefs/testing_pref_service.h"
|
| +#include "components/signin/core/browser/account_tracker_service.h"
|
| +#include "components/signin/core/browser/fake_signin_manager.h"
|
| +#include "components/signin/core/browser/test_signin_client.h"
|
| +#include "components/sync_preferences/testing_pref_service_syncable.h"
|
| +#include "google_apis/gaia/fake_oauth2_token_service.h"
|
| +#include "testing/gmock/include/gmock/gmock.h"
|
| +#include "testing/gmock_mutant.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +using base::MockCallback;
|
| +using sync_preferences::TestingPrefServiceSyncable;
|
| +using testing::_;
|
| +using testing::CallbackToFunctor;
|
| +using testing::InvokeWithoutArgs;
|
| +using testing::StrictMock;
|
| +
|
| +class AccessTokenFetcherTest : public testing::Test {
|
| + public:
|
| + using TestTokenCallback =
|
| + StrictMock<MockCallback<AccessTokenFetcher::TokenCallback>>;
|
| +
|
| + AccessTokenFetcherTest()
|
| + : signin_client_(&pref_service_),
|
| + signin_manager_(&signin_client_, &account_tracker_) {
|
| + SigninManagerBase::RegisterProfilePrefs(pref_service_.registry());
|
| + SigninManagerBase::RegisterPrefs(pref_service_.registry());
|
| + }
|
| +
|
| + ~AccessTokenFetcherTest() override {}
|
| +
|
| + std::unique_ptr<AccessTokenFetcher> CreateFetcher(
|
| + AccessTokenFetcher::TokenCallback callback) {
|
| + std::set<std::string> scopes{"scope"};
|
| + return base::MakeUnique<AccessTokenFetcher>(
|
| + "test_consumer", &signin_manager_, &token_service_, scopes,
|
| + std::move(callback));
|
| + }
|
| +
|
| + FakeOAuth2TokenService* token_service() { return &token_service_; }
|
| + FakeSigninManagerBase* signin_manager() { return &signin_manager_; }
|
| +
|
| + private:
|
| + // AccessTokenFetcher may post a task to the current task runner, which
|
| + // requires an active message loop.
|
| + base::MessageLoop message_loop_;
|
| +
|
| + FakeOAuth2TokenService token_service_;
|
| + TestingPrefServiceSyncable pref_service_;
|
| + AccountTrackerService account_tracker_;
|
| + TestSigninClient signin_client_;
|
| + FakeSigninManagerBase signin_manager_;
|
| +};
|
| +
|
| +TEST_F(AccessTokenFetcherTest, ShouldReturnAccessToken) {
|
| + TestTokenCallback callback;
|
| +
|
| + signin_manager()->SignIn("account");
|
| + token_service()->GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials(
|
| + "account", "refresh token");
|
| +
|
| + // Signed in and refresh token already exists, so this should result in a
|
| + // request for an access token.
|
| + auto fetcher = CreateFetcher(callback.Get());
|
| +
|
| + // Once the access token request is fulfilled, we should get called back with
|
| + // the access token.
|
| + EXPECT_CALL(callback, Run("access token"));
|
| + token_service()->IssueAllTokensForAccount(
|
| + "account", "access token",
|
| + base::Time::Now() + base::TimeDelta::FromHours(1));
|
| +}
|
| +
|
| +TEST_F(AccessTokenFetcherTest, ShouldNotReplyIfDestroyed) {
|
| + TestTokenCallback callback;
|
| +
|
| + signin_manager()->SignIn("account");
|
| + token_service()->GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials(
|
| + "account", "refresh token");
|
| +
|
| + // Signed in and refresh token already exists, so this should result in a
|
| + // request for an access token.
|
| + auto fetcher = CreateFetcher(callback.Get());
|
| +
|
| + // Destroy the fetcher before the access token request is fulfilled.
|
| + fetcher.reset();
|
| +
|
| + // Now fulfilling the access token request should have no effect.
|
| + token_service()->IssueAllTokensForAccount(
|
| + "account", "access token",
|
| + base::Time::Now() + base::TimeDelta::FromHours(1));
|
| +}
|
| +
|
| +TEST_F(AccessTokenFetcherTest, ShouldReturnEmptyTokenWhenSignedOut) {
|
| + TestTokenCallback callback;
|
| +
|
| + // Signed out -> we should get called back with an empty access token.
|
| + base::RunLoop run_loop;
|
| + EXPECT_CALL(callback, Run(std::string()))
|
| + .WillOnce(InvokeWithoutArgs(CallbackToFunctor(run_loop.QuitClosure())));
|
| + auto fetcher = CreateFetcher(callback.Get());
|
| + run_loop.Run();
|
| +}
|
| +
|
| +TEST_F(AccessTokenFetcherTest, ShouldNotReplyIfDestroyedWhenSignedOut) {
|
| + TestTokenCallback callback;
|
| +
|
| + auto fetcher = CreateFetcher(callback.Get());
|
| +
|
| + // Destroy the fetcher before it gets a chance to run the callback.
|
| + fetcher.reset();
|
| +
|
| + // Make sure the fetcher didn't post a callback to the message loop.
|
| + base::RunLoop().RunUntilIdle();
|
| +}
|
| +
|
| +TEST_F(AccessTokenFetcherTest, ShouldWaitForSignIn) {
|
| + TestTokenCallback callback;
|
| +
|
| + signin_manager()->SetAuthInProgress(true);
|
| +
|
| + // A sign-in is currently in progress, so this should wait for the sign-in to
|
| + // complete.
|
| + auto fetcher = CreateFetcher(callback.Get());
|
| +
|
| + signin_manager()->SignIn("account");
|
| + token_service()->GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials(
|
| + "account", "refresh token");
|
| +
|
| + // Once the access token request is fulfilled, we should get called back with
|
| + // the access token.
|
| + EXPECT_CALL(callback, Run("access token"));
|
| + token_service()->IssueAllTokensForAccount(
|
| + "account", "access token",
|
| + base::Time::Now() + base::TimeDelta::FromHours(1));
|
| +}
|
| +
|
| +TEST_F(AccessTokenFetcherTest, ShouldWaitForRefreshToken) {
|
| + TestTokenCallback callback;
|
| +
|
| + signin_manager()->SignIn("account");
|
| +
|
| + // Signed in, but there is no refresh token -> we should not get called back
|
| + // (yet).
|
| + auto fetcher = CreateFetcher(callback.Get());
|
| +
|
| + // Getting a refresh token should result in a request for an access token.
|
| + token_service()->GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials(
|
| + "account", "refresh token");
|
| +
|
| + // Once the access token request is fulfilled, we should get called back with
|
| + // the access token.
|
| + EXPECT_CALL(callback, Run("access token"));
|
| + token_service()->IssueAllTokensForAccount(
|
| + "account", "access token",
|
| + base::Time::Now() + base::TimeDelta::FromHours(1));
|
| +}
|
| +
|
| +TEST_F(AccessTokenFetcherTest, ShouldReturnWhenNoRefreshTokenAvailable) {
|
| + TestTokenCallback callback;
|
| +
|
| + signin_manager()->SignIn("account");
|
| +
|
| + // Signed in, but there is no refresh token -> we should not get called back
|
| + // (yet).
|
| + auto fetcher = CreateFetcher(callback.Get());
|
| +
|
| + // Getting a refresh token for some other account should have no effect.
|
| + token_service()->GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials(
|
| + "different account", "refresh token");
|
| +
|
| + // When all refresh tokens have been loaded by the token service, but the one
|
| + // for our account wasn't among them, we should get called back with an empty
|
| + // access token
|
| + EXPECT_CALL(callback, Run(std::string()));
|
| + token_service()->GetFakeOAuth2TokenServiceDelegate()->LoadCredentials(
|
| + "account doesn't matter");
|
| +}
|
| +
|
| +TEST_F(AccessTokenFetcherTest, ShouldRetryCanceledAccessTokenRequest) {
|
| + TestTokenCallback callback;
|
| +
|
| + signin_manager()->SignIn("account");
|
| + token_service()->GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials(
|
| + "account", "refresh token");
|
| +
|
| + // Signed in and refresh token already exists, so this should result in a
|
| + // request for an access token.
|
| + auto fetcher = CreateFetcher(callback.Get());
|
| +
|
| + // A canceled access token request should get retried once.
|
| + token_service()->IssueErrorForAllPendingRequestsForAccount(
|
| + "account",
|
| + GoogleServiceAuthError(GoogleServiceAuthError::State::REQUEST_CANCELED));
|
| +
|
| + // Once the access token request is fulfilled, we should get called back with
|
| + // the access token.
|
| + EXPECT_CALL(callback, Run("access token"));
|
| + token_service()->IssueAllTokensForAccount(
|
| + "account", "access token",
|
| + base::Time::Now() + base::TimeDelta::FromHours(1));
|
| +}
|
| +
|
| +TEST_F(AccessTokenFetcherTest, ShouldRetryCanceledAccessTokenRequestOnlyOnce) {
|
| + TestTokenCallback callback;
|
| +
|
| + signin_manager()->SignIn("account");
|
| + token_service()->GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials(
|
| + "account", "refresh token");
|
| +
|
| + // Signed in and refresh token already exists, so this should result in a
|
| + // request for an access token.
|
| + auto fetcher = CreateFetcher(callback.Get());
|
| +
|
| + // A canceled access token request should get retried once.
|
| + token_service()->IssueErrorForAllPendingRequestsForAccount(
|
| + "account",
|
| + GoogleServiceAuthError(GoogleServiceAuthError::State::REQUEST_CANCELED));
|
| +
|
| + // On the second failure, we should get called back with an empty access
|
| + // token.
|
| + EXPECT_CALL(callback, Run(std::string()));
|
| + token_service()->IssueErrorForAllPendingRequestsForAccount(
|
| + "account",
|
| + GoogleServiceAuthError(GoogleServiceAuthError::State::REQUEST_CANCELED));
|
| +}
|
| +
|
| +TEST_F(AccessTokenFetcherTest, ShouldNotRetryFailedAccessTokenRequest) {
|
| + TestTokenCallback callback;
|
| +
|
| + signin_manager()->SignIn("account");
|
| + token_service()->GetFakeOAuth2TokenServiceDelegate()->UpdateCredentials(
|
| + "account", "refresh token");
|
| +
|
| + // Signed in and refresh token already exists, so this should result in a
|
| + // request for an access token.
|
| + auto fetcher = CreateFetcher(callback.Get());
|
| +
|
| + // An access token failure other than "canceled" should not be retried; we
|
| + // should immediately get called back with an empty access token.
|
| + EXPECT_CALL(callback, Run(std::string()));
|
| + token_service()->IssueErrorForAllPendingRequestsForAccount(
|
| + "account", GoogleServiceAuthError(
|
| + GoogleServiceAuthError::State::INVALID_GAIA_CREDENTIALS));
|
| +}
|
|
|