1 // Copyright 2013 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.
5 #include "base/run_loop.h"
6 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
7 #include "chrome/browser/webdata/web_data_service_factory.h"
8 #include "chrome/test/base/testing_profile.h"
9 #include "components/signin/core/browser/mutable_profile_oauth2_token_service.h"
10 #include "components/signin/core/browser/profile_oauth2_token_service.h"
11 #include "components/signin/core/browser/signin_error_controller.h"
12 #include "components/signin/core/browser/webdata/token_web_data.h"
13 #include "content/public/test/test_browser_thread_bundle.h"
14 #include "google_apis/gaia/gaia_constants.h"
15 #include "google_apis/gaia/gaia_urls.h"
16 #include "google_apis/gaia/oauth2_token_service_test_util.h"
17 #include "net/http/http_status_code.h"
18 #include "net/url_request/test_url_fetcher_factory.h"
19 #include "testing/gtest/include/gtest/gtest.h"
21 #if defined(OS_MACOSX)
22 #include "components/os_crypt/os_crypt.h"
25 // Defining constant here to handle backward compatiblity tests, but this
26 // constant is no longer used in current versions of chrome.
27 static const char kLSOService[] = "lso";
28 static const char kEmail[] = "user@gmail.com";
30 class MutableProfileOAuth2TokenServiceTest :
32 public OAuth2TokenService::Observer {
34 MutableProfileOAuth2TokenServiceTest()
36 oauth2_service_(NULL),
37 token_available_count_(0),
38 token_revoked_count_(0),
39 tokens_loaded_count_(0) {
42 virtual void SetUp() OVERRIDE {
43 #if defined(OS_MACOSX)
44 OSCrypt::UseMockKeychain(true);
47 profile_.reset(new TestingProfile);
48 profile_->CreateWebDataService();
50 factory_.SetFakeResponse(GaiaUrls::GetInstance()->oauth2_revoke_url(),
51 "", net::HTTP_OK, net::URLRequestStatus::SUCCESS);
53 ProfileOAuth2TokenServiceFactory::GetPlatformSpecificForProfile(
55 // Make sure PO2TS has a chance to load itself before continuing.
56 base::RunLoop().RunUntilIdle();
57 oauth2_service_->AddObserver(this);
60 virtual void TearDown() OVERRIDE {
61 oauth2_service_->RemoveObserver(this);
65 TestingProfile* profile() { return profile_.get(); }
67 void AddAuthTokenManually(const std::string& service,
68 const std::string& value) {
69 scoped_refptr<TokenWebData> token_web_data =
70 WebDataServiceFactory::GetTokenWebDataForProfile(
71 profile(), Profile::EXPLICIT_ACCESS);
72 if (token_web_data.get())
73 token_web_data->SetTokenForService(service, value);
76 // OAuth2TokenService::Observer implementation.
77 virtual void OnRefreshTokenAvailable(const std::string& account_id) OVERRIDE {
78 ++token_available_count_;
80 virtual void OnRefreshTokenRevoked(const std::string& account_id) OVERRIDE {
81 ++token_revoked_count_;
83 virtual void OnRefreshTokensLoaded() OVERRIDE {
84 ++tokens_loaded_count_;
87 void ResetObserverCounts() {
88 token_available_count_ = 0;
89 token_revoked_count_ = 0;
90 tokens_loaded_count_ = 0;
93 void ExpectNoNotifications() {
94 EXPECT_EQ(0, token_available_count_);
95 EXPECT_EQ(0, token_revoked_count_);
96 EXPECT_EQ(0, tokens_loaded_count_);
97 ResetObserverCounts();
100 void ExpectOneTokenAvailableNotification() {
101 EXPECT_EQ(1, token_available_count_);
102 EXPECT_EQ(0, token_revoked_count_);
103 EXPECT_EQ(0, tokens_loaded_count_);
104 ResetObserverCounts();
107 void ExpectOneTokenRevokedNotification() {
108 EXPECT_EQ(0, token_available_count_);
109 EXPECT_EQ(1, token_revoked_count_);
110 EXPECT_EQ(0, tokens_loaded_count_);
111 ResetObserverCounts();
114 void ExpectOneTokensLoadedNotification() {
115 EXPECT_EQ(0, token_available_count_);
116 EXPECT_EQ(0, token_revoked_count_);
117 EXPECT_EQ(1, tokens_loaded_count_);
118 ResetObserverCounts();
122 content::TestBrowserThreadBundle thread_bundle_;
123 scoped_ptr<TestingProfile> profile_;
124 net::FakeURLFetcherFactory factory_;
125 MutableProfileOAuth2TokenService* oauth2_service_;
126 TestingOAuth2TokenServiceConsumer consumer_;
127 int token_available_count_;
128 int token_revoked_count_;
129 int tokens_loaded_count_;
132 TEST_F(MutableProfileOAuth2TokenServiceTest, PersistenceDBUpgrade) {
133 std::string main_account_id(kEmail);
134 std::string main_refresh_token("old_refresh_token");
136 // Populate DB with legacy tokens.
137 AddAuthTokenManually(GaiaConstants::kSyncService, "syncServiceToken");
138 AddAuthTokenManually(kLSOService, "lsoToken");
139 AddAuthTokenManually(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
142 // Force LoadCredentials.
143 oauth2_service_->LoadCredentials(main_account_id);
144 base::RunLoop().RunUntilIdle();
146 // Legacy tokens get discarded, but the old refresh token is kept.
147 EXPECT_EQ(1, tokens_loaded_count_);
148 EXPECT_EQ(1, token_available_count_);
149 EXPECT_TRUE(oauth2_service_->RefreshTokenIsAvailable(main_account_id));
150 EXPECT_EQ(1U, oauth2_service_->refresh_tokens().size());
151 EXPECT_EQ(main_refresh_token,
152 oauth2_service_->refresh_tokens()[main_account_id]->refresh_token());
154 // Add an old legacy token to the DB, to ensure it will not overwrite existing
155 // credentials for main account.
156 AddAuthTokenManually(
157 GaiaConstants::kGaiaOAuth2LoginRefreshToken,
158 "secondOldRefreshToken");
159 // Add some other legacy token. (Expected to get discarded).
160 AddAuthTokenManually(kLSOService, "lsoToken");
161 // Also add a token using PO2TS.UpdateCredentials and make sure upgrade does
163 std::string other_account_id("other_account_id");
164 std::string other_refresh_token("other_refresh_token");
165 oauth2_service_->UpdateCredentials(other_account_id, other_refresh_token);
166 ResetObserverCounts();
168 // Force LoadCredentials.
169 oauth2_service_->LoadCredentials(main_account_id);
170 base::RunLoop().RunUntilIdle();
172 // Again legacy tokens get discarded, but since the main porfile account
173 // token is present it is not overwritten.
174 EXPECT_EQ(2, token_available_count_);
175 EXPECT_EQ(1, tokens_loaded_count_);
176 EXPECT_TRUE(oauth2_service_->RefreshTokenIsAvailable(main_account_id));
177 // TODO(fgorski): cover both using RefreshTokenIsAvailable() and then get the
178 // tokens using GetRefreshToken()
179 EXPECT_EQ(2U, oauth2_service_->refresh_tokens().size());
180 EXPECT_EQ(main_refresh_token,
181 oauth2_service_->refresh_tokens()[
182 main_account_id]->refresh_token());
185 oauth2_service_->refresh_tokens()[other_account_id]->refresh_token());
187 oauth2_service_->RevokeAllCredentials();
190 TEST_F(MutableProfileOAuth2TokenServiceTest, PersistenceRevokeCredentials) {
191 std::string account_id_1 = "account_id_1";
192 std::string refresh_token_1 = "refresh_token_1";
193 std::string account_id_2 = "account_id_2";
194 std::string refresh_token_2 = "refresh_token_2";
196 // TODO(fgorski): Enable below when implemented:
197 // EXPECT_FALSE(oauth2_servive_->RefreshTokenIsAvailable(account_id_1));
198 // EXPECT_FALSE(oauth2_servive_->RefreshTokenIsAvailable(account_id_2));
200 oauth2_service_->UpdateCredentials(account_id_1, refresh_token_1);
201 oauth2_service_->UpdateCredentials(account_id_2, refresh_token_2);
203 // TODO(fgorski): Enable below when implemented:
204 // EXPECT_TRUE(oauth2_servive_->RefreshTokenIsAvailable(account_id_1));
205 // EXPECT_TRUE(oauth2_service_->RefreshTokenIsAvailable(account_id_2));
207 ResetObserverCounts();
208 oauth2_service_->RevokeCredentials(account_id_1);
209 ExpectOneTokenRevokedNotification();
211 // TODO(fgorski): Enable below when implemented:
212 // EXPECT_FALSE(oauth2_servive_->RefreshTokenIsAvailable(account_id_1));
213 // EXPECT_TRUE(oauth2_service_->RefreshTokenIsAvailable(account_id_2));
215 oauth2_service_->RevokeAllCredentials();
216 EXPECT_EQ(0, token_available_count_);
217 EXPECT_EQ(1, token_revoked_count_);
218 EXPECT_EQ(0, tokens_loaded_count_);
219 ResetObserverCounts();
222 TEST_F(MutableProfileOAuth2TokenServiceTest, PersistenceLoadCredentials) {
223 // Ensure DB is clean.
224 oauth2_service_->RevokeAllCredentials();
225 ResetObserverCounts();
226 // Perform a load from an empty DB.
227 oauth2_service_->LoadCredentials("account_id");
228 base::RunLoop().RunUntilIdle();
229 ExpectOneTokensLoadedNotification();
230 // LoadCredentials() guarantees that the account given to it as argument
231 // is in the refresh_token map.
232 EXPECT_EQ(1U, oauth2_service_->refresh_tokens().size());
234 oauth2_service_->refresh_tokens()["account_id"]->refresh_token().empty());
235 // Setup a DB with tokens that don't require upgrade and clear memory.
236 oauth2_service_->UpdateCredentials("account_id", "refresh_token");
237 oauth2_service_->UpdateCredentials("account_id2", "refresh_token2");
238 oauth2_service_->refresh_tokens().clear();
239 ResetObserverCounts();
241 oauth2_service_->LoadCredentials("account_id");
242 base::RunLoop().RunUntilIdle();
243 EXPECT_EQ(2, token_available_count_);
244 EXPECT_EQ(0, token_revoked_count_);
245 EXPECT_EQ(1, tokens_loaded_count_);
246 ResetObserverCounts();
248 // TODO(fgorski): Enable below when implemented:
249 // EXPECT_TRUE(oauth2_servive_->RefreshTokenIsAvailable("account_id"));
250 // EXPECT_TRUE(oauth2_service_->RefreshTokenIsAvailable("account_id2"));
252 oauth2_service_->RevokeAllCredentials();
253 EXPECT_EQ(0, token_available_count_);
254 EXPECT_EQ(2, token_revoked_count_);
255 EXPECT_EQ(0, tokens_loaded_count_);
256 ResetObserverCounts();
259 TEST_F(MutableProfileOAuth2TokenServiceTest, PersistanceNotifications) {
260 EXPECT_EQ(0, oauth2_service_->cache_size_for_testing());
261 oauth2_service_->UpdateCredentials("account_id", "refresh_token");
262 ExpectOneTokenAvailableNotification();
264 oauth2_service_->UpdateCredentials("account_id", "refresh_token");
265 ExpectNoNotifications();
267 oauth2_service_->UpdateCredentials("account_id", "refresh_token2");
268 ExpectOneTokenAvailableNotification();
270 oauth2_service_->RevokeCredentials("account_id");
271 ExpectOneTokenRevokedNotification();
273 oauth2_service_->UpdateCredentials("account_id", "refresh_token2");
274 ExpectOneTokenAvailableNotification();
276 oauth2_service_->RevokeAllCredentials();
277 ResetObserverCounts();
280 TEST_F(MutableProfileOAuth2TokenServiceTest, GetAccounts) {
281 EXPECT_TRUE(oauth2_service_->GetAccounts().empty());
282 oauth2_service_->UpdateCredentials("account_id1", "refresh_token1");
283 oauth2_service_->UpdateCredentials("account_id2", "refresh_token2");
284 std::vector<std::string> accounts = oauth2_service_->GetAccounts();
285 EXPECT_EQ(2u, accounts.size());
286 EXPECT_EQ(1, count(accounts.begin(), accounts.end(), "account_id1"));
287 EXPECT_EQ(1, count(accounts.begin(), accounts.end(), "account_id2"));
288 oauth2_service_->RevokeCredentials("account_id2");
289 accounts = oauth2_service_->GetAccounts();
290 EXPECT_EQ(1u, oauth2_service_->GetAccounts().size());
291 EXPECT_EQ(1, count(accounts.begin(), accounts.end(), "account_id1"));
294 TEST_F(MutableProfileOAuth2TokenServiceTest, TokenServiceUpdateClearsCache) {
295 EXPECT_EQ(0, oauth2_service_->cache_size_for_testing());
296 std::set<std::string> scope_list;
297 scope_list.insert("scope");
298 oauth2_service_->UpdateCredentials(kEmail, "refreshToken");
299 ExpectOneTokenAvailableNotification();
300 factory_.SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_url(),
301 GetValidTokenResponse("token", 3600),
302 net::HTTP_OK, net::URLRequestStatus::SUCCESS);
304 scoped_ptr<OAuth2TokenService::Request> request(
305 oauth2_service_->StartRequest(kEmail, scope_list, &consumer_));
306 base::RunLoop().RunUntilIdle();
307 EXPECT_EQ(1, consumer_.number_of_successful_tokens_);
308 EXPECT_EQ(0, consumer_.number_of_errors_);
309 EXPECT_EQ("token", consumer_.last_token_);
310 EXPECT_EQ(1, oauth2_service_->cache_size_for_testing());
312 // Signs out and signs in
313 oauth2_service_->RevokeCredentials(kEmail);
314 ExpectOneTokenRevokedNotification();
316 EXPECT_EQ(0, oauth2_service_->cache_size_for_testing());
317 oauth2_service_->UpdateCredentials(kEmail, "refreshToken");
318 ExpectOneTokenAvailableNotification();
319 factory_.SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_url(),
320 GetValidTokenResponse("another token", 3600),
321 net::HTTP_OK, net::URLRequestStatus::SUCCESS);
323 request = oauth2_service_->StartRequest(kEmail, scope_list, &consumer_);
324 base::RunLoop().RunUntilIdle();
325 EXPECT_EQ(2, consumer_.number_of_successful_tokens_);
326 EXPECT_EQ(0, consumer_.number_of_errors_);
327 EXPECT_EQ("another token", consumer_.last_token_);
328 EXPECT_EQ(1, oauth2_service_->cache_size_for_testing());
331 TEST_F(MutableProfileOAuth2TokenServiceTest, FetchTransientError) {
332 factory_.SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_url(),
333 "", net::HTTP_FORBIDDEN,
334 net::URLRequestStatus::FAILED);
336 EXPECT_EQ(0, oauth2_service_->cache_size_for_testing());
337 std::set<std::string> scope_list;
338 scope_list.insert("scope");
339 oauth2_service_->set_max_authorization_token_fetch_retries_for_testing(0);
340 oauth2_service_->UpdateCredentials(kEmail, "refreshToken");
341 ExpectOneTokenAvailableNotification();
343 scoped_ptr<OAuth2TokenService::Request> request(
344 oauth2_service_->StartRequest(kEmail, scope_list, &consumer_));
345 base::RunLoop().RunUntilIdle();
346 EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
347 oauth2_service_->signin_error_controller()->auth_error());