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