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 "components/signin/core/browser/test_signin_client.h"
14 #include "components/signin/core/common/signin_pref_names.h"
15 #include "google_apis/gaia/fake_oauth2_token_service.h"
16 #include "google_apis/gaia/gaia_oauth_client.h"
17 #include "net/http/http_status_code.h"
18 #include "net/url_request/test_url_fetcher_factory.h"
19 #include "net/url_request/url_fetcher_delegate.h"
20 #include "net/url_request/url_request_test_util.h"
21 #include "testing/gtest/include/gtest/gtest.h"
25 enum TrackingEventType
{
30 std::string
AccountIdToEmail(const std::string account_id
) {
31 return account_id
+ "@gmail.com";
34 std::string
AccountIdToGaiaId(const std::string account_id
) {
35 return "gaia-" + account_id
;
40 TrackingEvent(TrackingEventType type
,
41 const std::string
& account_id
,
42 const std::string
& gaia_id
)
44 account_id_(account_id
),
47 TrackingEvent(TrackingEventType type
,
48 const std::string
& account_id
)
50 account_id_(account_id
),
51 gaia_id_(AccountIdToGaiaId(account_id
)) {}
53 bool operator==(const TrackingEvent
& event
) const {
54 return type_
== event
.type_
&& account_id_
== event
.account_id_
&&
55 gaia_id_
== event
.gaia_id_
;
58 std::string
ToString() const {
59 const char * typestr
= "INVALID";
68 return base::StringPrintf("{ type: %s, account_id: %s, gaia: %s }",
75 friend bool CompareByUser(TrackingEvent a
, TrackingEvent b
);
77 TrackingEventType type_
;
78 std::string account_id_
;
82 bool CompareByUser(TrackingEvent a
, TrackingEvent b
) {
83 return a
.account_id_
< b
.account_id_
;
86 std::string
Str(const std::vector
<TrackingEvent
>& events
) {
87 std::string str
= "[";
88 bool needs_comma
= false;
89 for (std::vector
<TrackingEvent
>::const_iterator it
=
90 events
.begin(); it
!= events
.end(); ++it
) {
94 str
+= it
->ToString();
100 class AccountTrackerObserver
: public AccountTrackerService::Observer
{
102 AccountTrackerObserver() {}
103 ~AccountTrackerObserver() override
{}
106 void SortEventsByUser();
108 testing::AssertionResult
CheckEvents();
109 testing::AssertionResult
CheckEvents(const TrackingEvent
& e1
);
110 testing::AssertionResult
CheckEvents(const TrackingEvent
& e1
,
111 const TrackingEvent
& e2
);
112 testing::AssertionResult
CheckEvents(const TrackingEvent
& e1
,
113 const TrackingEvent
& e2
,
114 const TrackingEvent
& e3
);
117 // AccountTrackerService::Observer implementation
118 void OnAccountUpdated(const AccountTrackerService::AccountInfo
& ids
) override
;
119 void OnAccountRemoved(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 ~AccountTrackerServiceTest() override
{}
198 void SetUp() override
{
199 fake_oauth2_token_service_
.reset(new FakeOAuth2TokenService());
201 pref_service_
.registry()->RegisterListPref(
202 AccountTrackerService::kAccountInfoPref
);
203 pref_service_
.registry()->RegisterIntegerPref(
204 prefs::kAccountIdMigrationState
,
205 AccountTrackerService::MIGRATION_NOT_STARTED
);
206 signin_client_
.reset(new TestSigninClient(&pref_service_
));
207 signin_client_
.get()->SetURLRequestContext(
208 new net::TestURLRequestContextGetter(
209 message_loop_
.message_loop_proxy()));
211 account_tracker_
.reset(new AccountTrackerService());
212 account_tracker_
->Initialize(fake_oauth2_token_service_
.get(),
213 signin_client_
.get());
214 account_tracker_
->AddObserver(&observer_
);
217 void TearDown() override
{
218 account_tracker_
->RemoveObserver(&observer_
);
219 account_tracker_
->Shutdown();
222 void SimulateTokenAvailable(const std::string
& account_id
) {
223 fake_oauth2_token_service_
->AddAccount(account_id
);
226 void SimulateTokenRevoked(const std::string
& account_id
) {
227 fake_oauth2_token_service_
->RemoveAccount(account_id
);
230 // Helpers to fake access token and user info fetching
231 void IssueAccessToken(const std::string
& account_id
) {
232 fake_oauth2_token_service_
->IssueAllTokensForAccount(
233 account_id
, "access_token-" + account_id
, base::Time::Max());
236 std::string
GenerateValidTokenInfoResponse(const std::string
& account_id
) {
237 return base::StringPrintf(
238 "{\"id\": \"%s\", \"email\": \"%s\", \"hd\": \"\"}",
239 AccountIdToGaiaId(account_id
).c_str(),
240 AccountIdToEmail(account_id
).c_str());
243 void ReturnOAuthUrlFetchSuccess(const std::string
& account_id
);
244 void ReturnOAuthUrlFetchFailure(const std::string
& account_id
);
246 base::MessageLoopForIO
* message_loop() { return &message_loop_
; }
247 AccountTrackerService
* account_tracker() { return account_tracker_
.get(); }
248 AccountTrackerObserver
* observer() { return &observer_
; }
249 OAuth2TokenService
* token_service() {
250 return fake_oauth2_token_service_
.get();
252 TestingPrefServiceSimple
* pref_service() { return &pref_service_
; }
253 SigninClient
* signin_client() { return signin_client_
.get(); }
256 void ReturnOAuthUrlFetchResults(int fetcher_id
,
257 net::HttpStatusCode response_code
,
258 const std::string
& response_string
);
260 base::MessageLoopForIO message_loop_
;
261 net::TestURLFetcherFactory test_fetcher_factory_
;
262 scoped_ptr
<FakeOAuth2TokenService
> fake_oauth2_token_service_
;
263 TestingPrefServiceSimple pref_service_
;
264 scoped_ptr
<AccountTrackerService
> account_tracker_
;
265 AccountTrackerObserver observer_
;
266 scoped_ptr
<TestSigninClient
> signin_client_
;
269 void AccountTrackerServiceTest::ReturnOAuthUrlFetchResults(
271 net::HttpStatusCode response_code
,
272 const std::string
& response_string
) {
273 net::TestURLFetcher
* fetcher
=
274 test_fetcher_factory_
.GetFetcherByID(fetcher_id
);
275 ASSERT_TRUE(fetcher
);
276 fetcher
->set_response_code(response_code
);
277 fetcher
->SetResponseString(response_string
);
278 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
281 void AccountTrackerServiceTest::ReturnOAuthUrlFetchSuccess(
282 const std::string
& account_id
) {
283 IssueAccessToken(account_id
);
284 ReturnOAuthUrlFetchResults(gaia::GaiaOAuthClient::kUrlFetcherId
,
286 GenerateValidTokenInfoResponse(account_id
));
289 void AccountTrackerServiceTest::ReturnOAuthUrlFetchFailure(
290 const std::string
& account_id
) {
291 IssueAccessToken(account_id
);
292 ReturnOAuthUrlFetchResults(
293 gaia::GaiaOAuthClient::kUrlFetcherId
, net::HTTP_BAD_REQUEST
, "");
296 TEST_F(AccountTrackerServiceTest
, Basic
) {
299 TEST_F(AccountTrackerServiceTest
, TokenAvailable
) {
300 SimulateTokenAvailable("alpha");
301 ASSERT_FALSE(account_tracker()->IsAllUserInfoFetched());
302 ASSERT_TRUE(observer()->CheckEvents());
305 TEST_F(AccountTrackerServiceTest
, TokenAvailable_Revoked
) {
306 SimulateTokenAvailable("alpha");
307 SimulateTokenRevoked("alpha");
308 ASSERT_TRUE(account_tracker()->IsAllUserInfoFetched());
309 ASSERT_TRUE(observer()->CheckEvents());
312 TEST_F(AccountTrackerServiceTest
, TokenAvailable_UserInfo
) {
313 SimulateTokenAvailable("alpha");
314 ReturnOAuthUrlFetchSuccess("alpha");
315 ASSERT_TRUE(account_tracker()->IsAllUserInfoFetched());
316 ASSERT_TRUE(observer()->CheckEvents(TrackingEvent(UPDATED
, "alpha")));
319 TEST_F(AccountTrackerServiceTest
, TokenAvailable_UserInfo_Revoked
) {
320 SimulateTokenAvailable("alpha");
321 ReturnOAuthUrlFetchSuccess("alpha");
322 ASSERT_TRUE(account_tracker()->IsAllUserInfoFetched());
323 ASSERT_TRUE(observer()->CheckEvents(TrackingEvent(UPDATED
, "alpha")));
324 SimulateTokenRevoked("alpha");
325 ASSERT_TRUE(observer()->CheckEvents(TrackingEvent(REMOVED
, "alpha")));
328 TEST_F(AccountTrackerServiceTest
, TokenAvailable_UserInfoFailed
) {
329 SimulateTokenAvailable("alpha");
330 ReturnOAuthUrlFetchFailure("alpha");
331 ASSERT_TRUE(account_tracker()->IsAllUserInfoFetched());
332 ASSERT_TRUE(observer()->CheckEvents());
335 TEST_F(AccountTrackerServiceTest
, TokenAvailableTwice_UserInfoOnce
) {
336 SimulateTokenAvailable("alpha");
337 ReturnOAuthUrlFetchSuccess("alpha");
338 ASSERT_TRUE(account_tracker()->IsAllUserInfoFetched());
339 ASSERT_TRUE(observer()->CheckEvents(TrackingEvent(UPDATED
, "alpha")));
341 SimulateTokenAvailable("alpha");
342 ASSERT_TRUE(account_tracker()->IsAllUserInfoFetched());
343 ASSERT_TRUE(observer()->CheckEvents());
346 TEST_F(AccountTrackerServiceTest
, TokenAlreadyExists
) {
347 SimulateTokenAvailable("alpha");
348 AccountTrackerService tracker
;
349 AccountTrackerObserver observer
;
350 tracker
.AddObserver(&observer
);
351 tracker
.Initialize(token_service(), signin_client());
352 ASSERT_FALSE(tracker
.IsAllUserInfoFetched());
353 ASSERT_TRUE(observer
.CheckEvents());
354 tracker
.RemoveObserver(&observer
);
358 TEST_F(AccountTrackerServiceTest
, TwoTokenAvailable_TwoUserInfo
) {
359 SimulateTokenAvailable("alpha");
360 SimulateTokenAvailable("beta");
361 ReturnOAuthUrlFetchSuccess("alpha");
362 ReturnOAuthUrlFetchSuccess("beta");
363 ASSERT_TRUE(account_tracker()->IsAllUserInfoFetched());
364 ASSERT_TRUE(observer()->CheckEvents(TrackingEvent(UPDATED
, "alpha"),
365 TrackingEvent(UPDATED
, "beta")));
368 TEST_F(AccountTrackerServiceTest
, TwoTokenAvailable_OneUserInfo
) {
369 SimulateTokenAvailable("alpha");
370 SimulateTokenAvailable("beta");
371 ReturnOAuthUrlFetchSuccess("beta");
372 ASSERT_FALSE(account_tracker()->IsAllUserInfoFetched());
373 ASSERT_TRUE(observer()->CheckEvents(TrackingEvent(UPDATED
, "beta")));
374 ReturnOAuthUrlFetchSuccess("alpha");
375 ASSERT_TRUE(account_tracker()->IsAllUserInfoFetched());
376 ASSERT_TRUE(observer()->CheckEvents(TrackingEvent(UPDATED
, "alpha")));
379 TEST_F(AccountTrackerServiceTest
, GetAccounts
) {
380 SimulateTokenAvailable("alpha");
381 SimulateTokenAvailable("beta");
382 SimulateTokenAvailable("gamma");
383 ReturnOAuthUrlFetchSuccess("alpha");
384 ReturnOAuthUrlFetchSuccess("beta");
385 ReturnOAuthUrlFetchSuccess("gamma");
387 std::vector
<AccountTrackerService::AccountInfo
> infos
=
388 account_tracker()->GetAccounts();
390 EXPECT_EQ(3u, infos
.size());
391 EXPECT_EQ("alpha", infos
[0].account_id
);
392 EXPECT_EQ(AccountIdToGaiaId("alpha"), infos
[0].gaia
);
393 EXPECT_EQ(AccountIdToEmail("alpha"), infos
[0].email
);
394 EXPECT_EQ(AccountTrackerService::kNoHostedDomainFound
,
395 infos
[0].hosted_domain
);
396 EXPECT_EQ("beta", infos
[1].account_id
);
397 EXPECT_EQ(AccountIdToGaiaId("beta"), infos
[1].gaia
);
398 EXPECT_EQ(AccountIdToEmail("beta"), infos
[1].email
);
399 EXPECT_EQ(AccountTrackerService::kNoHostedDomainFound
,
400 infos
[1].hosted_domain
);
401 EXPECT_EQ("gamma", infos
[2].account_id
);
402 EXPECT_EQ(AccountIdToGaiaId("gamma"), infos
[2].gaia
);
403 EXPECT_EQ(AccountIdToEmail("gamma"), infos
[2].email
);
404 EXPECT_EQ(AccountTrackerService::kNoHostedDomainFound
,
405 infos
[2].hosted_domain
);
408 TEST_F(AccountTrackerServiceTest
, GetAccountInfo_Empty
) {
409 AccountTrackerService::AccountInfo info
=
410 account_tracker()->GetAccountInfo("alpha");
411 ASSERT_EQ("", info
.account_id
);
414 TEST_F(AccountTrackerServiceTest
, GetAccountInfo_TokenAvailable
) {
415 SimulateTokenAvailable("alpha");
416 AccountTrackerService::AccountInfo info
=
417 account_tracker()->GetAccountInfo("alpha");
418 ASSERT_EQ("alpha", info
.account_id
);
419 ASSERT_EQ("", info
.gaia
);
420 ASSERT_EQ("", info
.email
);
423 TEST_F(AccountTrackerServiceTest
, GetAccountInfo_TokenAvailable_UserInfo
) {
424 SimulateTokenAvailable("alpha");
425 ReturnOAuthUrlFetchSuccess("alpha");
426 AccountTrackerService::AccountInfo info
=
427 account_tracker()->GetAccountInfo("alpha");
428 ASSERT_EQ("alpha", info
.account_id
);
429 ASSERT_EQ(AccountIdToGaiaId("alpha"), info
.gaia
);
430 ASSERT_EQ(AccountIdToEmail("alpha"), info
.email
);
431 ASSERT_EQ(AccountTrackerService::kNoHostedDomainFound
, info
.hosted_domain
);
434 TEST_F(AccountTrackerServiceTest
, FindAccountInfoByGaiaId
) {
435 SimulateTokenAvailable("alpha");
436 ReturnOAuthUrlFetchSuccess("alpha");
438 std::string gaia_id
= AccountIdToGaiaId("alpha");
439 AccountTrackerService::AccountInfo info
=
440 account_tracker()->FindAccountInfoByGaiaId(gaia_id
);
441 ASSERT_EQ("alpha", info
.account_id
);
442 ASSERT_EQ(gaia_id
, info
.gaia
);
444 gaia_id
= AccountIdToGaiaId("beta");
445 info
= account_tracker()->FindAccountInfoByGaiaId(gaia_id
);
446 ASSERT_EQ("", info
.account_id
);
449 TEST_F(AccountTrackerServiceTest
, FindAccountInfoByEmail
) {
450 SimulateTokenAvailable("alpha");
451 ReturnOAuthUrlFetchSuccess("alpha");
453 std::string email
= AccountIdToEmail("alpha");
454 AccountTrackerService::AccountInfo info
=
455 account_tracker()->FindAccountInfoByEmail(email
);
456 ASSERT_EQ("alpha", info
.account_id
);
457 ASSERT_EQ(email
, info
.email
);
459 // Should also work with "canonically-equal" email addresses.
460 info
= account_tracker()->FindAccountInfoByEmail("Alpha@Gmail.COM");
461 ASSERT_EQ("alpha", info
.account_id
);
462 ASSERT_EQ(email
, info
.email
);
463 info
= account_tracker()->FindAccountInfoByEmail("al.pha@gmail.com");
464 ASSERT_EQ("alpha", info
.account_id
);
465 ASSERT_EQ(email
, info
.email
);
467 email
= AccountIdToEmail("beta");
468 info
= account_tracker()->FindAccountInfoByEmail(email
);
469 ASSERT_EQ("", info
.account_id
);
472 TEST_F(AccountTrackerServiceTest
, Persistence
) {
473 // Create a tracker and add two accounts. This should cause the accounts
474 // to be saved to persistence.
476 AccountTrackerService tracker
;
477 tracker
.Initialize(token_service(), signin_client());
478 SimulateTokenAvailable("alpha");
479 ReturnOAuthUrlFetchSuccess("alpha");
480 SimulateTokenAvailable("beta");
481 ReturnOAuthUrlFetchSuccess("beta");
485 // Create a new tracker and make sure it loads the accounts corectly from
488 AccountTrackerService tracker
;
489 tracker
.AddObserver(observer());
490 tracker
.Initialize(token_service(), signin_client());
491 ASSERT_TRUE(observer()->CheckEvents(TrackingEvent(UPDATED
, "alpha"),
492 TrackingEvent(UPDATED
, "beta")));
494 std::vector
<AccountTrackerService::AccountInfo
> infos
=
495 tracker
.GetAccounts();
496 ASSERT_EQ(2u, infos
.size());
497 EXPECT_EQ(AccountIdToGaiaId("alpha"), infos
[0].gaia
);
498 EXPECT_EQ(AccountIdToEmail("alpha"), infos
[0].email
);
499 EXPECT_EQ("beta", infos
[1].account_id
);
500 EXPECT_EQ(AccountIdToGaiaId("beta"), infos
[1].gaia
);
501 EXPECT_EQ(AccountIdToEmail("beta"), infos
[1].email
);
504 SimulateTokenRevoked("alpha");
505 tracker
.RemoveObserver(observer());
509 // Create a new tracker and make sure it loads the single account from
512 AccountTrackerService tracker
;
513 tracker
.Initialize(token_service(), signin_client());
515 std::vector
<AccountTrackerService::AccountInfo
> infos
=
516 tracker
.GetAccounts();
517 ASSERT_EQ(1u, infos
.size());
518 EXPECT_EQ("beta", infos
[0].account_id
);
519 EXPECT_EQ(AccountIdToGaiaId("beta"), infos
[0].gaia
);
520 EXPECT_EQ(AccountIdToEmail("beta"), infos
[0].email
);
525 TEST_F(AccountTrackerServiceTest
, SeedAccountInfo
) {
526 std::vector
<AccountTrackerService::AccountInfo
> infos
=
527 account_tracker()->GetAccounts();
528 EXPECT_EQ(0u, infos
.size());
530 const std::string gaia_id
= AccountIdToGaiaId("alpha");
531 const std::string email
= AccountIdToEmail("alpha");
532 const std::string account_id
=
533 account_tracker()->PickAccountIdForAccount(gaia_id
, email
);
534 account_tracker()->SeedAccountInfo(gaia_id
, email
);
536 infos
= account_tracker()->GetAccounts();
537 EXPECT_EQ(1u, infos
.size());
538 EXPECT_EQ(account_id
, infos
[0].account_id
);
539 EXPECT_EQ(gaia_id
, infos
[0].gaia
);
540 EXPECT_EQ(email
, infos
[0].email
);