Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(660)

Unified Diff: components/signin/core/browser/access_token_fetcher_unittest.cc

Issue 2582573002: Signin/OAuth: Create an AccessTokenFetcher helper class (Closed)
Patch Set: review5 Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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..331468b0e1520f87623ef2f2661222c632b503b1
--- /dev/null
+++ b/components/signin/core/browser/access_token_fetcher_unittest.cc
@@ -0,0 +1,390 @@
+// 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_profile_oauth2_token_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 "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::CallbackToFunctor;
+using testing::InvokeWithoutArgs;
+using testing::StrictMock;
+
+#if defined(OS_CHROMEOS)
+// ChromeOS doesn't have SigninManager.
+using SigninManagerForTest = FakeSigninManagerBase;
+#else
+using SigninManagerForTest = FakeSigninManager;
+#endif // OS_CHROMEOS
+
+class AccessTokenFetcherTest : public testing::Test {
+ public:
+ using TestTokenCallback =
+ StrictMock<MockCallback<AccessTokenFetcher::TokenCallback>>;
+
+ AccessTokenFetcherTest() : signin_client_(&pref_service_) {
+ AccountTrackerService::RegisterPrefs(pref_service_.registry());
+#if defined(OS_CHROMEOS)
+ SigninManagerBase::RegisterProfilePrefs(pref_service_.registry());
+ SigninManagerBase::RegisterPrefs(pref_service_.registry());
+#else
+ SigninManager::RegisterProfilePrefs(pref_service_.registry());
+ SigninManager::RegisterPrefs(pref_service_.registry());
+#endif // OS_CHROMEOS
+
+ account_tracker_ = base::MakeUnique<AccountTrackerService>();
+ account_tracker_->Initialize(&signin_client_);
+
+#if defined(OS_CHROMEOS)
+ signin_manager_ = base::MakeUnique<FakeSigninManagerBase>(
+ &signin_client_, account_tracker_.get());
+#else
+ signin_manager_ = base::MakeUnique<FakeSigninManager>(
+ &signin_client_, &token_service_, account_tracker_.get(),
+ /*cookie_manager_service=*/nullptr);
+#endif // OS_CHROMEOS
+ }
+
+ ~AccessTokenFetcherTest() override {}
+
+ std::unique_ptr<AccessTokenFetcher> CreateFetcher(
+ AccessTokenFetcher::TokenCallback callback) {
+ std::set<std::string> scopes{"scope"};
+ return base::MakeUnique<AccessTokenFetcher>(
+ "test_consumer", signin_manager_.get(), &token_service_, scopes,
+ std::move(callback));
+ }
+
+ FakeProfileOAuth2TokenService* token_service() { return &token_service_; }
+ SigninManagerForTest* signin_manager() { return signin_manager_.get(); }
+
+ void SignIn(const std::string& account) {
+#if defined(OS_CHROMEOS)
+ signin_manager_->SignIn(account);
+#else
+ signin_manager_->SignIn(account, "user", "pass");
+#endif // OS_CHROMEOS
+ }
+
+ private:
+ TestingPrefServiceSyncable pref_service_;
+ TestSigninClient signin_client_;
+ FakeProfileOAuth2TokenService token_service_;
+
+ std::unique_ptr<AccountTrackerService> account_tracker_;
+ std::unique_ptr<SigninManagerForTest> signin_manager_;
+};
+
+TEST_F(AccessTokenFetcherTest, ShouldReturnAccessToken) {
+ TestTokenCallback callback;
+
+ SignIn("account");
+ token_service()->GetDelegate()->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(GoogleServiceAuthError::AuthErrorNone(), "access token"));
+ token_service()->IssueAllTokensForAccount(
+ "account", "access token",
+ base::Time::Now() + base::TimeDelta::FromHours(1));
+}
+
+TEST_F(AccessTokenFetcherTest, ShouldNotReplyIfDestroyed) {
+ TestTokenCallback callback;
+
+ SignIn("account");
+ token_service()->GetDelegate()->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, ShouldNotReturnWhenSignedOut) {
+ TestTokenCallback callback;
+
+ // Signed out -> the fetcher should wait for a sign-in which never happens
+ // in this test, so we shouldn't get called back.
+ auto fetcher = CreateFetcher(callback.Get());
+}
+
+// Tests related to waiting for sign-in don't apply on ChromeOS (it doesn't have
+// that concept).
+#if !defined(OS_CHROMEOS)
+
+TEST_F(AccessTokenFetcherTest, ShouldWaitForSignIn) {
+ TestTokenCallback callback;
+
+ // Not signed in, so this should wait for a sign-in to complete.
+ auto fetcher = CreateFetcher(callback.Get());
+
+ SignIn("account");
+ token_service()->GetDelegate()->UpdateCredentials("account", "refresh token");
+
+ // Once the access token request is fulfilled, we should get called back with
+ // the access token.
+ EXPECT_CALL(callback,
+ Run(GoogleServiceAuthError::AuthErrorNone(), "access token"));
+ token_service()->IssueAllTokensForAccount(
+ "account", "access token",
+ base::Time::Now() + base::TimeDelta::FromHours(1));
+}
+
+TEST_F(AccessTokenFetcherTest, ShouldWaitForSignInInProgress) {
+ TestTokenCallback callback;
+
+ signin_manager()->set_auth_in_progress("account");
+
+ // A sign-in is currently in progress, so this should wait for the sign-in to
+ // complete.
+ auto fetcher = CreateFetcher(callback.Get());
+
+ SignIn("account");
+ token_service()->GetDelegate()->UpdateCredentials("account", "refresh token");
+
+ // Once the access token request is fulfilled, we should get called back with
+ // the access token.
+ EXPECT_CALL(callback,
+ Run(GoogleServiceAuthError::AuthErrorNone(), "access token"));
+ token_service()->IssueAllTokensForAccount(
+ "account", "access token",
+ base::Time::Now() + base::TimeDelta::FromHours(1));
+}
+
+TEST_F(AccessTokenFetcherTest, ShouldWaitForFailedSignIn) {
+ TestTokenCallback callback;
+
+ signin_manager()->set_auth_in_progress("account");
+
+ // A sign-in is currently in progress, so this should wait for the sign-in to
+ // complete.
+ auto fetcher = CreateFetcher(callback.Get());
+
+ // The fetcher should detect the failed sign-in and call us with an empty
+ // access token.
+ EXPECT_CALL(
+ callback,
+ Run(GoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED),
+ std::string()));
+
+ signin_manager()->FailSignin(
+ GoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED));
+}
+
+#endif // !OS_CHROMEOS
+
+TEST_F(AccessTokenFetcherTest, ShouldWaitForRefreshToken) {
+ TestTokenCallback callback;
+
+ 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()->GetDelegate()->UpdateCredentials("account", "refresh token");
+
+ // Once the access token request is fulfilled, we should get called back with
+ // the access token.
+ EXPECT_CALL(callback,
+ Run(GoogleServiceAuthError::AuthErrorNone(), "access token"));
+ token_service()->IssueAllTokensForAccount(
+ "account", "access token",
+ base::Time::Now() + base::TimeDelta::FromHours(1));
+}
+
+TEST_F(AccessTokenFetcherTest, ShouldIgnoreRefreshTokensForOtherAccounts) {
+ TestTokenCallback callback;
+
+ // Signed-in to "account", but there's only a refresh token for a different
+ // account.
+ SignIn("account");
+ token_service()->GetDelegate()->UpdateCredentials("account 2", "refresh");
+
+ // The fetcher should wait for the correct refresh token.
+ auto fetcher = CreateFetcher(callback.Get());
+
+ // A refresh token for yet another account shouldn't matter either.
+ token_service()->GetDelegate()->UpdateCredentials("account 3", "refresh");
+}
+
+TEST_F(AccessTokenFetcherTest, ShouldReturnWhenNoRefreshTokenAvailable) {
+ TestTokenCallback callback;
+
+ 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()->GetDelegate()->UpdateCredentials("different account",
+ "refresh token");
+
+ // The OAuth2TokenService posts a task to the current thread when we try to
+ // get an access token for an account without a refresh token, so we need a
+ // MessageLoop in this test to not crash.
+ base::MessageLoop message_loop;
Marc Treib 2017/01/27 13:16:39 This is unfortunate :( But I don't see any other s
+
+ // 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(testing::_, std::string()));
+ token_service()->GetDelegate()->LoadCredentials("account doesn't matter");
+
+ // Wait for the task posted by OAuth2TokenService to run.
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(AccessTokenFetcherTest, ShouldRetryCanceledAccessTokenRequest) {
+ TestTokenCallback callback;
+
+ SignIn("account");
+ token_service()->GetDelegate()->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::REQUEST_CANCELED));
+
+ // Once the access token request is fulfilled, we should get called back with
+ // the access token.
+ EXPECT_CALL(callback,
+ Run(GoogleServiceAuthError::AuthErrorNone(), "access token"));
+ token_service()->IssueAllTokensForAccount(
+ "account", "access token",
+ base::Time::Now() + base::TimeDelta::FromHours(1));
+}
+
+TEST_F(AccessTokenFetcherTest, ShouldRetryCanceledAccessTokenRequestOnlyOnce) {
+ TestTokenCallback callback;
+
+ SignIn("account");
+ token_service()->GetDelegate()->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::REQUEST_CANCELED));
+
+ // On the second failure, we should get called back with an empty access
+ // token.
+ EXPECT_CALL(
+ callback,
+ Run(GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED),
+ std::string()));
+ token_service()->IssueErrorForAllPendingRequestsForAccount(
+ "account",
+ GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED));
+}
+
+#if !defined(OS_CHROMEOS)
+
+TEST_F(AccessTokenFetcherTest,
+ ShouldNotRetryCanceledAccessTokenRequestIfSignedOut) {
+ TestTokenCallback callback;
+
+ SignIn("account");
+ token_service()->GetDelegate()->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());
+
+ // Simulate the user signing out while the access token request is pending.
+ // In this case, the pending request gets canceled, and the fetcher should
+ // *not* retry.
+ signin_manager()->ForceSignOut();
+ EXPECT_CALL(
+ callback,
+ Run(GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED),
+ std::string()));
+ token_service()->IssueErrorForAllPendingRequestsForAccount(
+ "account",
+ GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED));
+}
+
+#endif // !OS_CHROMEOS
+
+TEST_F(AccessTokenFetcherTest,
+ ShouldNotRetryCanceledAccessTokenRequestIfRefreshTokenRevoked) {
+ TestTokenCallback callback;
+
+ SignIn("account");
+ token_service()->GetDelegate()->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());
+
+ // Simulate the refresh token getting invalidated. In this case, pending
+ // access token requests get canceled, and the fetcher should *not* retry.
+ token_service()->GetDelegate()->RevokeCredentials("account");
+ EXPECT_CALL(
+ callback,
+ Run(GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED),
+ std::string()));
+ token_service()->IssueErrorForAllPendingRequestsForAccount(
+ "account",
+ GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED));
+}
+
+TEST_F(AccessTokenFetcherTest, ShouldNotRetryFailedAccessTokenRequest) {
+ TestTokenCallback callback;
+
+ SignIn("account");
+ token_service()->GetDelegate()->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(GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE),
+ std::string()));
+ token_service()->IssueErrorForAllPendingRequestsForAccount(
+ "account",
+ GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE));
+}
« no previous file with comments | « components/signin/core/browser/access_token_fetcher.cc ('k') | components/signin/core/browser/fake_signin_manager.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698