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

Side by Side 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, 10 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/signin/core/browser/access_token_fetcher.h"
6
7 #include <memory>
8 #include <utility>
9
10 #include "base/memory/ptr_util.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/run_loop.h"
13 #include "base/test/mock_callback.h"
14 #include "components/prefs/testing_pref_service.h"
15 #include "components/signin/core/browser/account_tracker_service.h"
16 #include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
17 #include "components/signin/core/browser/fake_signin_manager.h"
18 #include "components/signin/core/browser/test_signin_client.h"
19 #include "components/sync_preferences/testing_pref_service_syncable.h"
20 #include "testing/gmock/include/gmock/gmock.h"
21 #include "testing/gmock_mutant.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23
24 using base::MockCallback;
25 using sync_preferences::TestingPrefServiceSyncable;
26 using testing::CallbackToFunctor;
27 using testing::InvokeWithoutArgs;
28 using testing::StrictMock;
29
30 #if defined(OS_CHROMEOS)
31 // ChromeOS doesn't have SigninManager.
32 using SigninManagerForTest = FakeSigninManagerBase;
33 #else
34 using SigninManagerForTest = FakeSigninManager;
35 #endif // OS_CHROMEOS
36
37 class AccessTokenFetcherTest : public testing::Test {
38 public:
39 using TestTokenCallback =
40 StrictMock<MockCallback<AccessTokenFetcher::TokenCallback>>;
41
42 AccessTokenFetcherTest() : signin_client_(&pref_service_) {
43 AccountTrackerService::RegisterPrefs(pref_service_.registry());
44 #if defined(OS_CHROMEOS)
45 SigninManagerBase::RegisterProfilePrefs(pref_service_.registry());
46 SigninManagerBase::RegisterPrefs(pref_service_.registry());
47 #else
48 SigninManager::RegisterProfilePrefs(pref_service_.registry());
49 SigninManager::RegisterPrefs(pref_service_.registry());
50 #endif // OS_CHROMEOS
51
52 account_tracker_ = base::MakeUnique<AccountTrackerService>();
53 account_tracker_->Initialize(&signin_client_);
54
55 #if defined(OS_CHROMEOS)
56 signin_manager_ = base::MakeUnique<FakeSigninManagerBase>(
57 &signin_client_, account_tracker_.get());
58 #else
59 signin_manager_ = base::MakeUnique<FakeSigninManager>(
60 &signin_client_, &token_service_, account_tracker_.get(),
61 /*cookie_manager_service=*/nullptr);
62 #endif // OS_CHROMEOS
63 }
64
65 ~AccessTokenFetcherTest() override {}
66
67 std::unique_ptr<AccessTokenFetcher> CreateFetcher(
68 AccessTokenFetcher::TokenCallback callback) {
69 std::set<std::string> scopes{"scope"};
70 return base::MakeUnique<AccessTokenFetcher>(
71 "test_consumer", signin_manager_.get(), &token_service_, scopes,
72 std::move(callback));
73 }
74
75 FakeProfileOAuth2TokenService* token_service() { return &token_service_; }
76 SigninManagerForTest* signin_manager() { return signin_manager_.get(); }
77
78 void SignIn(const std::string& account) {
79 #if defined(OS_CHROMEOS)
80 signin_manager_->SignIn(account);
81 #else
82 signin_manager_->SignIn(account, "user", "pass");
83 #endif // OS_CHROMEOS
84 }
85
86 private:
87 TestingPrefServiceSyncable pref_service_;
88 TestSigninClient signin_client_;
89 FakeProfileOAuth2TokenService token_service_;
90
91 std::unique_ptr<AccountTrackerService> account_tracker_;
92 std::unique_ptr<SigninManagerForTest> signin_manager_;
93 };
94
95 TEST_F(AccessTokenFetcherTest, ShouldReturnAccessToken) {
96 TestTokenCallback callback;
97
98 SignIn("account");
99 token_service()->GetDelegate()->UpdateCredentials("account", "refresh token");
100
101 // Signed in and refresh token already exists, so this should result in a
102 // request for an access token.
103 auto fetcher = CreateFetcher(callback.Get());
104
105 // Once the access token request is fulfilled, we should get called back with
106 // the access token.
107 EXPECT_CALL(callback,
108 Run(GoogleServiceAuthError::AuthErrorNone(), "access token"));
109 token_service()->IssueAllTokensForAccount(
110 "account", "access token",
111 base::Time::Now() + base::TimeDelta::FromHours(1));
112 }
113
114 TEST_F(AccessTokenFetcherTest, ShouldNotReplyIfDestroyed) {
115 TestTokenCallback callback;
116
117 SignIn("account");
118 token_service()->GetDelegate()->UpdateCredentials("account", "refresh token");
119
120 // Signed in and refresh token already exists, so this should result in a
121 // request for an access token.
122 auto fetcher = CreateFetcher(callback.Get());
123
124 // Destroy the fetcher before the access token request is fulfilled.
125 fetcher.reset();
126
127 // Now fulfilling the access token request should have no effect.
128 token_service()->IssueAllTokensForAccount(
129 "account", "access token",
130 base::Time::Now() + base::TimeDelta::FromHours(1));
131 }
132
133 TEST_F(AccessTokenFetcherTest, ShouldNotReturnWhenSignedOut) {
134 TestTokenCallback callback;
135
136 // Signed out -> the fetcher should wait for a sign-in which never happens
137 // in this test, so we shouldn't get called back.
138 auto fetcher = CreateFetcher(callback.Get());
139 }
140
141 // Tests related to waiting for sign-in don't apply on ChromeOS (it doesn't have
142 // that concept).
143 #if !defined(OS_CHROMEOS)
144
145 TEST_F(AccessTokenFetcherTest, ShouldWaitForSignIn) {
146 TestTokenCallback callback;
147
148 // Not signed in, so this should wait for a sign-in to complete.
149 auto fetcher = CreateFetcher(callback.Get());
150
151 SignIn("account");
152 token_service()->GetDelegate()->UpdateCredentials("account", "refresh token");
153
154 // Once the access token request is fulfilled, we should get called back with
155 // the access token.
156 EXPECT_CALL(callback,
157 Run(GoogleServiceAuthError::AuthErrorNone(), "access token"));
158 token_service()->IssueAllTokensForAccount(
159 "account", "access token",
160 base::Time::Now() + base::TimeDelta::FromHours(1));
161 }
162
163 TEST_F(AccessTokenFetcherTest, ShouldWaitForSignInInProgress) {
164 TestTokenCallback callback;
165
166 signin_manager()->set_auth_in_progress("account");
167
168 // A sign-in is currently in progress, so this should wait for the sign-in to
169 // complete.
170 auto fetcher = CreateFetcher(callback.Get());
171
172 SignIn("account");
173 token_service()->GetDelegate()->UpdateCredentials("account", "refresh token");
174
175 // Once the access token request is fulfilled, we should get called back with
176 // the access token.
177 EXPECT_CALL(callback,
178 Run(GoogleServiceAuthError::AuthErrorNone(), "access token"));
179 token_service()->IssueAllTokensForAccount(
180 "account", "access token",
181 base::Time::Now() + base::TimeDelta::FromHours(1));
182 }
183
184 TEST_F(AccessTokenFetcherTest, ShouldWaitForFailedSignIn) {
185 TestTokenCallback callback;
186
187 signin_manager()->set_auth_in_progress("account");
188
189 // A sign-in is currently in progress, so this should wait for the sign-in to
190 // complete.
191 auto fetcher = CreateFetcher(callback.Get());
192
193 // The fetcher should detect the failed sign-in and call us with an empty
194 // access token.
195 EXPECT_CALL(
196 callback,
197 Run(GoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED),
198 std::string()));
199
200 signin_manager()->FailSignin(
201 GoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED));
202 }
203
204 #endif // !OS_CHROMEOS
205
206 TEST_F(AccessTokenFetcherTest, ShouldWaitForRefreshToken) {
207 TestTokenCallback callback;
208
209 SignIn("account");
210
211 // Signed in, but there is no refresh token -> we should not get called back
212 // (yet).
213 auto fetcher = CreateFetcher(callback.Get());
214
215 // Getting a refresh token should result in a request for an access token.
216 token_service()->GetDelegate()->UpdateCredentials("account", "refresh token");
217
218 // Once the access token request is fulfilled, we should get called back with
219 // the access token.
220 EXPECT_CALL(callback,
221 Run(GoogleServiceAuthError::AuthErrorNone(), "access token"));
222 token_service()->IssueAllTokensForAccount(
223 "account", "access token",
224 base::Time::Now() + base::TimeDelta::FromHours(1));
225 }
226
227 TEST_F(AccessTokenFetcherTest, ShouldIgnoreRefreshTokensForOtherAccounts) {
228 TestTokenCallback callback;
229
230 // Signed-in to "account", but there's only a refresh token for a different
231 // account.
232 SignIn("account");
233 token_service()->GetDelegate()->UpdateCredentials("account 2", "refresh");
234
235 // The fetcher should wait for the correct refresh token.
236 auto fetcher = CreateFetcher(callback.Get());
237
238 // A refresh token for yet another account shouldn't matter either.
239 token_service()->GetDelegate()->UpdateCredentials("account 3", "refresh");
240 }
241
242 TEST_F(AccessTokenFetcherTest, ShouldReturnWhenNoRefreshTokenAvailable) {
243 TestTokenCallback callback;
244
245 SignIn("account");
246
247 // Signed in, but there is no refresh token -> we should not get called back
248 // (yet).
249 auto fetcher = CreateFetcher(callback.Get());
250
251 // Getting a refresh token for some other account should have no effect.
252 token_service()->GetDelegate()->UpdateCredentials("different account",
253 "refresh token");
254
255 // The OAuth2TokenService posts a task to the current thread when we try to
256 // get an access token for an account without a refresh token, so we need a
257 // MessageLoop in this test to not crash.
258 base::MessageLoop message_loop;
Marc Treib 2017/01/27 13:16:39 This is unfortunate :( But I don't see any other s
259
260 // When all refresh tokens have been loaded by the token service, but the one
261 // for our account wasn't among them, we should get called back with an empty
262 // access token.
263 EXPECT_CALL(callback, Run(testing::_, std::string()));
264 token_service()->GetDelegate()->LoadCredentials("account doesn't matter");
265
266 // Wait for the task posted by OAuth2TokenService to run.
267 base::RunLoop().RunUntilIdle();
268 }
269
270 TEST_F(AccessTokenFetcherTest, ShouldRetryCanceledAccessTokenRequest) {
271 TestTokenCallback callback;
272
273 SignIn("account");
274 token_service()->GetDelegate()->UpdateCredentials("account", "refresh token");
275
276 // Signed in and refresh token already exists, so this should result in a
277 // request for an access token.
278 auto fetcher = CreateFetcher(callback.Get());
279
280 // A canceled access token request should get retried once.
281 token_service()->IssueErrorForAllPendingRequestsForAccount(
282 "account",
283 GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED));
284
285 // Once the access token request is fulfilled, we should get called back with
286 // the access token.
287 EXPECT_CALL(callback,
288 Run(GoogleServiceAuthError::AuthErrorNone(), "access token"));
289 token_service()->IssueAllTokensForAccount(
290 "account", "access token",
291 base::Time::Now() + base::TimeDelta::FromHours(1));
292 }
293
294 TEST_F(AccessTokenFetcherTest, ShouldRetryCanceledAccessTokenRequestOnlyOnce) {
295 TestTokenCallback callback;
296
297 SignIn("account");
298 token_service()->GetDelegate()->UpdateCredentials("account", "refresh token");
299
300 // Signed in and refresh token already exists, so this should result in a
301 // request for an access token.
302 auto fetcher = CreateFetcher(callback.Get());
303
304 // A canceled access token request should get retried once.
305 token_service()->IssueErrorForAllPendingRequestsForAccount(
306 "account",
307 GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED));
308
309 // On the second failure, we should get called back with an empty access
310 // token.
311 EXPECT_CALL(
312 callback,
313 Run(GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED),
314 std::string()));
315 token_service()->IssueErrorForAllPendingRequestsForAccount(
316 "account",
317 GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED));
318 }
319
320 #if !defined(OS_CHROMEOS)
321
322 TEST_F(AccessTokenFetcherTest,
323 ShouldNotRetryCanceledAccessTokenRequestIfSignedOut) {
324 TestTokenCallback callback;
325
326 SignIn("account");
327 token_service()->GetDelegate()->UpdateCredentials("account", "refresh token");
328
329 // Signed in and refresh token already exists, so this should result in a
330 // request for an access token.
331 auto fetcher = CreateFetcher(callback.Get());
332
333 // Simulate the user signing out while the access token request is pending.
334 // In this case, the pending request gets canceled, and the fetcher should
335 // *not* retry.
336 signin_manager()->ForceSignOut();
337 EXPECT_CALL(
338 callback,
339 Run(GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED),
340 std::string()));
341 token_service()->IssueErrorForAllPendingRequestsForAccount(
342 "account",
343 GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED));
344 }
345
346 #endif // !OS_CHROMEOS
347
348 TEST_F(AccessTokenFetcherTest,
349 ShouldNotRetryCanceledAccessTokenRequestIfRefreshTokenRevoked) {
350 TestTokenCallback callback;
351
352 SignIn("account");
353 token_service()->GetDelegate()->UpdateCredentials("account", "refresh token");
354
355 // Signed in and refresh token already exists, so this should result in a
356 // request for an access token.
357 auto fetcher = CreateFetcher(callback.Get());
358
359 // Simulate the refresh token getting invalidated. In this case, pending
360 // access token requests get canceled, and the fetcher should *not* retry.
361 token_service()->GetDelegate()->RevokeCredentials("account");
362 EXPECT_CALL(
363 callback,
364 Run(GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED),
365 std::string()));
366 token_service()->IssueErrorForAllPendingRequestsForAccount(
367 "account",
368 GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED));
369 }
370
371 TEST_F(AccessTokenFetcherTest, ShouldNotRetryFailedAccessTokenRequest) {
372 TestTokenCallback callback;
373
374 SignIn("account");
375 token_service()->GetDelegate()->UpdateCredentials("account", "refresh token");
376
377 // Signed in and refresh token already exists, so this should result in a
378 // request for an access token.
379 auto fetcher = CreateFetcher(callback.Get());
380
381 // An access token failure other than "canceled" should not be retried; we
382 // should immediately get called back with an empty access token.
383 EXPECT_CALL(
384 callback,
385 Run(GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE),
386 std::string()));
387 token_service()->IssueErrorForAllPendingRequestsForAccount(
388 "account",
389 GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE));
390 }
OLDNEW
« 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