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.
8 #include "base/message_loop/message_loop.h"
9 #include "base/prefs/pref_registry_simple.h"
10 #include "base/prefs/testing_pref_service.h"
11 #include "base/strings/stringprintf.h"
12 #include "components/signin/core/browser/account_tracker_service.h"
13 #include "google_apis/gaia/fake_oauth2_token_service.h"
14 #include "google_apis/gaia/gaia_oauth_client.h"
15 #include "net/http/http_status_code.h"
16 #include "net/url_request/test_url_fetcher_factory.h"
17 #include "net/url_request/url_fetcher_delegate.h"
18 #include "net/url_request/url_request_test_util.h"
19 #include "testing/gtest/include/gtest/gtest.h"
23 enum TrackingEventType
{
28 std::string
AccountIdToEmail(const std::string account_id
) {
29 return account_id
+ "@gmail.com";
32 std::string
AccountIdToGaiaId(const std::string account_id
) {
33 return "gaia-" + account_id
;
38 TrackingEvent(TrackingEventType type
,
39 const std::string
& account_id
,
40 const std::string
& gaia_id
)
42 account_id_(account_id
),
45 TrackingEvent(TrackingEventType type
,
46 const std::string
& account_id
)
48 account_id_(account_id
),
49 gaia_id_(AccountIdToGaiaId(account_id
)) {}
51 bool operator==(const TrackingEvent
& event
) const {
52 return type_
== event
.type_
&& account_id_
== event
.account_id_
&&
53 gaia_id_
== event
.gaia_id_
;
56 std::string
ToString() const {
57 const char * typestr
= "INVALID";
66 return base::StringPrintf("{ type: %s, account_id: %s, gaia: %s }",
73 friend bool CompareByUser(TrackingEvent a
, TrackingEvent b
);
75 TrackingEventType type_
;
76 std::string account_id_
;
80 bool CompareByUser(TrackingEvent a
, TrackingEvent b
) {
81 return a
.account_id_
< b
.account_id_
;
84 std::string
Str(const std::vector
<TrackingEvent
>& events
) {
85 std::string str
= "[";
86 bool needs_comma
= false;
87 for (std::vector
<TrackingEvent
>::const_iterator it
=
88 events
.begin(); it
!= events
.end(); ++it
) {
92 str
+= it
->ToString();
98 class AccountTrackerObserver
: public AccountTrackerService::Observer
{
100 AccountTrackerObserver() {}
101 virtual ~AccountTrackerObserver() {}
104 void SortEventsByUser();
106 testing::AssertionResult
CheckEvents();
107 testing::AssertionResult
CheckEvents(const TrackingEvent
& e1
);
108 testing::AssertionResult
CheckEvents(const TrackingEvent
& e1
,
109 const TrackingEvent
& e2
);
110 testing::AssertionResult
CheckEvents(const TrackingEvent
& e1
,
111 const TrackingEvent
& e2
,
112 const TrackingEvent
& e3
);
115 // AccountTrackerService::Observer implementation
116 virtual void OnAccountUpdated(
117 const AccountTrackerService::AccountInfo
& ids
) OVERRIDE
;
118 virtual void OnAccountRemoved(
119 const AccountTrackerService::AccountInfo
& ids
) OVERRIDE
;
121 testing::AssertionResult
CheckEvents(
122 const std::vector
<TrackingEvent
>& events
);
124 std::vector
<TrackingEvent
> events_
;
127 void AccountTrackerObserver::OnAccountUpdated(
128 const AccountTrackerService::AccountInfo
& ids
) {
129 events_
.push_back(TrackingEvent(UPDATED
, ids
.account_id
, ids
.gaia
));
132 void AccountTrackerObserver::OnAccountRemoved(
133 const AccountTrackerService::AccountInfo
& ids
) {
134 events_
.push_back(TrackingEvent(REMOVED
, ids
.account_id
, ids
.gaia
));
137 void AccountTrackerObserver::Clear() {
141 void AccountTrackerObserver::SortEventsByUser() {
142 std::stable_sort(events_
.begin(), events_
.end(), CompareByUser
);
145 testing::AssertionResult
AccountTrackerObserver::CheckEvents() {
146 std::vector
<TrackingEvent
> events
;
147 return CheckEvents(events
);
150 testing::AssertionResult
AccountTrackerObserver::CheckEvents(
151 const TrackingEvent
& e1
) {
152 std::vector
<TrackingEvent
> events
;
153 events
.push_back(e1
);
154 return CheckEvents(events
);
157 testing::AssertionResult
AccountTrackerObserver::CheckEvents(
158 const TrackingEvent
& e1
,
159 const TrackingEvent
& e2
) {
160 std::vector
<TrackingEvent
> events
;
161 events
.push_back(e1
);
162 events
.push_back(e2
);
163 return CheckEvents(events
);
166 testing::AssertionResult
AccountTrackerObserver::CheckEvents(
167 const TrackingEvent
& e1
,
168 const TrackingEvent
& e2
,
169 const TrackingEvent
& e3
) {
170 std::vector
<TrackingEvent
> events
;
171 events
.push_back(e1
);
172 events
.push_back(e2
);
173 events
.push_back(e3
);
174 return CheckEvents(events
);
177 testing::AssertionResult
AccountTrackerObserver::CheckEvents(
178 const std::vector
<TrackingEvent
>& events
) {
179 std::string maybe_newline
= (events
.size() + events_
.size()) > 2 ? "\n" : "";
180 testing::AssertionResult
result(
182 ? testing::AssertionSuccess()
183 : (testing::AssertionFailure()
184 << "Expected " << maybe_newline
<< Str(events
) << ", "
185 << maybe_newline
<< "Got " << maybe_newline
<< Str(events_
)));
192 class AccountTrackerServiceTest
: public testing::Test
{
194 AccountTrackerServiceTest() {}
196 virtual ~AccountTrackerServiceTest() {}
198 virtual void SetUp() OVERRIDE
{
199 fake_oauth2_token_service_
.reset(new FakeOAuth2TokenService());
201 pref_service_
.registry()->RegisterListPref(
202 AccountTrackerService::kAccountInfoPref
);
204 account_tracker_
.reset(new AccountTrackerService());
205 account_tracker_
->Initialize(fake_oauth2_token_service_
.get(),
207 new net::TestURLRequestContextGetter(
208 message_loop_
.message_loop_proxy()));
209 account_tracker_
->AddObserver(&observer_
);
212 virtual void TearDown() OVERRIDE
{
213 account_tracker_
->RemoveObserver(&observer_
);
214 account_tracker_
->Shutdown();
217 void SimulateTokenAvailable(const std::string
& account_id
) {
218 fake_oauth2_token_service_
->AddAccount(account_id
);
221 void SimulateTokenRevoked(const std::string
& account_id
) {
222 fake_oauth2_token_service_
->RemoveAccount(account_id
);
225 // Helpers to fake access token and user info fetching
226 void IssueAccessToken(const std::string
& account_id
) {
227 fake_oauth2_token_service_
->IssueAllTokensForAccount(
228 account_id
, "access_token-" + account_id
, base::Time::Max());
231 std::string
GenerateValidTokenInfoResponse(const std::string
& account_id
) {
232 return base::StringPrintf("{\"id\": \"%s\", \"email\": \"%s\"}",
233 AccountIdToGaiaId(account_id
).c_str(),
234 AccountIdToEmail(account_id
).c_str());
237 void ReturnOAuthUrlFetchSuccess(const std::string
& account_id
);
238 void ReturnOAuthUrlFetchFailure(const std::string
& account_id
);
240 base::MessageLoopForIO
* message_loop() { return &message_loop_
; }
241 AccountTrackerService
* account_tracker() { return account_tracker_
.get(); }
242 AccountTrackerObserver
* observer() { return &observer_
; }
243 OAuth2TokenService
* token_service() {
244 return fake_oauth2_token_service_
.get();
246 TestingPrefServiceSimple
* pref_service() { return &pref_service_
; }
249 void ReturnOAuthUrlFetchResults(int fetcher_id
,
250 net::HttpStatusCode response_code
,
251 const std::string
& response_string
);
253 base::MessageLoopForIO message_loop_
;
254 net::TestURLFetcherFactory test_fetcher_factory_
;
255 scoped_ptr
<FakeOAuth2TokenService
> fake_oauth2_token_service_
;
256 TestingPrefServiceSimple pref_service_
;
257 scoped_ptr
<AccountTrackerService
> account_tracker_
;
258 AccountTrackerObserver observer_
;
261 void AccountTrackerServiceTest::ReturnOAuthUrlFetchResults(
263 net::HttpStatusCode response_code
,
264 const std::string
& response_string
) {
265 net::TestURLFetcher
* fetcher
=
266 test_fetcher_factory_
.GetFetcherByID(fetcher_id
);
267 ASSERT_TRUE(fetcher
);
268 fetcher
->set_response_code(response_code
);
269 fetcher
->SetResponseString(response_string
);
270 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
273 void AccountTrackerServiceTest::ReturnOAuthUrlFetchSuccess(
274 const std::string
& account_id
) {
275 IssueAccessToken(account_id
);
276 ReturnOAuthUrlFetchResults(gaia::GaiaOAuthClient::kUrlFetcherId
,
278 GenerateValidTokenInfoResponse(account_id
));
281 void AccountTrackerServiceTest::ReturnOAuthUrlFetchFailure(
282 const std::string
& account_id
) {
283 IssueAccessToken(account_id
);
284 ReturnOAuthUrlFetchResults(
285 gaia::GaiaOAuthClient::kUrlFetcherId
, net::HTTP_BAD_REQUEST
, "");
288 TEST_F(AccountTrackerServiceTest
, Basic
) {
291 TEST_F(AccountTrackerServiceTest
, TokenAvailable
) {
292 SimulateTokenAvailable("alpha");
293 ASSERT_FALSE(account_tracker()->IsAllUserInfoFetched());
294 ASSERT_TRUE(observer()->CheckEvents());
297 TEST_F(AccountTrackerServiceTest
, TokenAvailable_Revoked
) {
298 SimulateTokenAvailable("alpha");
299 SimulateTokenRevoked("alpha");
300 ASSERT_TRUE(account_tracker()->IsAllUserInfoFetched());
301 ASSERT_TRUE(observer()->CheckEvents());
304 TEST_F(AccountTrackerServiceTest
, TokenAvailable_UserInfo
) {
305 SimulateTokenAvailable("alpha");
306 ReturnOAuthUrlFetchSuccess("alpha");
307 ASSERT_TRUE(account_tracker()->IsAllUserInfoFetched());
308 ASSERT_TRUE(observer()->CheckEvents(TrackingEvent(UPDATED
, "alpha")));
311 TEST_F(AccountTrackerServiceTest
, TokenAvailable_UserInfo_Revoked
) {
312 SimulateTokenAvailable("alpha");
313 ReturnOAuthUrlFetchSuccess("alpha");
314 ASSERT_TRUE(account_tracker()->IsAllUserInfoFetched());
315 ASSERT_TRUE(observer()->CheckEvents(TrackingEvent(UPDATED
, "alpha")));
316 SimulateTokenRevoked("alpha");
317 ASSERT_TRUE(observer()->CheckEvents(TrackingEvent(REMOVED
, "alpha")));
320 TEST_F(AccountTrackerServiceTest
, TokenAvailable_UserInfoFailed
) {
321 SimulateTokenAvailable("alpha");
322 ReturnOAuthUrlFetchFailure("alpha");
323 ASSERT_TRUE(account_tracker()->IsAllUserInfoFetched());
324 ASSERT_TRUE(observer()->CheckEvents());
327 TEST_F(AccountTrackerServiceTest
, TokenAlreadyExists
) {
328 SimulateTokenAvailable("alpha");
329 AccountTrackerService tracker
;
330 AccountTrackerObserver observer
;
331 tracker
.AddObserver(&observer
);
332 tracker
.Initialize(token_service(),
334 new net::TestURLRequestContextGetter(
335 message_loop()->message_loop_proxy()));
336 ASSERT_FALSE(tracker
.IsAllUserInfoFetched());
337 ASSERT_TRUE(observer
.CheckEvents());
338 tracker
.RemoveObserver(&observer
);
342 TEST_F(AccountTrackerServiceTest
, TwoTokenAvailable_TwoUserInfo
) {
343 SimulateTokenAvailable("alpha");
344 SimulateTokenAvailable("beta");
345 ReturnOAuthUrlFetchSuccess("alpha");
346 ReturnOAuthUrlFetchSuccess("beta");
347 ASSERT_TRUE(account_tracker()->IsAllUserInfoFetched());
348 ASSERT_TRUE(observer()->CheckEvents(TrackingEvent(UPDATED
, "alpha"),
349 TrackingEvent(UPDATED
, "beta")));
352 TEST_F(AccountTrackerServiceTest
, TwoTokenAvailable_OneUserInfo
) {
353 SimulateTokenAvailable("alpha");
354 SimulateTokenAvailable("beta");
355 ReturnOAuthUrlFetchSuccess("beta");
356 ASSERT_FALSE(account_tracker()->IsAllUserInfoFetched());
357 ASSERT_TRUE(observer()->CheckEvents(TrackingEvent(UPDATED
, "beta")));
358 ReturnOAuthUrlFetchSuccess("alpha");
359 ASSERT_TRUE(account_tracker()->IsAllUserInfoFetched());
360 ASSERT_TRUE(observer()->CheckEvents(TrackingEvent(UPDATED
, "alpha")));
363 TEST_F(AccountTrackerServiceTest
, GetAccounts
) {
364 SimulateTokenAvailable("alpha");
365 SimulateTokenAvailable("beta");
366 SimulateTokenAvailable("gamma");
367 ReturnOAuthUrlFetchSuccess("alpha");
368 ReturnOAuthUrlFetchSuccess("beta");
369 ReturnOAuthUrlFetchSuccess("gamma");
371 std::vector
<AccountTrackerService::AccountInfo
> infos
=
372 account_tracker()->GetAccounts();
374 EXPECT_EQ(3u, infos
.size());
375 EXPECT_EQ("alpha", infos
[0].account_id
);
376 EXPECT_EQ(AccountIdToGaiaId("alpha"), infos
[0].gaia
);
377 EXPECT_EQ(AccountIdToEmail("alpha"), infos
[0].email
);
378 EXPECT_EQ("beta", infos
[1].account_id
);
379 EXPECT_EQ(AccountIdToGaiaId("beta"), infos
[1].gaia
);
380 EXPECT_EQ(AccountIdToEmail("beta"), infos
[1].email
);
381 EXPECT_EQ("gamma", infos
[2].account_id
);
382 EXPECT_EQ(AccountIdToGaiaId("gamma"), infos
[2].gaia
);
383 EXPECT_EQ(AccountIdToEmail("gamma"), infos
[2].email
);
386 TEST_F(AccountTrackerServiceTest
, GetAccountInfo_Empty
) {
387 AccountTrackerService::AccountInfo info
=
388 account_tracker()->GetAccountInfo("alpha");
389 ASSERT_EQ("", info
.account_id
);
392 TEST_F(AccountTrackerServiceTest
, GetAccountInfo_TokenAvailable
) {
393 SimulateTokenAvailable("alpha");
394 AccountTrackerService::AccountInfo info
=
395 account_tracker()->GetAccountInfo("alpha");
396 ASSERT_EQ("alpha", info
.account_id
);
397 ASSERT_EQ("", info
.gaia
);
398 ASSERT_EQ("", info
.email
);
401 TEST_F(AccountTrackerServiceTest
, GetAccountInfo_TokenAvailable_UserInfo
) {
402 SimulateTokenAvailable("alpha");
403 ReturnOAuthUrlFetchSuccess("alpha");
404 AccountTrackerService::AccountInfo info
=
405 account_tracker()->GetAccountInfo("alpha");
406 ASSERT_EQ("alpha", info
.account_id
);
407 ASSERT_EQ(AccountIdToGaiaId("alpha"), info
.gaia
);
408 ASSERT_EQ(AccountIdToEmail("alpha"), info
.email
);
411 TEST_F(AccountTrackerServiceTest
, FindAccountInfoByGaiaId
) {
412 SimulateTokenAvailable("alpha");
413 ReturnOAuthUrlFetchSuccess("alpha");
415 std::string gaia_id
= AccountIdToGaiaId("alpha");
416 AccountTrackerService::AccountInfo info
=
417 account_tracker()->FindAccountInfoByGaiaId(gaia_id
);
418 ASSERT_EQ("alpha", info
.account_id
);
419 ASSERT_EQ(gaia_id
, info
.gaia
);
421 gaia_id
= AccountIdToGaiaId("beta");
422 info
= account_tracker()->FindAccountInfoByGaiaId(gaia_id
);
423 ASSERT_EQ("", info
.account_id
);
426 TEST_F(AccountTrackerServiceTest
, FindAccountInfoByEmail
) {
427 SimulateTokenAvailable("alpha");
428 ReturnOAuthUrlFetchSuccess("alpha");
430 std::string email
= AccountIdToEmail("alpha");
431 AccountTrackerService::AccountInfo info
=
432 account_tracker()->FindAccountInfoByEmail(email
);
433 ASSERT_EQ("alpha", info
.account_id
);
434 ASSERT_EQ(email
, info
.email
);
436 // Should also work with "canonically-equal" email addresses.
437 info
= account_tracker()->FindAccountInfoByEmail("Alpha@Gmail.COM");
438 ASSERT_EQ("alpha", info
.account_id
);
439 ASSERT_EQ(email
, info
.email
);
440 info
= account_tracker()->FindAccountInfoByEmail("al.pha@gmail.com");
441 ASSERT_EQ("alpha", info
.account_id
);
442 ASSERT_EQ(email
, info
.email
);
444 email
= AccountIdToEmail("beta");
445 info
= account_tracker()->FindAccountInfoByEmail(email
);
446 ASSERT_EQ("", info
.account_id
);
449 TEST_F(AccountTrackerServiceTest
, Persistence
) {
450 // Create a tracker and add two accounts. This should cause the accounts
451 // to be saved to persistence.
453 AccountTrackerService tracker
;
454 tracker
.Initialize(token_service(),
456 new net::TestURLRequestContextGetter(
457 message_loop()->message_loop_proxy()));
458 SimulateTokenAvailable("alpha");
459 ReturnOAuthUrlFetchSuccess("alpha");
460 SimulateTokenAvailable("beta");
461 ReturnOAuthUrlFetchSuccess("beta");
465 // Create a new tracker and make sure it loads the accounts corectly from
468 AccountTrackerService tracker
;
469 tracker
.AddObserver(observer());
470 tracker
.Initialize(token_service(),
472 new net::TestURLRequestContextGetter(
473 message_loop()->message_loop_proxy()));
474 ASSERT_TRUE(observer()->CheckEvents(TrackingEvent(UPDATED
, "alpha"),
475 TrackingEvent(UPDATED
, "beta")));
477 std::vector
<AccountTrackerService::AccountInfo
> infos
=
478 tracker
.GetAccounts();
479 ASSERT_EQ(2u, infos
.size());
480 EXPECT_EQ(AccountIdToGaiaId("alpha"), infos
[0].gaia
);
481 EXPECT_EQ(AccountIdToEmail("alpha"), infos
[0].email
);
482 EXPECT_EQ("beta", infos
[1].account_id
);
483 EXPECT_EQ(AccountIdToGaiaId("beta"), infos
[1].gaia
);
484 EXPECT_EQ(AccountIdToEmail("beta"), infos
[1].email
);
487 SimulateTokenRevoked("alpha");
488 tracker
.RemoveObserver(observer());
492 // Create a new tracker and make sure it loads the single account from
495 AccountTrackerService tracker
;
496 tracker
.Initialize(token_service(),
498 new net::TestURLRequestContextGetter(
499 message_loop()->message_loop_proxy()));
501 std::vector
<AccountTrackerService::AccountInfo
> infos
=
502 tracker
.GetAccounts();
503 ASSERT_EQ(1u, infos
.size());
504 EXPECT_EQ("beta", infos
[0].account_id
);
505 EXPECT_EQ(AccountIdToGaiaId("beta"), infos
[0].gaia
);
506 EXPECT_EQ(AccountIdToEmail("beta"), infos
[0].email
);