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/time/time.h"
10 #include "build/build_config.h"
11 #include "chrome/browser/prefs/pref_service_syncable.h"
12 #include "chrome/browser/signin/account_reconcilor_factory.h"
13 #include "chrome/browser/signin/chrome_signin_client_factory.h"
14 #include "chrome/browser/signin/fake_profile_oauth2_token_service.h"
15 #include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h"
16 #include "chrome/browser/signin/fake_signin_manager.h"
17 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
18 #include "chrome/browser/signin/signin_manager_factory.h"
19 #include "chrome/browser/signin/test_signin_client_builder.h"
20 #include "chrome/test/base/testing_browser_process.h"
21 #include "chrome/test/base/testing_profile.h"
22 #include "chrome/test/base/testing_profile_manager.h"
23 #include "chrome/test/base/uma_histogram_helper.h"
24 #include "components/signin/core/browser/account_reconcilor.h"
25 #include "components/signin/core/browser/profile_oauth2_token_service.h"
26 #include "components/signin/core/browser/signin_manager.h"
27 #include "components/signin/core/browser/signin_metrics.h"
28 #include "components/signin/core/common/profile_management_switches.h"
29 #include "components/signin/core/common/signin_switches.h"
30 #include "content/public/test/test_browser_thread_bundle.h"
31 #include "google_apis/gaia/gaia_urls.h"
32 #include "net/url_request/test_url_fetcher_factory.h"
33 #include "testing/gmock/include/gmock/gmock.h"
34 #include "testing/gtest/include/gtest/gtest.h"
38 const char kTestEmail[] = "user@gmail.com";
39 const char* const kHistogramsToSnapshot[] = {
40 "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun",
41 "Signin.Reconciler.AddedToCookieJar.FirstRun",
42 "Signin.Reconciler.AddedToChrome.FirstRun",
43 "Signin.Reconciler.DifferentPrimaryAccounts.SubsequentRun",
44 "Signin.Reconciler.AddedToCookieJar.SubsequentRun",
45 "Signin.Reconciler.AddedToChrome.SubsequentRun"};
47 class MockAccountReconcilor : public testing::StrictMock<AccountReconcilor> {
49 static KeyedService* Build(content::BrowserContext* context);
51 MockAccountReconcilor(ProfileOAuth2TokenService* token_service,
52 SigninManagerBase* signin_manager,
53 SigninClient* client);
54 virtual ~MockAccountReconcilor() {}
56 MOCK_METHOD1(PerformMergeAction, void(const std::string& account_id));
57 MOCK_METHOD1(PerformStartRemoveAction, void(const std::string& account_id));
59 PerformFinishRemoveAction,
60 void(const std::string& account_id,
61 const GoogleServiceAuthError& error,
62 const std::vector<std::pair<std::string, bool> >& accounts));
63 MOCK_METHOD2(PerformAddToChromeAction, void(const std::string& account_id,
65 MOCK_METHOD0(PerformLogoutAllAccountsAction, void());
69 KeyedService* MockAccountReconcilor::Build(content::BrowserContext* context) {
70 Profile* profile = Profile::FromBrowserContext(context);
71 AccountReconcilor* reconcilor = new MockAccountReconcilor(
72 ProfileOAuth2TokenServiceFactory::GetForProfile(profile),
73 SigninManagerFactory::GetForProfile(profile),
74 ChromeSigninClientFactory::GetForProfile(profile));
75 reconcilor->Initialize(false /* start_reconcile_if_tokens_available */);
79 MockAccountReconcilor::MockAccountReconcilor(
80 ProfileOAuth2TokenService* token_service,
81 SigninManagerBase* signin_manager,
83 : testing::StrictMock<AccountReconcilor>(token_service,
89 class AccountReconcilorTest : public ::testing::TestWithParam<bool> {
91 AccountReconcilorTest();
92 virtual void SetUp() OVERRIDE;
94 TestingProfile* profile() { return profile_; }
95 FakeSigninManagerForTesting* signin_manager() { return signin_manager_; }
96 FakeProfileOAuth2TokenService* token_service() { return token_service_; }
97 UMAHistogramHelper* histogram_helper() { return &histogram_helper_; }
99 void SetFakeResponse(const std::string& url,
100 const std::string& data,
101 net::HttpStatusCode code,
102 net::URLRequestStatus::Status status) {
103 url_fetcher_factory_.SetFakeResponse(GURL(url), data, code, status);
106 MockAccountReconcilor* GetMockReconcilor();
108 void SimulateMergeSessionCompleted(
109 MergeSessionHelper::Observer* observer,
110 const std::string& account_id,
111 const GoogleServiceAuthError& error);
113 void SimulateRefreshTokenFetched(
114 AccountReconcilor* reconcilor,
115 const std::string& account_id,
116 const std::string& refresh_token);
119 content::TestBrowserThreadBundle bundle_;
120 TestingProfile* profile_;
121 FakeSigninManagerForTesting* signin_manager_;
122 FakeProfileOAuth2TokenService* token_service_;
123 MockAccountReconcilor* mock_reconcilor_;
124 net::FakeURLFetcherFactory url_fetcher_factory_;
125 scoped_ptr<TestingProfileManager> testing_profile_manager_;
126 UMAHistogramHelper histogram_helper_;
128 DISALLOW_COPY_AND_ASSIGN(AccountReconcilorTest);
131 AccountReconcilorTest::AccountReconcilorTest()
132 : signin_manager_(NULL),
133 token_service_(NULL),
134 mock_reconcilor_(NULL),
135 url_fetcher_factory_(NULL) {}
137 void AccountReconcilorTest::SetUp() {
138 // If it's a non-parameterized test, or we have a parameter of true, set flag.
139 if (!::testing::UnitTest::GetInstance()->current_test_info()->value_param() ||
141 CommandLine::ForCurrentProcess()->AppendSwitch(
142 switches::kEnableNewProfileManagement);
145 testing_profile_manager_.reset(
146 new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
147 ASSERT_TRUE(testing_profile_manager_.get()->SetUp());
149 TestingProfile::TestingFactories factories;
150 factories.push_back(std::make_pair(ChromeSigninClientFactory::GetInstance(),
151 signin::BuildTestSigninClient));
152 factories.push_back(std::make_pair(
153 ProfileOAuth2TokenServiceFactory::GetInstance(),
154 BuildFakeProfileOAuth2TokenService));
155 factories.push_back(std::make_pair(SigninManagerFactory::GetInstance(),
156 FakeSigninManagerBase::Build));
157 factories.push_back(std::make_pair(AccountReconcilorFactory::GetInstance(),
158 MockAccountReconcilor::Build));
160 profile_ = testing_profile_manager_.get()->CreateTestingProfile("name",
161 scoped_ptr<PrefServiceSyncable>(),
162 base::UTF8ToUTF16("name"), 0, std::string(),
166 static_cast<FakeSigninManagerForTesting*>(
167 SigninManagerFactory::GetForProfile(profile()));
170 static_cast<FakeProfileOAuth2TokenService*>(
171 ProfileOAuth2TokenServiceFactory::GetForProfile(profile()));
173 // Take a new snapshot of the concerned histograms before each test
174 histogram_helper_.PrepareSnapshot(kHistogramsToSnapshot,
175 arraysize(kHistogramsToSnapshot));
178 MockAccountReconcilor* AccountReconcilorTest::GetMockReconcilor() {
179 if (!mock_reconcilor_) {
181 static_cast<MockAccountReconcilor*>(
182 AccountReconcilorFactory::GetForProfile(profile()));
185 return mock_reconcilor_;
188 void AccountReconcilorTest::SimulateMergeSessionCompleted(
189 MergeSessionHelper::Observer* observer,
190 const std::string& account_id,
191 const GoogleServiceAuthError& error) {
192 observer->MergeSessionCompleted(account_id, error);
195 void AccountReconcilorTest::SimulateRefreshTokenFetched(
196 AccountReconcilor* reconcilor,
197 const std::string& account_id,
198 const std::string& refresh_token) {
199 reconcilor->HandleRefreshTokenFetched(account_id, refresh_token);
202 TEST_F(AccountReconcilorTest, Basic) {
203 AccountReconcilor* reconcilor =
204 AccountReconcilorFactory::GetForProfile(profile());
205 ASSERT_TRUE(reconcilor);
206 ASSERT_EQ(token_service(), reconcilor->token_service());
209 #if !defined(OS_CHROMEOS)
211 // This method requires the use of the |TestSigninClient| to be created from the
212 // |ChromeSigninClientFactory| because it overrides the |GoogleSigninSucceeded|
213 // method with an empty implementation. On MacOS, the normal implementation
214 // causes the try_bots to time out.
215 TEST_F(AccountReconcilorTest, SigninManagerRegistration) {
216 AccountReconcilor* reconcilor =
217 AccountReconcilorFactory::GetForProfile(profile());
218 ASSERT_TRUE(reconcilor);
219 ASSERT_FALSE(reconcilor->IsRegisteredWithTokenService());
221 signin_manager()->set_password("password");
222 signin_manager()->OnExternalSigninCompleted(kTestEmail);
223 ASSERT_TRUE(reconcilor->IsRegisteredWithTokenService());
225 EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction());
227 signin_manager()->SignOut(signin_metrics::SIGNOUT_TEST);
228 ASSERT_FALSE(reconcilor->IsRegisteredWithTokenService());
231 // This method requires the use of the |TestSigninClient| to be created from the
232 // |ChromeSigninClientFactory| because it overrides the |GoogleSigninSucceeded|
233 // method with an empty implementation. On MacOS, the normal implementation
234 // causes the try_bots to time out.
235 TEST_F(AccountReconcilorTest, Reauth) {
236 signin_manager()->SetAuthenticatedUsername(kTestEmail);
237 signin_manager()->set_password("password");
239 AccountReconcilor* reconcilor =
240 AccountReconcilorFactory::GetForProfile(profile());
241 ASSERT_TRUE(reconcilor);
242 ASSERT_TRUE(reconcilor->IsRegisteredWithTokenService());
244 // Simulate reauth. The state of the reconcilor should not change.
245 signin_manager()->OnExternalSigninCompleted(kTestEmail);
246 ASSERT_TRUE(reconcilor->IsRegisteredWithTokenService());
249 #endif // !defined(OS_CHROMEOS)
251 TEST_F(AccountReconcilorTest, ProfileAlreadyConnected) {
252 signin_manager()->SetAuthenticatedUsername(kTestEmail);
254 AccountReconcilor* reconcilor =
255 AccountReconcilorFactory::GetForProfile(profile());
256 ASSERT_TRUE(reconcilor);
257 ASSERT_TRUE(reconcilor->IsRegisteredWithTokenService());
260 TEST_F(AccountReconcilorTest, GetAccountsFromCookieSuccess) {
261 signin_manager()->SetAuthenticatedUsername(kTestEmail);
262 token_service()->UpdateCredentials(kTestEmail, "refresh_token");
263 AccountReconcilor* reconcilor =
264 AccountReconcilorFactory::GetForProfile(profile());
265 ASSERT_TRUE(reconcilor);
267 SetFakeResponse(GaiaUrls::GetInstance()->list_accounts_url().spec(),
268 "[\"f\", [[\"b\", 0, \"n\", \"user@gmail.com\", \"p\", 0, 0, 0, 0, 0]]]",
269 net::HTTP_OK, net::URLRequestStatus::SUCCESS);
271 reconcilor->StartReconcile();
272 ASSERT_FALSE(reconcilor->AreGaiaAccountsSet());
274 base::RunLoop().RunUntilIdle();
275 ASSERT_TRUE(reconcilor->AreGaiaAccountsSet());
276 const std::vector<std::pair<std::string, bool> >& accounts =
277 reconcilor->GetGaiaAccountsForTesting();
278 ASSERT_EQ(1u, accounts.size());
279 ASSERT_EQ("user@gmail.com", accounts[0].first);
282 TEST_F(AccountReconcilorTest, GetAccountsFromCookieFailure) {
283 signin_manager()->SetAuthenticatedUsername(kTestEmail);
284 token_service()->UpdateCredentials(kTestEmail, "refresh_token");
285 AccountReconcilor* reconcilor =
286 AccountReconcilorFactory::GetForProfile(profile());
287 ASSERT_TRUE(reconcilor);
289 SetFakeResponse(GaiaUrls::GetInstance()->list_accounts_url().spec(), "",
290 net::HTTP_NOT_FOUND, net::URLRequestStatus::SUCCESS);
292 reconcilor->StartReconcile();
293 ASSERT_FALSE(reconcilor->AreGaiaAccountsSet());
295 base::RunLoop().RunUntilIdle();
296 ASSERT_EQ(0u, reconcilor->GetGaiaAccountsForTesting().size());
299 TEST_F(AccountReconcilorTest, ValidateAccountsFromTokens) {
300 signin_manager()->SetAuthenticatedUsername(kTestEmail);
301 token_service()->UpdateCredentials(kTestEmail, "refresh_token");
303 AccountReconcilor* reconcilor =
304 AccountReconcilorFactory::GetForProfile(profile());
305 ASSERT_TRUE(reconcilor);
307 reconcilor->ValidateAccountsFromTokenService();
308 ASSERT_FALSE(reconcilor->AreAllRefreshTokensChecked());
310 SetFakeResponse("https://www.googleapis.com/oauth2/v1/userinfo",
311 "{\"id\":\"foo\"}", net::HTTP_OK, net::URLRequestStatus::SUCCESS);
312 token_service()->IssueTokenForAllPendingRequests("access_token",
313 base::Time::Now() + base::TimeDelta::FromHours(1));
315 base::RunLoop().RunUntilIdle();
316 ASSERT_TRUE(reconcilor->AreAllRefreshTokensChecked());
317 ASSERT_EQ(1u, reconcilor->GetValidChromeAccountsForTesting().size());
318 ASSERT_EQ(0u, reconcilor->GetInvalidChromeAccountsForTesting().size());
321 TEST_F(AccountReconcilorTest, ValidateAccountsFromTokensFailedUserInfo) {
322 signin_manager()->SetAuthenticatedUsername(kTestEmail);
323 token_service()->UpdateCredentials(kTestEmail, "refresh_token");
325 AccountReconcilor* reconcilor =
326 AccountReconcilorFactory::GetForProfile(profile());
327 ASSERT_TRUE(reconcilor);
329 reconcilor->ValidateAccountsFromTokenService();
330 ASSERT_FALSE(reconcilor->AreAllRefreshTokensChecked());
332 SetFakeResponse("https://www.googleapis.com/oauth2/v1/userinfo",
333 "", net::HTTP_NOT_FOUND, net::URLRequestStatus::SUCCESS);
334 token_service()->IssueTokenForAllPendingRequests("access_token",
335 base::Time::Now() + base::TimeDelta::FromHours(1));
337 base::RunLoop().RunUntilIdle();
338 ASSERT_TRUE(reconcilor->AreAllRefreshTokensChecked());
339 ASSERT_EQ(0u, reconcilor->GetValidChromeAccountsForTesting().size());
340 ASSERT_EQ(1u, reconcilor->GetInvalidChromeAccountsForTesting().size());
343 TEST_F(AccountReconcilorTest, ValidateAccountsFromTokensFailedTokenRequest) {
344 signin_manager()->SetAuthenticatedUsername(kTestEmail);
345 token_service()->UpdateCredentials(kTestEmail, "refresh_token");
347 AccountReconcilor* reconcilor =
348 AccountReconcilorFactory::GetForProfile(profile());
349 ASSERT_TRUE(reconcilor);
351 reconcilor->ValidateAccountsFromTokenService();
352 ASSERT_FALSE(reconcilor->AreAllRefreshTokensChecked());
354 token_service()->IssueErrorForAllPendingRequests(
355 GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
357 base::RunLoop().RunUntilIdle();
358 ASSERT_TRUE(reconcilor->AreAllRefreshTokensChecked());
359 ASSERT_EQ(0u, reconcilor->GetValidChromeAccountsForTesting().size());
360 ASSERT_EQ(1u, reconcilor->GetInvalidChromeAccountsForTesting().size());
363 TEST_P(AccountReconcilorTest, StartReconcileNoop) {
364 signin_manager()->SetAuthenticatedUsername(kTestEmail);
365 token_service()->UpdateCredentials(kTestEmail, "refresh_token");
367 AccountReconcilor* reconcilor =
368 AccountReconcilorFactory::GetForProfile(profile());
369 ASSERT_TRUE(reconcilor);
371 SetFakeResponse(GaiaUrls::GetInstance()->list_accounts_url().spec(),
372 "[\"f\", [[\"b\", 0, \"n\", \"user@gmail.com\", \"p\", 0, 0, 0, 0, 1]]]",
373 net::HTTP_OK, net::URLRequestStatus::SUCCESS);
374 SetFakeResponse("https://www.googleapis.com/oauth2/v1/userinfo",
375 "{\"id\":\"foo\"}", net::HTTP_OK, net::URLRequestStatus::SUCCESS);
377 reconcilor->StartReconcile();
378 ASSERT_FALSE(reconcilor->AreGaiaAccountsSet());
379 ASSERT_FALSE(reconcilor->AreAllRefreshTokensChecked());
381 base::RunLoop().RunUntilIdle();
382 ASSERT_TRUE(reconcilor->AreGaiaAccountsSet());
383 ASSERT_EQ(1u, reconcilor->GetGaiaAccountsForTesting().size());
384 ASSERT_FALSE(reconcilor->AreAllRefreshTokensChecked());
386 token_service()->IssueAllTokensForAccount("user@gmail.com", "access_token",
387 base::Time::Now() + base::TimeDelta::FromHours(1));
389 base::RunLoop().RunUntilIdle();
390 ASSERT_TRUE(reconcilor->AreAllRefreshTokensChecked());
391 ASSERT_FALSE(reconcilor->is_reconcile_started_);
393 histogram_helper()->Fetch();
394 histogram_helper()->ExpectTotalCount(
395 "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", 1);
396 histogram_helper()->ExpectUniqueSample(
397 "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun",
398 signin_metrics::ACCOUNTS_SAME,
402 // This is test is needed until chrome changes to use gaia obfuscated id.
403 // The signin manager and token service use the gaia "email" property, which
404 // preserves dots in usernames and preserves case. gaia::ParseListAccountsData()
405 // however uses gaia "displayEmail" which does not preserve case, and then
406 // passes the string through gaia::CanonicalizeEmail() which removes dots. This
407 // tests makes sure that an email like "Dot.S@hmail.com", as seen by the
408 // token service, will be considered the same as "dots@gmail.com" as returned
409 // by gaia::ParseListAccountsData().
410 TEST_P(AccountReconcilorTest, StartReconcileNoopWithDots) {
411 signin_manager()->SetAuthenticatedUsername("Dot.S@gmail.com");
412 token_service()->UpdateCredentials("Dot.S@gmail.com", "refresh_token");
414 AccountReconcilor* reconcilor =
415 AccountReconcilorFactory::GetForProfile(profile());
416 ASSERT_TRUE(reconcilor);
418 SetFakeResponse(GaiaUrls::GetInstance()->list_accounts_url().spec(),
419 "[\"f\", [[\"b\", 0, \"n\", \"dot.s@gmail.com\", \"p\", 0, 0, 0, 0, 1]]]",
420 net::HTTP_OK, net::URLRequestStatus::SUCCESS);
421 SetFakeResponse("https://www.googleapis.com/oauth2/v1/userinfo",
422 "{\"id\":\"foo\"}", net::HTTP_OK, net::URLRequestStatus::SUCCESS);
424 reconcilor->StartReconcile();
425 ASSERT_FALSE(reconcilor->AreGaiaAccountsSet());
426 ASSERT_FALSE(reconcilor->AreAllRefreshTokensChecked());
428 base::RunLoop().RunUntilIdle();
429 ASSERT_TRUE(reconcilor->AreGaiaAccountsSet());
430 ASSERT_EQ(1u, reconcilor->GetGaiaAccountsForTesting().size());
431 ASSERT_STREQ("dots@gmail.com",
432 reconcilor->GetGaiaAccountsForTesting()[0].first.c_str());
433 ASSERT_FALSE(reconcilor->AreAllRefreshTokensChecked());
435 token_service()->IssueAllTokensForAccount("Dot.S@gmail.com", "access_token",
436 base::Time::Now() + base::TimeDelta::FromHours(1));
438 base::RunLoop().RunUntilIdle();
439 ASSERT_TRUE(reconcilor->AreAllRefreshTokensChecked());
440 ASSERT_FALSE(reconcilor->is_reconcile_started_);
442 histogram_helper()->Fetch();
443 histogram_helper()->ExpectUniqueSample(
444 "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun",
445 signin_metrics::ACCOUNTS_SAME,
449 TEST_P(AccountReconcilorTest, StartReconcileNoopMultiple) {
450 signin_manager()->SetAuthenticatedUsername("user@gmail.com");
451 token_service()->UpdateCredentials("user@gmail.com", "refresh_token");
452 token_service()->UpdateCredentials("other@gmail.com", "refresh_token");
454 AccountReconcilor* reconcilor =
455 AccountReconcilorFactory::GetForProfile(profile());
456 ASSERT_TRUE(reconcilor);
458 SetFakeResponse(GaiaUrls::GetInstance()->list_accounts_url().spec(),
459 "[\"f\", [[\"b\", 0, \"n\", \"user@gmail.com\", \"p\", 0, 0, 0, 0, 1], "
460 "[\"b\", 0, \"n\", \"other@gmail.com\", \"p\", 0, 0, 0, 0, 1]]]",
461 net::HTTP_OK, net::URLRequestStatus::SUCCESS);
462 SetFakeResponse("https://www.googleapis.com/oauth2/v1/userinfo",
463 "{\"id\":\"foo\"}", net::HTTP_OK, net::URLRequestStatus::SUCCESS);
465 reconcilor->StartReconcile();
466 ASSERT_FALSE(reconcilor->AreGaiaAccountsSet());
467 ASSERT_FALSE(reconcilor->AreAllRefreshTokensChecked());
469 base::RunLoop().RunUntilIdle();
470 ASSERT_TRUE(reconcilor->AreGaiaAccountsSet());
471 ASSERT_FALSE(reconcilor->AreAllRefreshTokensChecked());
472 ASSERT_EQ(2u, reconcilor->GetGaiaAccountsForTesting().size());
474 token_service()->IssueAllTokensForAccount("other@gmail.com", "access_token",
475 base::Time::Now() + base::TimeDelta::FromHours(1));
477 base::RunLoop().RunUntilIdle();
478 ASSERT_FALSE(reconcilor->AreAllRefreshTokensChecked());
480 token_service()->IssueAllTokensForAccount("user@gmail.com", "access_token",
481 base::Time::Now() + base::TimeDelta::FromHours(1));
483 base::RunLoop().RunUntilIdle();
484 ASSERT_TRUE(reconcilor->AreAllRefreshTokensChecked());
485 ASSERT_FALSE(reconcilor->is_reconcile_started_);
487 histogram_helper()->Fetch();
488 histogram_helper()->ExpectTotalCount(
489 "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", 1);
490 histogram_helper()->ExpectUniqueSample(
491 "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun",
492 signin_metrics::ACCOUNTS_SAME,
496 TEST_P(AccountReconcilorTest, StartReconcileAddToCookie) {
497 signin_manager()->SetAuthenticatedUsername("user@gmail.com");
498 token_service()->UpdateCredentials("user@gmail.com", "refresh_token");
499 token_service()->UpdateCredentials("other@gmail.com", "refresh_token");
501 EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction("other@gmail.com"));
503 SetFakeResponse(GaiaUrls::GetInstance()->list_accounts_url().spec(),
504 "[\"f\", [[\"b\", 0, \"n\", \"user@gmail.com\", \"p\", 0, 0, 0, 0, 1]]]",
505 net::HTTP_OK, net::URLRequestStatus::SUCCESS);
506 SetFakeResponse("https://www.googleapis.com/oauth2/v1/userinfo",
507 "{\"id\":\"foo\"}", net::HTTP_OK, net::URLRequestStatus::SUCCESS);
509 AccountReconcilor* reconcilor = GetMockReconcilor();
510 reconcilor->StartReconcile();
511 token_service()->IssueAllTokensForAccount("other@gmail.com", "access_token",
512 base::Time::Now() + base::TimeDelta::FromHours(1));
513 token_service()->IssueAllTokensForAccount("user@gmail.com", "access_token",
514 base::Time::Now() + base::TimeDelta::FromHours(1));
516 base::RunLoop().RunUntilIdle();
517 ASSERT_TRUE(reconcilor->is_reconcile_started_);
518 SimulateMergeSessionCompleted(reconcilor, "other@gmail.com",
519 GoogleServiceAuthError::AuthErrorNone());
520 ASSERT_FALSE(reconcilor->is_reconcile_started_);
522 histogram_helper()->Fetch();
523 histogram_helper()->ExpectUniqueSample(
524 "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun",
525 signin_metrics::ACCOUNTS_SAME,
527 histogram_helper()->ExpectUniqueSample(
528 "Signin.Reconciler.AddedToCookieJar.FirstRun", 1, 1);
529 histogram_helper()->ExpectUniqueSample(
530 "Signin.Reconciler.AddedToChrome.FirstRun", 0, 1);
533 TEST_P(AccountReconcilorTest, StartReconcileAddToCookieTwice) {
534 signin_manager()->SetAuthenticatedUsername("user@gmail.com");
535 token_service()->UpdateCredentials("user@gmail.com", "refresh_token");
536 token_service()->UpdateCredentials("other@gmail.com", "refresh_token");
538 EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction("other@gmail.com"));
539 EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction("third@gmail.com"));
542 GaiaUrls::GetInstance()->list_accounts_url().spec(),
543 "[\"f\", [[\"b\", 0, \"n\", \"user@gmail.com\", \"p\", 0, 0, 0, 0, 1]]]",
545 net::URLRequestStatus::SUCCESS);
546 SetFakeResponse("https://www.googleapis.com/oauth2/v1/userinfo",
549 net::URLRequestStatus::SUCCESS);
551 AccountReconcilor* reconcilor = GetMockReconcilor();
552 reconcilor->StartReconcile();
553 token_service()->IssueAllTokensForAccount(
556 base::Time::Now() + base::TimeDelta::FromHours(1));
557 token_service()->IssueAllTokensForAccount(
560 base::Time::Now() + base::TimeDelta::FromHours(1));
562 base::RunLoop().RunUntilIdle();
563 ASSERT_TRUE(reconcilor->is_reconcile_started_);
564 SimulateMergeSessionCompleted(
565 reconcilor, "other@gmail.com", GoogleServiceAuthError::AuthErrorNone());
566 ASSERT_FALSE(reconcilor->is_reconcile_started_);
568 histogram_helper()->Fetch();
569 histogram_helper()->ExpectUniqueSample(
570 "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun",
571 signin_metrics::ACCOUNTS_SAME,
573 histogram_helper()->ExpectUniqueSample(
574 "Signin.Reconciler.AddedToCookieJar.FirstRun", 1, 1);
575 histogram_helper()->ExpectUniqueSample(
576 "Signin.Reconciler.AddedToChrome.FirstRun", 0, 1);
578 // Do another pass after I've added a third account to the token service
581 GaiaUrls::GetInstance()->list_accounts_url().spec(),
582 "[\"f\", [[\"b\", 0, \"n\", \"user@gmail.com\", \"p\", 0, 0, 0, 0, 1], "
583 "[\"b\", 0, \"n\", \"other@gmail.com\", \"p\", 0, 0, 0, 0, 1]]]",
585 net::URLRequestStatus::SUCCESS);
586 // This will cause the reconcilor to fire.
587 token_service()->UpdateCredentials("third@gmail.com", "refresh_token");
589 token_service()->IssueAllTokensForAccount(
592 base::Time::Now() + base::TimeDelta::FromHours(1));
593 token_service()->IssueAllTokensForAccount(
596 base::Time::Now() + base::TimeDelta::FromHours(1));
597 token_service()->IssueAllTokensForAccount(
600 base::Time::Now() + base::TimeDelta::FromHours(1));
602 base::RunLoop().RunUntilIdle();
604 ASSERT_TRUE(reconcilor->is_reconcile_started_);
605 SimulateMergeSessionCompleted(
606 reconcilor, "third@gmail.com", GoogleServiceAuthError::AuthErrorNone());
607 ASSERT_FALSE(reconcilor->is_reconcile_started_);
609 histogram_helper()->Fetch();
610 histogram_helper()->ExpectUniqueSample(
611 "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun",
612 signin_metrics::ACCOUNTS_SAME,
614 histogram_helper()->ExpectUniqueSample(
615 "Signin.Reconciler.AddedToCookieJar.FirstRun", 1, 1);
616 histogram_helper()->ExpectUniqueSample(
617 "Signin.Reconciler.AddedToChrome.FirstRun", 0, 1);
618 histogram_helper()->ExpectUniqueSample(
619 "Signin.Reconciler.DifferentPrimaryAccounts.SubsequentRun",
620 signin_metrics::ACCOUNTS_SAME,
622 histogram_helper()->ExpectUniqueSample(
623 "Signin.Reconciler.AddedToCookieJar.SubsequentRun", 1, 1);
624 histogram_helper()->ExpectUniqueSample(
625 "Signin.Reconciler.AddedToChrome.SubsequentRun", 0, 1);
628 TEST_P(AccountReconcilorTest, StartReconcileAddToChrome) {
629 signin_manager()->SetAuthenticatedUsername("user@gmail.com");
630 token_service()->UpdateCredentials("user@gmail.com", "refresh_token");
632 EXPECT_CALL(*GetMockReconcilor(),
633 PerformAddToChromeAction("other@gmail.com", 1));
635 SetFakeResponse(GaiaUrls::GetInstance()->list_accounts_url().spec(),
636 "[\"f\", [[\"b\", 0, \"n\", \"user@gmail.com\", \"p\", 0, 0, 0, 0, 1], "
637 "[\"b\", 0, \"n\", \"other@gmail.com\", \"p\", 0, 0, 0, 0, 1]]]",
638 net::HTTP_OK, net::URLRequestStatus::SUCCESS);
639 SetFakeResponse("https://www.googleapis.com/oauth2/v1/userinfo",
640 "{\"id\":\"foo\"}", net::HTTP_OK, net::URLRequestStatus::SUCCESS);
642 AccountReconcilor* reconcilor = GetMockReconcilor();
643 reconcilor->StartReconcile();
644 token_service()->IssueAllTokensForAccount("user@gmail.com", "access_token",
645 base::Time::Now() + base::TimeDelta::FromHours(1));
647 base::RunLoop().RunUntilIdle();
648 ASSERT_TRUE(reconcilor->is_reconcile_started_);
649 SimulateRefreshTokenFetched(reconcilor, "other@gmail.com", "");
650 ASSERT_FALSE(reconcilor->is_reconcile_started_);
652 histogram_helper()->Fetch();
653 histogram_helper()->ExpectUniqueSample(
654 "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun",
655 signin_metrics::ACCOUNTS_SAME,
657 histogram_helper()->ExpectUniqueSample(
658 "Signin.Reconciler.AddedToCookieJar.FirstRun", 0, 1);
659 histogram_helper()->ExpectUniqueSample(
660 "Signin.Reconciler.AddedToChrome.FirstRun", 1, 1);
663 TEST_P(AccountReconcilorTest, StartReconcileBadPrimary) {
664 signin_manager()->SetAuthenticatedUsername("user@gmail.com");
665 token_service()->UpdateCredentials("user@gmail.com", "refresh_token");
666 token_service()->UpdateCredentials("other@gmail.com", "refresh_token");
668 EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction());
669 EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction("user@gmail.com"));
670 EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction("other@gmail.com"));
672 SetFakeResponse(GaiaUrls::GetInstance()->list_accounts_url().spec(),
673 "[\"f\", [[\"b\", 0, \"n\", \"other@gmail.com\", \"p\", 0, 0, 0, 0, 1], "
674 "[\"b\", 0, \"n\", \"user@gmail.com\", \"p\", 0, 0, 0, 0, 1]]]",
675 net::HTTP_OK, net::URLRequestStatus::SUCCESS);
676 SetFakeResponse("https://www.googleapis.com/oauth2/v1/userinfo",
677 "{\"id\":\"foo\"}", net::HTTP_OK, net::URLRequestStatus::SUCCESS);
679 AccountReconcilor* reconcilor = GetMockReconcilor();
680 reconcilor->StartReconcile();
681 token_service()->IssueAllTokensForAccount("other@gmail.com", "access_token",
682 base::Time::Now() + base::TimeDelta::FromHours(1));
683 token_service()->IssueAllTokensForAccount("user@gmail.com", "access_token",
684 base::Time::Now() + base::TimeDelta::FromHours(1));
686 base::RunLoop().RunUntilIdle();
687 ASSERT_TRUE(reconcilor->is_reconcile_started_);
688 SimulateMergeSessionCompleted(reconcilor, "other@gmail.com",
689 GoogleServiceAuthError::AuthErrorNone());
690 ASSERT_TRUE(reconcilor->is_reconcile_started_);
691 SimulateMergeSessionCompleted(reconcilor, "user@gmail.com",
692 GoogleServiceAuthError::AuthErrorNone());
693 ASSERT_FALSE(reconcilor->is_reconcile_started_);
695 histogram_helper()->Fetch();
696 histogram_helper()->ExpectUniqueSample(
697 "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun",
698 signin_metrics::COOKIE_AND_TOKEN_PRIMARIES_DIFFERENT,
700 histogram_helper()->ExpectUniqueSample(
701 "Signin.Reconciler.AddedToCookieJar.FirstRun", 2, 1);
702 histogram_helper()->ExpectUniqueSample(
703 "Signin.Reconciler.AddedToChrome.FirstRun", 0, 1);
706 TEST_P(AccountReconcilorTest, StartReconcileOnlyOnce) {
707 signin_manager()->SetAuthenticatedUsername(kTestEmail);
708 token_service()->UpdateCredentials(kTestEmail, "refresh_token");
710 AccountReconcilor* reconcilor =
711 AccountReconcilorFactory::GetForProfile(profile());
712 ASSERT_TRUE(reconcilor);
714 SetFakeResponse(GaiaUrls::GetInstance()->list_accounts_url().spec(),
715 "[\"f\", [[\"b\", 0, \"n\", \"user@gmail.com\", \"p\", 0, 0, 0, 0, 1]]]",
716 net::HTTP_OK, net::URLRequestStatus::SUCCESS);
717 SetFakeResponse("https://www.googleapis.com/oauth2/v1/userinfo",
718 "{\"id\":\"foo\"}", net::HTTP_OK, net::URLRequestStatus::SUCCESS);
720 ASSERT_FALSE(reconcilor->is_reconcile_started_);
721 reconcilor->StartReconcile();
722 ASSERT_TRUE(reconcilor->is_reconcile_started_);
724 token_service()->IssueAllTokensForAccount("user@gmail.com", "access_token",
725 base::Time::Now() + base::TimeDelta::FromHours(1));
727 base::RunLoop().RunUntilIdle();
728 ASSERT_FALSE(reconcilor->is_reconcile_started_);
731 TEST_P(AccountReconcilorTest, StartReconcileWithSessionInfoExpiredDefault) {
732 signin_manager()->SetAuthenticatedUsername("user@gmail.com");
733 token_service()->UpdateCredentials("user@gmail.com", "refresh_token");
734 token_service()->UpdateCredentials("other@gmail.com", "refresh_token");
736 EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction("user@gmail.com"));
738 SetFakeResponse(GaiaUrls::GetInstance()->list_accounts_url().spec(),
739 "[\"f\", [[\"b\", 0, \"n\", \"user@gmail.com\", \"p\", 0, 0, 0, 0, 0],"
740 "[\"b\", 0, \"n\", \"other@gmail.com\", \"p\", 0, 0, 0, 0, 1]]]",
741 net::HTTP_OK, net::URLRequestStatus::SUCCESS);
742 SetFakeResponse("https://www.googleapis.com/oauth2/v1/userinfo",
743 "{\"id\":\"foo\"}", net::HTTP_OK, net::URLRequestStatus::SUCCESS);
745 AccountReconcilor* reconcilor =
746 AccountReconcilorFactory::GetForProfile(profile());
747 ASSERT_TRUE(reconcilor);
749 ASSERT_FALSE(reconcilor->is_reconcile_started_);
750 reconcilor->StartReconcile();
751 ASSERT_TRUE(reconcilor->is_reconcile_started_);
753 token_service()->IssueAllTokensForAccount("user@gmail.com", "access_token",
754 base::Time::Now() + base::TimeDelta::FromHours(1));
755 token_service()->IssueAllTokensForAccount("other@gmail.com", "access_token",
756 base::Time::Now() + base::TimeDelta::FromHours(1));
758 base::RunLoop().RunUntilIdle();
759 SimulateMergeSessionCompleted(reconcilor, "user@gmail.com",
760 GoogleServiceAuthError::AuthErrorNone());
761 ASSERT_FALSE(reconcilor->is_reconcile_started_);
764 INSTANTIATE_TEST_CASE_P(AccountReconcilorMaybeEnabled,
765 AccountReconcilorTest,