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/command_line.h"
6 #include "base/memory/scoped_ptr.h"
7 #include "base/run_loop.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "base/test/histogram_tester.h"
10 #include "base/time/time.h"
11 #include "build/build_config.h"
12 #include "chrome/browser/prefs/pref_service_syncable.h"
13 #include "chrome/browser/signin/account_reconcilor_factory.h"
14 #include "chrome/browser/signin/account_tracker_service_factory.h"
15 #include "chrome/browser/signin/chrome_signin_client_factory.h"
16 #include "chrome/browser/signin/fake_gaia_cookie_manager_service.h"
17 #include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h"
18 #include "chrome/browser/signin/fake_signin_manager_builder.h"
19 #include "chrome/browser/signin/gaia_cookie_manager_service_factory.h"
20 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
21 #include "chrome/browser/signin/signin_manager_factory.h"
22 #include "chrome/browser/signin/test_signin_client_builder.h"
23 #include "chrome/test/base/testing_browser_process.h"
24 #include "chrome/test/base/testing_profile.h"
25 #include "chrome/test/base/testing_profile_manager.h"
26 #include "components/signin/core/browser/account_reconcilor.h"
27 #include "components/signin/core/browser/account_tracker_service.h"
28 #include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
29 #include "components/signin/core/browser/profile_oauth2_token_service.h"
30 #include "components/signin/core/browser/signin_manager.h"
31 #include "components/signin/core/browser/signin_metrics.h"
32 #include "components/signin/core/browser/test_signin_client.h"
33 #include "components/signin/core/common/profile_management_switches.h"
34 #include "components/signin/core/common/signin_switches.h"
35 #include "content/public/test/test_browser_thread_bundle.h"
36 #include "google_apis/gaia/fake_oauth2_token_service_delegate.h"
37 #include "google_apis/gaia/gaia_constants.h"
38 #include "google_apis/gaia/gaia_urls.h"
39 #include "net/url_request/test_url_fetcher_factory.h"
40 #include "testing/gmock/include/gmock/gmock.h"
41 #include "testing/gtest/include/gtest/gtest.h"
45 class MockAccountReconcilor
: public testing::StrictMock
<AccountReconcilor
> {
47 static scoped_ptr
<KeyedService
> Build(content::BrowserContext
* context
);
49 MockAccountReconcilor(ProfileOAuth2TokenService
* token_service
,
50 SigninManagerBase
* signin_manager
,
52 GaiaCookieManagerService
* cookie_manager_service
);
53 ~MockAccountReconcilor() override
{}
55 MOCK_METHOD1(PerformMergeAction
, void(const std::string
& account_id
));
56 MOCK_METHOD0(PerformLogoutAllAccountsAction
, void());
60 scoped_ptr
<KeyedService
> MockAccountReconcilor::Build(
61 content::BrowserContext
* context
) {
62 Profile
* profile
= Profile::FromBrowserContext(context
);
63 scoped_ptr
<AccountReconcilor
> reconcilor(new MockAccountReconcilor(
64 ProfileOAuth2TokenServiceFactory::GetForProfile(profile
),
65 SigninManagerFactory::GetForProfile(profile
),
66 ChromeSigninClientFactory::GetForProfile(profile
),
67 GaiaCookieManagerServiceFactory::GetForProfile(profile
)));
68 reconcilor
->Initialize(false /* start_reconcile_if_tokens_available */);
69 return reconcilor
.Pass();
72 MockAccountReconcilor::MockAccountReconcilor(
73 ProfileOAuth2TokenService
* token_service
,
74 SigninManagerBase
* signin_manager
,
76 GaiaCookieManagerService
* cookie_manager_service
)
77 : testing::StrictMock
<AccountReconcilor
>(token_service
,
80 cookie_manager_service
) {}
84 class AccountReconcilorTest
: public ::testing::TestWithParam
<bool> {
86 AccountReconcilorTest();
87 void SetUp() override
;
89 TestingProfile
* profile() { return profile_
; }
90 FakeSigninManagerForTesting
* signin_manager() { return signin_manager_
; }
91 FakeProfileOAuth2TokenService
* token_service() { return token_service_
; }
92 FakeOAuth2TokenServiceDelegate
* token_service_delegate() {
93 return static_cast<FakeOAuth2TokenServiceDelegate
*>(
94 token_service_
->GetDelegate());
96 TestSigninClient
* test_signin_client() { return test_signin_client_
; }
97 AccountTrackerService
* account_tracker() { return account_tracker_
; }
98 FakeGaiaCookieManagerService
* cookie_manager_service() {
99 return cookie_manager_service_
;
101 base::HistogramTester
* histogram_tester() { return &histogram_tester_
; }
103 void SetFakeResponse(const std::string
& url
,
104 const std::string
& data
,
105 net::HttpStatusCode code
,
106 net::URLRequestStatus::Status status
) {
107 url_fetcher_factory_
.SetFakeResponse(GURL(url
), data
, code
, status
);
110 MockAccountReconcilor
* GetMockReconcilor();
112 std::string
ConnectProfileToAccount(const std::string
& gaia_id
,
113 const std::string
& username
);
115 std::string
PickAccountIdForAccount(const std::string
& gaia_id
,
116 const std::string
& username
);
118 void SimulateAddAccountToCookieCompleted(
119 GaiaCookieManagerService::Observer
* observer
,
120 const std::string
& account_id
,
121 const GoogleServiceAuthError
& error
);
123 void SimulateCookieContentSettingsChanged(
124 content_settings::Observer
* observer
,
125 const ContentSettingsPattern
& primary_pattern
);
127 GURL
get_check_connection_info_url() {
128 return get_check_connection_info_url_
;
132 content::TestBrowserThreadBundle bundle_
;
133 TestingProfile
* profile_
;
134 FakeSigninManagerForTesting
* signin_manager_
;
135 FakeProfileOAuth2TokenService
* token_service_
;
136 TestSigninClient
* test_signin_client_
;
137 AccountTrackerService
* account_tracker_
;
138 FakeGaiaCookieManagerService
* cookie_manager_service_
;
139 MockAccountReconcilor
* mock_reconcilor_
;
140 net::FakeURLFetcherFactory url_fetcher_factory_
;
141 scoped_ptr
<TestingProfileManager
> testing_profile_manager_
;
142 base::HistogramTester histogram_tester_
;
143 GURL get_check_connection_info_url_
;
145 DISALLOW_COPY_AND_ASSIGN(AccountReconcilorTest
);
148 AccountReconcilorTest::AccountReconcilorTest()
149 : signin_manager_(NULL
),
150 token_service_(NULL
),
151 test_signin_client_(NULL
),
152 cookie_manager_service_(NULL
),
153 mock_reconcilor_(NULL
),
154 url_fetcher_factory_(NULL
) {}
156 void AccountReconcilorTest::SetUp() {
157 // If it's a non-parameterized test, or we have a parameter of true, set flag.
158 if (!::testing::UnitTest::GetInstance()->current_test_info()->value_param() ||
160 base::CommandLine::ForCurrentProcess()->AppendSwitch(
161 switches::kEnableNewProfileManagement
);
164 get_check_connection_info_url_
=
165 GaiaUrls::GetInstance()->GetCheckConnectionInfoURLWithSource(
166 GaiaConstants::kChromeSource
);
168 testing_profile_manager_
.reset(
169 new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
170 ASSERT_TRUE(testing_profile_manager_
.get()->SetUp());
172 TestingProfile::TestingFactories factories
;
173 factories
.push_back(std::make_pair(ChromeSigninClientFactory::GetInstance(),
174 signin::BuildTestSigninClient
));
175 factories
.push_back(std::make_pair(
176 ProfileOAuth2TokenServiceFactory::GetInstance(),
177 BuildFakeProfileOAuth2TokenService
));
178 factories
.push_back(std::make_pair(
179 GaiaCookieManagerServiceFactory::GetInstance(),
180 FakeGaiaCookieManagerService::Build
));
181 factories
.push_back(std::make_pair(SigninManagerFactory::GetInstance(),
182 BuildFakeSigninManagerBase
));
183 factories
.push_back(std::make_pair(AccountReconcilorFactory::GetInstance(),
184 MockAccountReconcilor::Build
));
186 profile_
= testing_profile_manager_
.get()->CreateTestingProfile("name",
187 scoped_ptr
<PrefServiceSyncable
>(),
188 base::UTF8ToUTF16("name"), 0, std::string(),
191 test_signin_client_
=
192 static_cast<TestSigninClient
*>(
193 ChromeSigninClientFactory::GetForProfile(profile()));
196 static_cast<FakeProfileOAuth2TokenService
*>(
197 ProfileOAuth2TokenServiceFactory::GetForProfile(profile()));
200 AccountTrackerServiceFactory::GetForProfile(profile());
203 static_cast<FakeSigninManagerForTesting
*>(
204 SigninManagerFactory::GetForProfile(profile()));
206 test_signin_client_
=
207 static_cast<TestSigninClient
*>(
208 ChromeSigninClientFactory::GetForProfile(profile()));
210 cookie_manager_service_
=
211 static_cast<FakeGaiaCookieManagerService
*>(
212 GaiaCookieManagerServiceFactory::GetForProfile(profile()));
213 cookie_manager_service_
->Init(&url_fetcher_factory_
);
215 cookie_manager_service_
->SetListAccountsResponseHttpNotFound();
218 MockAccountReconcilor
* AccountReconcilorTest::GetMockReconcilor() {
219 if (!mock_reconcilor_
) {
221 static_cast<MockAccountReconcilor
*>(
222 AccountReconcilorFactory::GetForProfile(profile()));
225 return mock_reconcilor_
;
228 std::string
AccountReconcilorTest::ConnectProfileToAccount(
229 const std::string
& gaia_id
,
230 const std::string
& username
) {
231 const std::string account_id
= PickAccountIdForAccount(gaia_id
, username
);
232 #if !defined(OS_CHROMEOS)
233 signin_manager()->set_password("password");
235 signin_manager()->SetAuthenticatedAccountInfo(gaia_id
, username
);
236 token_service()->UpdateCredentials(account_id
, "refresh_token");
240 std::string
AccountReconcilorTest::PickAccountIdForAccount(
241 const std::string
& gaia_id
,
242 const std::string
& username
) {
243 return account_tracker()->PickAccountIdForAccount(gaia_id
, username
);
246 void AccountReconcilorTest::SimulateAddAccountToCookieCompleted(
247 GaiaCookieManagerService::Observer
* observer
,
248 const std::string
& account_id
,
249 const GoogleServiceAuthError
& error
) {
250 observer
->OnAddAccountToCookieCompleted(account_id
, error
);
253 void AccountReconcilorTest::SimulateCookieContentSettingsChanged(
254 content_settings::Observer
* observer
,
255 const ContentSettingsPattern
& primary_pattern
) {
256 observer
->OnContentSettingChanged(
258 ContentSettingsPattern::Wildcard(),
259 CONTENT_SETTINGS_TYPE_COOKIES
,
263 TEST_F(AccountReconcilorTest
, Basic
) {
264 AccountReconcilor
* reconcilor
=
265 AccountReconcilorFactory::GetForProfile(profile());
266 ASSERT_TRUE(reconcilor
);
269 #if !defined(OS_CHROMEOS)
271 // This method requires the use of the |TestSigninClient| to be created from the
272 // |ChromeSigninClientFactory| because it overrides the |GoogleSigninSucceeded|
273 // method with an empty implementation. On MacOS, the normal implementation
274 // causes the try_bots to time out.
275 TEST_F(AccountReconcilorTest
, SigninManagerRegistration
) {
276 AccountReconcilor
* reconcilor
=
277 AccountReconcilorFactory::GetForProfile(profile());
278 ASSERT_TRUE(reconcilor
);
279 ASSERT_FALSE(reconcilor
->IsRegisteredWithTokenService());
281 account_tracker()->SeedAccountInfo("12345", "user@gmail.com");
282 signin_manager()->SignIn("12345", "user@gmail.com", "password");
283 ASSERT_TRUE(reconcilor
->IsRegisteredWithTokenService());
285 EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction());
287 signin_manager()->SignOut(signin_metrics::SIGNOUT_TEST
);
288 ASSERT_FALSE(reconcilor
->IsRegisteredWithTokenService());
291 // This method requires the use of the |TestSigninClient| to be created from the
292 // |ChromeSigninClientFactory| because it overrides the |GoogleSigninSucceeded|
293 // method with an empty implementation. On MacOS, the normal implementation
294 // causes the try_bots to time out.
295 TEST_F(AccountReconcilorTest
, Reauth
) {
296 const std::string email
= "user@gmail.com";
297 const std::string account_id
=
298 ConnectProfileToAccount("12345", email
);
300 AccountReconcilor
* reconcilor
=
301 AccountReconcilorFactory::GetForProfile(profile());
302 ASSERT_TRUE(reconcilor
);
303 ASSERT_TRUE(reconcilor
->IsRegisteredWithTokenService());
305 // Simulate reauth. The state of the reconcilor should not change.
306 signin_manager()->OnExternalSigninCompleted(email
);
307 ASSERT_TRUE(reconcilor
->IsRegisteredWithTokenService());
310 #endif // !defined(OS_CHROMEOS)
312 TEST_F(AccountReconcilorTest
, ProfileAlreadyConnected
) {
313 ConnectProfileToAccount("12345", "user@gmail.com");
315 AccountReconcilor
* reconcilor
=
316 AccountReconcilorFactory::GetForProfile(profile());
317 ASSERT_TRUE(reconcilor
);
318 ASSERT_TRUE(reconcilor
->IsRegisteredWithTokenService());
321 TEST_F(AccountReconcilorTest
, GetAccountsFromCookieSuccess
) {
322 const std::string account_id
=
323 ConnectProfileToAccount("12345", "user@gmail.com");
324 cookie_manager_service()->SetListAccountsResponseOneAccountWithExpiry(
325 "user@gmail.com", "12345", true);
326 EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id
));
328 AccountReconcilor
* reconcilor
=
329 AccountReconcilorFactory::GetForProfile(profile());
330 ASSERT_TRUE(reconcilor
);
332 ASSERT_EQ(signin_metrics::ACCOUNT_RECONCILOR_OK
, reconcilor
->GetState());
333 reconcilor
->StartReconcile();
334 ASSERT_EQ(signin_metrics::ACCOUNT_RECONCILOR_RUNNING
,
335 reconcilor
->GetState());
336 base::RunLoop().RunUntilIdle();
337 ASSERT_EQ(signin_metrics::ACCOUNT_RECONCILOR_RUNNING
, reconcilor
->GetState());
339 std::vector
<gaia::ListedAccount
> accounts
;
340 ASSERT_TRUE(cookie_manager_service()->ListAccounts(&accounts
));
341 ASSERT_EQ(1u, accounts
.size());
342 ASSERT_EQ(account_id
, accounts
[0].id
);
345 TEST_F(AccountReconcilorTest
, GetAccountsFromCookieFailure
) {
346 ConnectProfileToAccount("12345", "user@gmail.com");
347 cookie_manager_service()->SetListAccountsResponseWebLoginRequired();
349 AccountReconcilor
* reconcilor
=
350 AccountReconcilorFactory::GetForProfile(profile());
351 ASSERT_TRUE(reconcilor
);
353 ASSERT_EQ(signin_metrics::ACCOUNT_RECONCILOR_OK
, reconcilor
->GetState());
354 reconcilor
->StartReconcile();
355 ASSERT_EQ(signin_metrics::ACCOUNT_RECONCILOR_RUNNING
,
356 reconcilor
->GetState());
357 base::RunLoop().RunUntilIdle();
359 std::vector
<gaia::ListedAccount
> accounts
;
360 ASSERT_FALSE(cookie_manager_service()->ListAccounts(&accounts
));
361 ASSERT_EQ(0u, accounts
.size());
363 base::RunLoop().RunUntilIdle();
364 ASSERT_EQ(signin_metrics::ACCOUNT_RECONCILOR_ERROR
,
365 reconcilor
->GetState());
368 TEST_P(AccountReconcilorTest
, StartReconcileNoop
) {
369 const std::string account_id
=
370 ConnectProfileToAccount("12345", "user@gmail.com");
372 AccountReconcilor
* reconcilor
=
373 AccountReconcilorFactory::GetForProfile(profile());
374 ASSERT_TRUE(reconcilor
);
376 cookie_manager_service()->SetListAccountsResponseOneAccount(
377 "user@gmail.com", "12345");
379 reconcilor
->StartReconcile();
380 ASSERT_TRUE(reconcilor
->is_reconcile_started_
);
382 base::RunLoop().RunUntilIdle();
383 ASSERT_FALSE(reconcilor
->is_reconcile_started_
);
385 histogram_tester()->ExpectTotalCount(
386 "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", 1);
387 histogram_tester()->ExpectUniqueSample(
388 "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun",
389 signin_metrics::ACCOUNTS_SAME
,
393 TEST_P(AccountReconcilorTest
, StartReconcileCookiesDisabled
) {
394 const std::string account_id
=
395 ConnectProfileToAccount("12345", "user@gmail.com");
396 token_service()->UpdateCredentials(account_id
, "refresh_token");
397 test_signin_client()->set_are_signin_cookies_allowed(false);
399 AccountReconcilor
* reconcilor
=
400 AccountReconcilorFactory::GetForProfile(profile());
401 ASSERT_TRUE(reconcilor
);
403 reconcilor
->StartReconcile();
404 ASSERT_FALSE(reconcilor
->is_reconcile_started_
);
406 base::RunLoop().RunUntilIdle();
407 std::vector
<gaia::ListedAccount
> accounts
;
408 // This will be the first call to ListAccounts.
409 ASSERT_FALSE(cookie_manager_service()->ListAccounts(&accounts
));
410 ASSERT_FALSE(reconcilor
->is_reconcile_started_
);
413 TEST_P(AccountReconcilorTest
, StartReconcileContentSettings
) {
414 const std::string account_id
=
415 ConnectProfileToAccount("12345", "user@gmail.com");
416 token_service()->UpdateCredentials(account_id
, "refresh_token");
418 AccountReconcilor
* reconcilor
=
419 AccountReconcilorFactory::GetForProfile(profile());
420 ASSERT_TRUE(reconcilor
);
422 test_signin_client()->set_are_signin_cookies_allowed(false);
423 SimulateCookieContentSettingsChanged(reconcilor
,
424 ContentSettingsPattern::Wildcard());
425 ASSERT_FALSE(reconcilor
->is_reconcile_started_
);
427 test_signin_client()->set_are_signin_cookies_allowed(true);
428 SimulateCookieContentSettingsChanged(reconcilor
,
429 ContentSettingsPattern::Wildcard());
430 ASSERT_TRUE(reconcilor
->is_reconcile_started_
);
433 TEST_P(AccountReconcilorTest
, StartReconcileContentSettingsGaiaUrl
) {
434 const std::string account_id
=
435 ConnectProfileToAccount("12345", "user@gmail.com");
436 token_service()->UpdateCredentials(account_id
, "refresh_token");
438 AccountReconcilor
* reconcilor
=
439 AccountReconcilorFactory::GetForProfile(profile());
440 ASSERT_TRUE(reconcilor
);
442 SimulateCookieContentSettingsChanged(
444 ContentSettingsPattern::FromURL(GaiaUrls::GetInstance()->gaia_url()));
445 ASSERT_TRUE(reconcilor
->is_reconcile_started_
);
448 TEST_P(AccountReconcilorTest
, StartReconcileContentSettingsNonGaiaUrl
) {
449 const std::string account_id
=
450 ConnectProfileToAccount("12345", "user@gmail.com");
451 token_service()->UpdateCredentials(account_id
, "refresh_token");
453 AccountReconcilor
* reconcilor
=
454 AccountReconcilorFactory::GetForProfile(profile());
455 ASSERT_TRUE(reconcilor
);
457 SimulateCookieContentSettingsChanged(
459 ContentSettingsPattern::FromURL(GURL("http://www.example.com")));
460 ASSERT_FALSE(reconcilor
->is_reconcile_started_
);
463 TEST_P(AccountReconcilorTest
, StartReconcileContentSettingsInvalidPattern
) {
464 const std::string account_id
=
465 ConnectProfileToAccount("12345", "user@gmail.com");
466 token_service()->UpdateCredentials(account_id
, "refresh_token");
468 AccountReconcilor
* reconcilor
=
469 AccountReconcilorFactory::GetForProfile(profile());
470 ASSERT_TRUE(reconcilor
);
472 scoped_ptr
<ContentSettingsPattern::BuilderInterface
>
473 builder(ContentSettingsPattern::CreateBuilder(false));
476 SimulateCookieContentSettingsChanged(reconcilor
, builder
->Build());
477 ASSERT_TRUE(reconcilor
->is_reconcile_started_
);
480 // This test is needed until chrome changes to use gaia obfuscated id.
481 // The signin manager and token service use the gaia "email" property, which
482 // preserves dots in usernames and preserves case. gaia::ParseListAccountsData()
483 // however uses gaia "displayEmail" which does not preserve case, and then
484 // passes the string through gaia::CanonicalizeEmail() which removes dots. This
485 // tests makes sure that an email like "Dot.S@hmail.com", as seen by the
486 // token service, will be considered the same as "dots@gmail.com" as returned
487 // by gaia::ParseListAccountsData().
488 TEST_P(AccountReconcilorTest
, StartReconcileNoopWithDots
) {
489 if (account_tracker()->GetMigrationState() !=
490 AccountTrackerService::MIGRATION_NOT_STARTED
) {
494 const std::string account_id
=
495 ConnectProfileToAccount("12345", "Dot.S@gmail.com");
496 cookie_manager_service()->SetListAccountsResponseOneAccount(
497 "dot.s@gmail.com", "12345");
498 AccountReconcilor
* reconcilor
=
499 AccountReconcilorFactory::GetForProfile(profile());
500 ASSERT_TRUE(reconcilor
);
502 reconcilor
->StartReconcile();
503 base::RunLoop().RunUntilIdle();
504 ASSERT_FALSE(reconcilor
->is_reconcile_started_
);
506 histogram_tester()->ExpectUniqueSample(
507 "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun",
508 signin_metrics::ACCOUNTS_SAME
,
512 TEST_P(AccountReconcilorTest
, StartReconcileNoopMultiple
) {
513 const std::string account_id
=
514 ConnectProfileToAccount("12345", "user@gmail.com");
515 const std::string account_id2
=
516 PickAccountIdForAccount("67890", "other@gmail.com");
517 cookie_manager_service()->SetListAccountsResponseTwoAccounts(
518 "user@gmail.com", "12345", "other@gmail.com", "67890");
519 token_service()->UpdateCredentials(account_id2
, "refresh_token");
521 AccountReconcilor
* reconcilor
=
522 AccountReconcilorFactory::GetForProfile(profile());
523 ASSERT_TRUE(reconcilor
);
525 reconcilor
->StartReconcile();
526 base::RunLoop().RunUntilIdle();
527 ASSERT_FALSE(reconcilor
->is_reconcile_started_
);
529 histogram_tester()->ExpectTotalCount(
530 "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", 1);
531 histogram_tester()->ExpectUniqueSample(
532 "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun",
533 signin_metrics::ACCOUNTS_SAME
,
537 TEST_P(AccountReconcilorTest
, StartReconcileAddToCookie
) {
538 const std::string account_id
=
539 ConnectProfileToAccount("12345", "user@gmail.com");
540 token_service()->UpdateCredentials(account_id
, "refresh_token");
541 cookie_manager_service()->SetListAccountsResponseOneAccount(
542 "user@gmail.com", "12345");
544 const std::string account_id2
=
545 PickAccountIdForAccount("67890", "other@gmail.com");
546 token_service()->UpdateCredentials(account_id2
, "refresh_token");
548 EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id2
));
550 AccountReconcilor
* reconcilor
= GetMockReconcilor();
551 reconcilor
->StartReconcile();
553 base::RunLoop().RunUntilIdle();
554 ASSERT_TRUE(reconcilor
->is_reconcile_started_
);
555 SimulateAddAccountToCookieCompleted(reconcilor
, account_id2
,
556 GoogleServiceAuthError::AuthErrorNone());
557 ASSERT_FALSE(reconcilor
->is_reconcile_started_
);
559 histogram_tester()->ExpectUniqueSample(
560 "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun",
561 signin_metrics::ACCOUNTS_SAME
,
563 histogram_tester()->ExpectUniqueSample(
564 "Signin.Reconciler.AddedToCookieJar.FirstRun", 1, 1);
565 histogram_tester()->ExpectUniqueSample(
566 "Signin.Reconciler.RemovedFromCookieJar.FirstRun", 0, 1);
569 TEST_P(AccountReconcilorTest
, StartReconcileRemoveFromCookie
) {
570 const std::string account_id
=
571 ConnectProfileToAccount("12345", "user@gmail.com");
572 token_service()->UpdateCredentials(account_id
, "refresh_token");
573 cookie_manager_service()->SetListAccountsResponseTwoAccounts(
574 "user@gmail.com", "12345", "other@gmail.com", "67890");
576 EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction());
577 EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id
));
579 AccountReconcilor
* reconcilor
= GetMockReconcilor();
580 reconcilor
->StartReconcile();
581 ASSERT_TRUE(reconcilor
->is_reconcile_started_
);
583 base::RunLoop().RunUntilIdle();
584 SimulateAddAccountToCookieCompleted(reconcilor
, account_id
,
585 GoogleServiceAuthError::AuthErrorNone());
586 ASSERT_FALSE(reconcilor
->is_reconcile_started_
);
588 histogram_tester()->ExpectUniqueSample(
589 "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun",
590 signin_metrics::ACCOUNTS_SAME
,
592 histogram_tester()->ExpectUniqueSample(
593 "Signin.Reconciler.AddedToCookieJar.FirstRun", 0, 1);
594 histogram_tester()->ExpectUniqueSample(
595 "Signin.Reconciler.RemovedFromCookieJar.FirstRun", 1, 1);
598 TEST_P(AccountReconcilorTest
, StartReconcileAddToCookieTwice
) {
599 const std::string account_id
=
600 ConnectProfileToAccount("12345", "user@gmail.com");
601 const std::string account_id2
=
602 PickAccountIdForAccount("67890", "other@gmail.com");
603 const std::string account_id3
=
604 PickAccountIdForAccount("34567", "third@gmail.com");
606 cookie_manager_service()->SetListAccountsResponseOneAccount(
607 "user@gmail.com", "12345");
608 token_service()->UpdateCredentials(account_id2
, "refresh_token");
610 EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id2
));
611 EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id3
));
613 AccountReconcilor
* reconcilor
= GetMockReconcilor();
614 reconcilor
->StartReconcile();
616 base::RunLoop().RunUntilIdle();
617 ASSERT_TRUE(reconcilor
->is_reconcile_started_
);
618 SimulateAddAccountToCookieCompleted(
619 reconcilor
, account_id2
, GoogleServiceAuthError::AuthErrorNone());
620 ASSERT_FALSE(reconcilor
->is_reconcile_started_
);
622 histogram_tester()->ExpectUniqueSample(
623 "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun",
624 signin_metrics::ACCOUNTS_SAME
,
626 histogram_tester()->ExpectUniqueSample(
627 "Signin.Reconciler.AddedToCookieJar.FirstRun", 1, 1);
628 histogram_tester()->ExpectUniqueSample(
629 "Signin.Reconciler.RemovedFromCookieJar.FirstRun", 0, 1);
631 // Do another pass after I've added a third account to the token service
632 cookie_manager_service()->SetListAccountsResponseTwoAccounts(
633 "user@gmail.com", "12345", "other@gmail.com", "67890");
634 cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
636 // This will cause the reconcilor to fire.
637 token_service()->UpdateCredentials(account_id3
, "refresh_token");
638 base::RunLoop().RunUntilIdle();
640 ASSERT_TRUE(reconcilor
->is_reconcile_started_
);
641 SimulateAddAccountToCookieCompleted(
642 reconcilor
, account_id3
, GoogleServiceAuthError::AuthErrorNone());
643 ASSERT_FALSE(reconcilor
->is_reconcile_started_
);
645 histogram_tester()->ExpectUniqueSample(
646 "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun",
647 signin_metrics::ACCOUNTS_SAME
,
649 histogram_tester()->ExpectUniqueSample(
650 "Signin.Reconciler.AddedToCookieJar.FirstRun", 1, 1);
651 histogram_tester()->ExpectUniqueSample(
652 "Signin.Reconciler.RemovedFromCookieJar.FirstRun", 0, 1);
653 histogram_tester()->ExpectUniqueSample(
654 "Signin.Reconciler.DifferentPrimaryAccounts.SubsequentRun",
655 signin_metrics::ACCOUNTS_SAME
,
657 histogram_tester()->ExpectUniqueSample(
658 "Signin.Reconciler.AddedToCookieJar.SubsequentRun", 1, 1);
659 histogram_tester()->ExpectUniqueSample(
660 "Signin.Reconciler.RemovedFromCookieJar.SubsequentRun", 0, 1);
663 TEST_P(AccountReconcilorTest
, StartReconcileBadPrimary
) {
664 const std::string account_id
=
665 ConnectProfileToAccount("12345", "user@gmail.com");
666 const std::string account_id2
=
667 PickAccountIdForAccount("67890", "other@gmail.com");
669 token_service()->UpdateCredentials(account_id2
, "refresh_token");
670 cookie_manager_service()->SetListAccountsResponseTwoAccounts(
671 "other@gmail.com", "67890", "user@gmail.com", "12345");
673 EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction());
674 EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id
));
675 EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id2
));
677 AccountReconcilor
* reconcilor
= GetMockReconcilor();
678 reconcilor
->StartReconcile();
680 base::RunLoop().RunUntilIdle();
681 ASSERT_TRUE(reconcilor
->is_reconcile_started_
);
682 SimulateAddAccountToCookieCompleted(reconcilor
, account_id2
,
683 GoogleServiceAuthError::AuthErrorNone());
684 ASSERT_TRUE(reconcilor
->is_reconcile_started_
);
685 SimulateAddAccountToCookieCompleted(reconcilor
, account_id
,
686 GoogleServiceAuthError::AuthErrorNone());
687 ASSERT_FALSE(reconcilor
->is_reconcile_started_
);
689 histogram_tester()->ExpectUniqueSample(
690 "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun",
691 signin_metrics::COOKIE_AND_TOKEN_PRIMARIES_DIFFERENT
,
693 histogram_tester()->ExpectUniqueSample(
694 "Signin.Reconciler.AddedToCookieJar.FirstRun", 0, 1);
695 histogram_tester()->ExpectUniqueSample(
696 "Signin.Reconciler.RemovedFromCookieJar.FirstRun", 0, 1);
699 TEST_P(AccountReconcilorTest
, StartReconcileOnlyOnce
) {
700 const std::string account_id
=
701 ConnectProfileToAccount("12345", "user@gmail.com");
702 cookie_manager_service()->SetListAccountsResponseOneAccount(
703 "user@gmail.com", "12345");
705 AccountReconcilor
* reconcilor
=
706 AccountReconcilorFactory::GetForProfile(profile());
707 ASSERT_TRUE(reconcilor
);
709 ASSERT_FALSE(reconcilor
->is_reconcile_started_
);
710 reconcilor
->StartReconcile();
711 ASSERT_TRUE(reconcilor
->is_reconcile_started_
);
713 base::RunLoop().RunUntilIdle();
714 ASSERT_FALSE(reconcilor
->is_reconcile_started_
);
717 TEST_P(AccountReconcilorTest
, StartReconcileWithSessionInfoExpiredDefault
) {
718 const std::string account_id
=
719 ConnectProfileToAccount("12345", "user@gmail.com");
720 const std::string account_id2
=
721 PickAccountIdForAccount("67890", "other@gmail.com");
722 token_service()->UpdateCredentials(account_id2
, "refresh_token");
723 cookie_manager_service()->SetListAccountsResponseTwoAccountsWithExpiry(
724 "user@gmail.com", "12345", true, "other@gmail.com", "67890", false);
726 EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id
));
728 AccountReconcilor
* reconcilor
=
729 AccountReconcilorFactory::GetForProfile(profile());
730 ASSERT_TRUE(reconcilor
);
732 ASSERT_FALSE(reconcilor
->is_reconcile_started_
);
733 reconcilor
->StartReconcile();
734 ASSERT_TRUE(reconcilor
->is_reconcile_started_
);
736 base::RunLoop().RunUntilIdle();
737 SimulateAddAccountToCookieCompleted(reconcilor
, account_id
,
738 GoogleServiceAuthError::AuthErrorNone());
739 ASSERT_FALSE(reconcilor
->is_reconcile_started_
);
742 TEST_F(AccountReconcilorTest
, AddAccountToCookieCompletedWithBogusAccount
) {
743 const std::string account_id
=
744 ConnectProfileToAccount("12345", "user@gmail.com");
745 cookie_manager_service()->SetListAccountsResponseOneAccountWithExpiry(
746 "user@gmail.com", "12345", true);
748 EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id
));
750 AccountReconcilor
* reconcilor
=
751 AccountReconcilorFactory::GetForProfile(profile());
752 ASSERT_TRUE(reconcilor
);
754 ASSERT_FALSE(reconcilor
->is_reconcile_started_
);
755 reconcilor
->StartReconcile();
756 ASSERT_TRUE(reconcilor
->is_reconcile_started_
);
758 base::RunLoop().RunUntilIdle();
760 // If an unknown account id is sent, it should not upset the state.
761 SimulateAddAccountToCookieCompleted(reconcilor
, "bogus_account_id",
762 GoogleServiceAuthError::AuthErrorNone());
763 ASSERT_TRUE(reconcilor
->is_reconcile_started_
);
765 SimulateAddAccountToCookieCompleted(reconcilor
, account_id
,
766 GoogleServiceAuthError::AuthErrorNone());
767 ASSERT_FALSE(reconcilor
->is_reconcile_started_
);
771 // These tests don't run on iOS because that platform uses a different
772 // implementation of FakeOAuth2TokenServiceDelegate. However, iOS also removes
773 // accounts when an auth error is detected, so the scenarios being tested here
776 TEST_F(AccountReconcilorTest
, NoLoopWithBadPrimary
) {
777 // Connect profile to a primary account and then add a secondary account.
778 const std::string account_id1
=
779 ConnectProfileToAccount("12345", "user@gmail.com");
780 const std::string account_id2
=
781 PickAccountIdForAccount("67890", "other@gmail.com");
782 token_service()->UpdateCredentials(account_id2
, "refresh_token");
784 EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction());
785 EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id1
));
786 EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id2
));
788 // The primary account is in auth error, so it is not in the cookie.
789 cookie_manager_service()->SetListAccountsResponseOneAccountWithExpiry(
790 "other@gmail.com", "67890", true);
792 AccountReconcilor
* reconcilor
=
793 AccountReconcilorFactory::GetForProfile(profile());
794 ASSERT_TRUE(reconcilor
);
796 reconcilor
->StartReconcile();
797 base::RunLoop().RunUntilIdle();
798 ASSERT_TRUE(reconcilor
->is_reconcile_started_
);
800 GoogleServiceAuthError
801 error(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS
);
803 // The primary cannot be added to cookie, so it fails.
804 SimulateAddAccountToCookieCompleted(
805 reconcilor
, account_id1
, error
);
806 SimulateAddAccountToCookieCompleted(reconcilor
, account_id2
,
807 GoogleServiceAuthError::AuthErrorNone());
808 base::RunLoop().RunUntilIdle();
809 ASSERT_FALSE(reconcilor
->is_reconcile_started_
);
810 ASSERT_TRUE(reconcilor
->error_during_last_reconcile_
);
811 testing::Mock::VerifyAndClearExpectations(GetMockReconcilor());
813 // Now that we've tried once, the token service knows that the primary
814 // account has an auth error.
815 token_service_delegate()->SetLastErrorForAccount(account_id1
, error
);
817 // A second attempt to reconcile should be a noop.
818 reconcilor
->StartReconcile();
819 base::RunLoop().RunUntilIdle();
820 ASSERT_FALSE(reconcilor
->is_reconcile_started_
);
821 testing::Mock::VerifyAndClearExpectations(GetMockReconcilor());
824 TEST_F(AccountReconcilorTest
, WontMergeAccountsWithError
) {
825 // Connect profile to a primary account and then add a secondary account.
826 const std::string account_id1
=
827 ConnectProfileToAccount("12345", "user@gmail.com");
828 const std::string account_id2
=
829 PickAccountIdForAccount("67890", "other@gmail.com");
830 token_service()->UpdateCredentials(account_id2
, "refresh_token");
832 // Mark the secondary account in auth error state.
833 token_service_delegate()->SetLastErrorForAccount(
835 GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS
));
837 // The cookie starts empty.
838 cookie_manager_service()->SetListAccountsResponseNoAccounts();
840 // Since the cookie jar starts empty, the reconcilor should attempt to merge
841 // accounts into it. However, it should only try accounts not in auth
843 EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction());
844 EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id1
));
846 AccountReconcilor
* reconcilor
=
847 AccountReconcilorFactory::GetForProfile(profile());
848 ASSERT_TRUE(reconcilor
);
850 reconcilor
->StartReconcile();
851 base::RunLoop().RunUntilIdle();
852 ASSERT_TRUE(reconcilor
->is_reconcile_started_
);
854 SimulateAddAccountToCookieCompleted(
855 reconcilor
, account_id1
, GoogleServiceAuthError::AuthErrorNone());
856 base::RunLoop().RunUntilIdle();
857 ASSERT_FALSE(reconcilor
->is_reconcile_started_
);
858 ASSERT_FALSE(reconcilor
->error_during_last_reconcile_
);
863 INSTANTIATE_TEST_CASE_P(AccountReconcilorMaybeEnabled
,
864 AccountReconcilorTest
,