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. 4 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" 35 36 namespace { 37 38 const char kTestEmail[] = "user (at) 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"}; 46 47 class MockAccountReconcilor : public testing::StrictMock<AccountReconcilor> { 48 public: 49 static KeyedService* Build(content::BrowserContext* context); 50 51 MockAccountReconcilor(ProfileOAuth2TokenService* token_service, 52 SigninManagerBase* signin_manager, 53 SigninClient* client); 54 virtual ~MockAccountReconcilor() {} 55 56 MOCK_METHOD1(PerformMergeAction, void(const std::string& account_id)); 57 MOCK_METHOD1(PerformStartRemoveAction, void(const std::string& account_id)); 58 MOCK_METHOD3( 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, 64 int session_index)); 65 MOCK_METHOD0(PerformLogoutAllAccountsAction, void()); 66 }; 67 68 // static 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 */); 76 return reconcilor; 77 } 78 79 MockAccountReconcilor::MockAccountReconcilor( 80 ProfileOAuth2TokenService* token_service, 81 SigninManagerBase* signin_manager, 82 SigninClient* client) 83 : testing::StrictMock<AccountReconcilor>(token_service, 84 signin_manager, 85 client) {} 86 87 } // namespace 88 89 class AccountReconcilorTest : public ::testing::TestWithParam<bool> { 90 public: 91 AccountReconcilorTest(); 92 virtual void SetUp() OVERRIDE; 93 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_; } 98 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); 104 } 105 106 MockAccountReconcilor* GetMockReconcilor(); 107 108 void SimulateMergeSessionCompleted( 109 MergeSessionHelper::Observer* observer, 110 const std::string& account_id, 111 const GoogleServiceAuthError& error); 112 113 void SimulateRefreshTokenFetched( 114 AccountReconcilor* reconcilor, 115 const std::string& account_id, 116 const std::string& refresh_token); 117 118 private: 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_; 127 128 DISALLOW_COPY_AND_ASSIGN(AccountReconcilorTest); 129 }; 130 131 AccountReconcilorTest::AccountReconcilorTest() 132 : signin_manager_(NULL), 133 token_service_(NULL), 134 mock_reconcilor_(NULL), 135 url_fetcher_factory_(NULL) {} 136 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() || 140 GetParam()) { 141 CommandLine::ForCurrentProcess()->AppendSwitch( 142 switches::kEnableNewProfileManagement); 143 } 144 145 testing_profile_manager_.reset( 146 new TestingProfileManager(TestingBrowserProcess::GetGlobal())); 147 ASSERT_TRUE(testing_profile_manager_.get()->SetUp()); 148 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)); 159 160 profile_ = testing_profile_manager_.get()->CreateTestingProfile("name", 161 scoped_ptr<PrefServiceSyncable>(), 162 base::UTF8ToUTF16("name"), 0, std::string(), 163 factories); 164 165 signin_manager_ = 166 static_cast<FakeSigninManagerForTesting*>( 167 SigninManagerFactory::GetForProfile(profile())); 168 169 token_service_ = 170 static_cast<FakeProfileOAuth2TokenService*>( 171 ProfileOAuth2TokenServiceFactory::GetForProfile(profile())); 172 173 // Take a new snapshot of the concerned histograms before each test 174 histogram_helper_.PrepareSnapshot(kHistogramsToSnapshot, 175 arraysize(kHistogramsToSnapshot)); 176 } 177 178 MockAccountReconcilor* AccountReconcilorTest::GetMockReconcilor() { 179 if (!mock_reconcilor_) { 180 mock_reconcilor_ = 181 static_cast<MockAccountReconcilor*>( 182 AccountReconcilorFactory::GetForProfile(profile())); 183 } 184 185 return mock_reconcilor_; 186 } 187 188 void AccountReconcilorTest::SimulateMergeSessionCompleted( 189 MergeSessionHelper::Observer* observer, 190 const std::string& account_id, 191 const GoogleServiceAuthError& error) { 192 observer->MergeSessionCompleted(account_id, error); 193 } 194 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); 200 } 201 202 TEST_F(AccountReconcilorTest, Basic) { 203 AccountReconcilor* reconcilor = 204 AccountReconcilorFactory::GetForProfile(profile()); 205 ASSERT_TRUE(reconcilor); 206 ASSERT_EQ(token_service(), reconcilor->token_service()); 207 } 208 209 #if !defined(OS_CHROMEOS) 210 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()); 220 221 signin_manager()->set_password("password"); 222 signin_manager()->OnExternalSigninCompleted(kTestEmail); 223 ASSERT_TRUE(reconcilor->IsRegisteredWithTokenService()); 224 225 EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction()); 226 227 signin_manager()->SignOut(signin_metrics::SIGNOUT_TEST); 228 ASSERT_FALSE(reconcilor->IsRegisteredWithTokenService()); 229 } 230 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"); 238 239 AccountReconcilor* reconcilor = 240 AccountReconcilorFactory::GetForProfile(profile()); 241 ASSERT_TRUE(reconcilor); 242 ASSERT_TRUE(reconcilor->IsRegisteredWithTokenService()); 243 244 // Simulate reauth. The state of the reconcilor should not change. 245 signin_manager()->OnExternalSigninCompleted(kTestEmail); 246 ASSERT_TRUE(reconcilor->IsRegisteredWithTokenService()); 247 } 248 249 #endif // !defined(OS_CHROMEOS) 250 251 TEST_F(AccountReconcilorTest, ProfileAlreadyConnected) { 252 signin_manager()->SetAuthenticatedUsername(kTestEmail); 253 254 AccountReconcilor* reconcilor = 255 AccountReconcilorFactory::GetForProfile(profile()); 256 ASSERT_TRUE(reconcilor); 257 ASSERT_TRUE(reconcilor->IsRegisteredWithTokenService()); 258 } 259 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); 266 267 SetFakeResponse(GaiaUrls::GetInstance()->list_accounts_url().spec(), 268 "[\"f\", [[\"b\", 0, \"n\", \"user (at) gmail.com\", \"p\", 0, 0, 0, 0, 0]]]", 269 net::HTTP_OK, net::URLRequestStatus::SUCCESS); 270 271 reconcilor->StartReconcile(); 272 ASSERT_FALSE(reconcilor->AreGaiaAccountsSet()); 273 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 (at) gmail.com", accounts[0].first); 280 } 281 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); 288 289 SetFakeResponse(GaiaUrls::GetInstance()->list_accounts_url().spec(), "", 290 net::HTTP_NOT_FOUND, net::URLRequestStatus::SUCCESS); 291 292 reconcilor->StartReconcile(); 293 ASSERT_FALSE(reconcilor->AreGaiaAccountsSet()); 294 295 base::RunLoop().RunUntilIdle(); 296 ASSERT_EQ(0u, reconcilor->GetGaiaAccountsForTesting().size()); 297 } 298 299 TEST_F(AccountReconcilorTest, ValidateAccountsFromTokens) { 300 signin_manager()->SetAuthenticatedUsername(kTestEmail); 301 token_service()->UpdateCredentials(kTestEmail, "refresh_token"); 302 303 AccountReconcilor* reconcilor = 304 AccountReconcilorFactory::GetForProfile(profile()); 305 ASSERT_TRUE(reconcilor); 306 307 reconcilor->ValidateAccountsFromTokenService(); 308 ASSERT_FALSE(reconcilor->AreAllRefreshTokensChecked()); 309 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)); 314 315 base::RunLoop().RunUntilIdle(); 316 ASSERT_TRUE(reconcilor->AreAllRefreshTokensChecked()); 317 ASSERT_EQ(1u, reconcilor->GetValidChromeAccountsForTesting().size()); 318 ASSERT_EQ(0u, reconcilor->GetInvalidChromeAccountsForTesting().size()); 319 } 320 321 TEST_F(AccountReconcilorTest, ValidateAccountsFromTokensFailedUserInfo) { 322 signin_manager()->SetAuthenticatedUsername(kTestEmail); 323 token_service()->UpdateCredentials(kTestEmail, "refresh_token"); 324 325 AccountReconcilor* reconcilor = 326 AccountReconcilorFactory::GetForProfile(profile()); 327 ASSERT_TRUE(reconcilor); 328 329 reconcilor->ValidateAccountsFromTokenService(); 330 ASSERT_FALSE(reconcilor->AreAllRefreshTokensChecked()); 331 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)); 336 337 base::RunLoop().RunUntilIdle(); 338 ASSERT_TRUE(reconcilor->AreAllRefreshTokensChecked()); 339 ASSERT_EQ(0u, reconcilor->GetValidChromeAccountsForTesting().size()); 340 ASSERT_EQ(1u, reconcilor->GetInvalidChromeAccountsForTesting().size()); 341 } 342 343 TEST_F(AccountReconcilorTest, ValidateAccountsFromTokensFailedTokenRequest) { 344 signin_manager()->SetAuthenticatedUsername(kTestEmail); 345 token_service()->UpdateCredentials(kTestEmail, "refresh_token"); 346 347 AccountReconcilor* reconcilor = 348 AccountReconcilorFactory::GetForProfile(profile()); 349 ASSERT_TRUE(reconcilor); 350 351 reconcilor->ValidateAccountsFromTokenService(); 352 ASSERT_FALSE(reconcilor->AreAllRefreshTokensChecked()); 353 354 token_service()->IssueErrorForAllPendingRequests( 355 GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS)); 356 357 base::RunLoop().RunUntilIdle(); 358 ASSERT_TRUE(reconcilor->AreAllRefreshTokensChecked()); 359 ASSERT_EQ(0u, reconcilor->GetValidChromeAccountsForTesting().size()); 360 ASSERT_EQ(1u, reconcilor->GetInvalidChromeAccountsForTesting().size()); 361 } 362 363 TEST_P(AccountReconcilorTest, StartReconcileNoop) { 364 signin_manager()->SetAuthenticatedUsername(kTestEmail); 365 token_service()->UpdateCredentials(kTestEmail, "refresh_token"); 366 367 AccountReconcilor* reconcilor = 368 AccountReconcilorFactory::GetForProfile(profile()); 369 ASSERT_TRUE(reconcilor); 370 371 SetFakeResponse(GaiaUrls::GetInstance()->list_accounts_url().spec(), 372 "[\"f\", [[\"b\", 0, \"n\", \"user (at) 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); 376 377 reconcilor->StartReconcile(); 378 ASSERT_FALSE(reconcilor->AreGaiaAccountsSet()); 379 ASSERT_FALSE(reconcilor->AreAllRefreshTokensChecked()); 380 381 base::RunLoop().RunUntilIdle(); 382 ASSERT_TRUE(reconcilor->AreGaiaAccountsSet()); 383 ASSERT_EQ(1u, reconcilor->GetGaiaAccountsForTesting().size()); 384 ASSERT_FALSE(reconcilor->AreAllRefreshTokensChecked()); 385 386 token_service()->IssueAllTokensForAccount("user (at) gmail.com", "access_token", 387 base::Time::Now() + base::TimeDelta::FromHours(1)); 388 389 base::RunLoop().RunUntilIdle(); 390 ASSERT_TRUE(reconcilor->AreAllRefreshTokensChecked()); 391 ASSERT_FALSE(reconcilor->is_reconcile_started_); 392 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, 399 1); 400 } 401 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 (at) hmail.com", as seen by the 408 // token service, will be considered the same as "dots (at) gmail.com" as returned 409 // by gaia::ParseListAccountsData(). 410 TEST_P(AccountReconcilorTest, StartReconcileNoopWithDots) { 411 signin_manager()->SetAuthenticatedUsername("Dot.S (at) gmail.com"); 412 token_service()->UpdateCredentials("Dot.S (at) gmail.com", "refresh_token"); 413 414 AccountReconcilor* reconcilor = 415 AccountReconcilorFactory::GetForProfile(profile()); 416 ASSERT_TRUE(reconcilor); 417 418 SetFakeResponse(GaiaUrls::GetInstance()->list_accounts_url().spec(), 419 "[\"f\", [[\"b\", 0, \"n\", \"dot.s (at) 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); 423 424 reconcilor->StartReconcile(); 425 ASSERT_FALSE(reconcilor->AreGaiaAccountsSet()); 426 ASSERT_FALSE(reconcilor->AreAllRefreshTokensChecked()); 427 428 base::RunLoop().RunUntilIdle(); 429 ASSERT_TRUE(reconcilor->AreGaiaAccountsSet()); 430 ASSERT_EQ(1u, reconcilor->GetGaiaAccountsForTesting().size()); 431 ASSERT_STREQ("dots (at) gmail.com", 432 reconcilor->GetGaiaAccountsForTesting()[0].first.c_str()); 433 ASSERT_FALSE(reconcilor->AreAllRefreshTokensChecked()); 434 435 token_service()->IssueAllTokensForAccount("Dot.S (at) gmail.com", "access_token", 436 base::Time::Now() + base::TimeDelta::FromHours(1)); 437 438 base::RunLoop().RunUntilIdle(); 439 ASSERT_TRUE(reconcilor->AreAllRefreshTokensChecked()); 440 ASSERT_FALSE(reconcilor->is_reconcile_started_); 441 442 histogram_helper()->Fetch(); 443 histogram_helper()->ExpectUniqueSample( 444 "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", 445 signin_metrics::ACCOUNTS_SAME, 446 1); 447 } 448 449 TEST_P(AccountReconcilorTest, StartReconcileNoopMultiple) { 450 signin_manager()->SetAuthenticatedUsername("user (at) gmail.com"); 451 token_service()->UpdateCredentials("user (at) gmail.com", "refresh_token"); 452 token_service()->UpdateCredentials("other (at) gmail.com", "refresh_token"); 453 454 AccountReconcilor* reconcilor = 455 AccountReconcilorFactory::GetForProfile(profile()); 456 ASSERT_TRUE(reconcilor); 457 458 SetFakeResponse(GaiaUrls::GetInstance()->list_accounts_url().spec(), 459 "[\"f\", [[\"b\", 0, \"n\", \"user (at) gmail.com\", \"p\", 0, 0, 0, 0, 1], " 460 "[\"b\", 0, \"n\", \"other (at) 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); 464 465 reconcilor->StartReconcile(); 466 ASSERT_FALSE(reconcilor->AreGaiaAccountsSet()); 467 ASSERT_FALSE(reconcilor->AreAllRefreshTokensChecked()); 468 469 base::RunLoop().RunUntilIdle(); 470 ASSERT_TRUE(reconcilor->AreGaiaAccountsSet()); 471 ASSERT_FALSE(reconcilor->AreAllRefreshTokensChecked()); 472 ASSERT_EQ(2u, reconcilor->GetGaiaAccountsForTesting().size()); 473 474 token_service()->IssueAllTokensForAccount("other (at) gmail.com", "access_token", 475 base::Time::Now() + base::TimeDelta::FromHours(1)); 476 477 base::RunLoop().RunUntilIdle(); 478 ASSERT_FALSE(reconcilor->AreAllRefreshTokensChecked()); 479 480 token_service()->IssueAllTokensForAccount("user (at) gmail.com", "access_token", 481 base::Time::Now() + base::TimeDelta::FromHours(1)); 482 483 base::RunLoop().RunUntilIdle(); 484 ASSERT_TRUE(reconcilor->AreAllRefreshTokensChecked()); 485 ASSERT_FALSE(reconcilor->is_reconcile_started_); 486 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, 493 1); 494 } 495 496 TEST_P(AccountReconcilorTest, StartReconcileAddToCookie) { 497 signin_manager()->SetAuthenticatedUsername("user (at) gmail.com"); 498 token_service()->UpdateCredentials("user (at) gmail.com", "refresh_token"); 499 token_service()->UpdateCredentials("other (at) gmail.com", "refresh_token"); 500 501 EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction("other (at) gmail.com")); 502 503 SetFakeResponse(GaiaUrls::GetInstance()->list_accounts_url().spec(), 504 "[\"f\", [[\"b\", 0, \"n\", \"user (at) 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); 508 509 AccountReconcilor* reconcilor = GetMockReconcilor(); 510 reconcilor->StartReconcile(); 511 token_service()->IssueAllTokensForAccount("other (at) gmail.com", "access_token", 512 base::Time::Now() + base::TimeDelta::FromHours(1)); 513 token_service()->IssueAllTokensForAccount("user (at) gmail.com", "access_token", 514 base::Time::Now() + base::TimeDelta::FromHours(1)); 515 516 base::RunLoop().RunUntilIdle(); 517 ASSERT_TRUE(reconcilor->is_reconcile_started_); 518 SimulateMergeSessionCompleted(reconcilor, "other (at) gmail.com", 519 GoogleServiceAuthError::AuthErrorNone()); 520 ASSERT_FALSE(reconcilor->is_reconcile_started_); 521 522 histogram_helper()->Fetch(); 523 histogram_helper()->ExpectUniqueSample( 524 "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", 525 signin_metrics::ACCOUNTS_SAME, 526 1); 527 histogram_helper()->ExpectUniqueSample( 528 "Signin.Reconciler.AddedToCookieJar.FirstRun", 1, 1); 529 histogram_helper()->ExpectUniqueSample( 530 "Signin.Reconciler.AddedToChrome.FirstRun", 0, 1); 531 } 532 533 TEST_P(AccountReconcilorTest, StartReconcileAddToCookieTwice) { 534 signin_manager()->SetAuthenticatedUsername("user (at) gmail.com"); 535 token_service()->UpdateCredentials("user (at) gmail.com", "refresh_token"); 536 token_service()->UpdateCredentials("other (at) gmail.com", "refresh_token"); 537 538 EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction("other (at) gmail.com")); 539 EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction("third (at) gmail.com")); 540 541 SetFakeResponse( 542 GaiaUrls::GetInstance()->list_accounts_url().spec(), 543 "[\"f\", [[\"b\", 0, \"n\", \"user (at) gmail.com\", \"p\", 0, 0, 0, 0, 1]]]", 544 net::HTTP_OK, 545 net::URLRequestStatus::SUCCESS); 546 SetFakeResponse("https://www.googleapis.com/oauth2/v1/userinfo", 547 "{\"id\":\"foo\"}", 548 net::HTTP_OK, 549 net::URLRequestStatus::SUCCESS); 550 551 AccountReconcilor* reconcilor = GetMockReconcilor(); 552 reconcilor->StartReconcile(); 553 token_service()->IssueAllTokensForAccount( 554 "other (at) gmail.com", 555 "access_token", 556 base::Time::Now() + base::TimeDelta::FromHours(1)); 557 token_service()->IssueAllTokensForAccount( 558 "user (at) gmail.com", 559 "access_token", 560 base::Time::Now() + base::TimeDelta::FromHours(1)); 561 562 base::RunLoop().RunUntilIdle(); 563 ASSERT_TRUE(reconcilor->is_reconcile_started_); 564 SimulateMergeSessionCompleted( 565 reconcilor, "other (at) gmail.com", GoogleServiceAuthError::AuthErrorNone()); 566 ASSERT_FALSE(reconcilor->is_reconcile_started_); 567 568 histogram_helper()->Fetch(); 569 histogram_helper()->ExpectUniqueSample( 570 "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", 571 signin_metrics::ACCOUNTS_SAME, 572 1); 573 histogram_helper()->ExpectUniqueSample( 574 "Signin.Reconciler.AddedToCookieJar.FirstRun", 1, 1); 575 histogram_helper()->ExpectUniqueSample( 576 "Signin.Reconciler.AddedToChrome.FirstRun", 0, 1); 577 578 // Do another pass after I've added a third account to the token service 579 580 SetFakeResponse( 581 GaiaUrls::GetInstance()->list_accounts_url().spec(), 582 "[\"f\", [[\"b\", 0, \"n\", \"user (at) gmail.com\", \"p\", 0, 0, 0, 0, 1], " 583 "[\"b\", 0, \"n\", \"other (at) gmail.com\", \"p\", 0, 0, 0, 0, 1]]]", 584 net::HTTP_OK, 585 net::URLRequestStatus::SUCCESS); 586 // This will cause the reconcilor to fire. 587 token_service()->UpdateCredentials("third (at) gmail.com", "refresh_token"); 588 589 token_service()->IssueAllTokensForAccount( 590 "other (at) gmail.com", 591 "access_token", 592 base::Time::Now() + base::TimeDelta::FromHours(1)); 593 token_service()->IssueAllTokensForAccount( 594 "user (at) gmail.com", 595 "access_token", 596 base::Time::Now() + base::TimeDelta::FromHours(1)); 597 token_service()->IssueAllTokensForAccount( 598 "third (at) gmail.com", 599 "access_token", 600 base::Time::Now() + base::TimeDelta::FromHours(1)); 601 602 base::RunLoop().RunUntilIdle(); 603 604 ASSERT_TRUE(reconcilor->is_reconcile_started_); 605 SimulateMergeSessionCompleted( 606 reconcilor, "third (at) gmail.com", GoogleServiceAuthError::AuthErrorNone()); 607 ASSERT_FALSE(reconcilor->is_reconcile_started_); 608 609 histogram_helper()->Fetch(); 610 histogram_helper()->ExpectUniqueSample( 611 "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", 612 signin_metrics::ACCOUNTS_SAME, 613 1); 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, 621 1); 622 histogram_helper()->ExpectUniqueSample( 623 "Signin.Reconciler.AddedToCookieJar.SubsequentRun", 1, 1); 624 histogram_helper()->ExpectUniqueSample( 625 "Signin.Reconciler.AddedToChrome.SubsequentRun", 0, 1); 626 } 627 628 TEST_P(AccountReconcilorTest, StartReconcileAddToChrome) { 629 signin_manager()->SetAuthenticatedUsername("user (at) gmail.com"); 630 token_service()->UpdateCredentials("user (at) gmail.com", "refresh_token"); 631 632 EXPECT_CALL(*GetMockReconcilor(), 633 PerformAddToChromeAction("other (at) gmail.com", 1)); 634 635 SetFakeResponse(GaiaUrls::GetInstance()->list_accounts_url().spec(), 636 "[\"f\", [[\"b\", 0, \"n\", \"user (at) gmail.com\", \"p\", 0, 0, 0, 0, 1], " 637 "[\"b\", 0, \"n\", \"other (at) 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); 641 642 AccountReconcilor* reconcilor = GetMockReconcilor(); 643 reconcilor->StartReconcile(); 644 token_service()->IssueAllTokensForAccount("user (at) gmail.com", "access_token", 645 base::Time::Now() + base::TimeDelta::FromHours(1)); 646 647 base::RunLoop().RunUntilIdle(); 648 ASSERT_TRUE(reconcilor->is_reconcile_started_); 649 SimulateRefreshTokenFetched(reconcilor, "other (at) gmail.com", ""); 650 ASSERT_FALSE(reconcilor->is_reconcile_started_); 651 652 histogram_helper()->Fetch(); 653 histogram_helper()->ExpectUniqueSample( 654 "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", 655 signin_metrics::ACCOUNTS_SAME, 656 1); 657 histogram_helper()->ExpectUniqueSample( 658 "Signin.Reconciler.AddedToCookieJar.FirstRun", 0, 1); 659 histogram_helper()->ExpectUniqueSample( 660 "Signin.Reconciler.AddedToChrome.FirstRun", 1, 1); 661 } 662 663 TEST_P(AccountReconcilorTest, StartReconcileBadPrimary) { 664 signin_manager()->SetAuthenticatedUsername("user (at) gmail.com"); 665 token_service()->UpdateCredentials("user (at) gmail.com", "refresh_token"); 666 token_service()->UpdateCredentials("other (at) gmail.com", "refresh_token"); 667 668 EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction()); 669 EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction("user (at) gmail.com")); 670 EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction("other (at) gmail.com")); 671 672 SetFakeResponse(GaiaUrls::GetInstance()->list_accounts_url().spec(), 673 "[\"f\", [[\"b\", 0, \"n\", \"other (at) gmail.com\", \"p\", 0, 0, 0, 0, 1], " 674 "[\"b\", 0, \"n\", \"user (at) 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); 678 679 AccountReconcilor* reconcilor = GetMockReconcilor(); 680 reconcilor->StartReconcile(); 681 token_service()->IssueAllTokensForAccount("other (at) gmail.com", "access_token", 682 base::Time::Now() + base::TimeDelta::FromHours(1)); 683 token_service()->IssueAllTokensForAccount("user (at) gmail.com", "access_token", 684 base::Time::Now() + base::TimeDelta::FromHours(1)); 685 686 base::RunLoop().RunUntilIdle(); 687 ASSERT_TRUE(reconcilor->is_reconcile_started_); 688 SimulateMergeSessionCompleted(reconcilor, "other (at) gmail.com", 689 GoogleServiceAuthError::AuthErrorNone()); 690 ASSERT_TRUE(reconcilor->is_reconcile_started_); 691 SimulateMergeSessionCompleted(reconcilor, "user (at) gmail.com", 692 GoogleServiceAuthError::AuthErrorNone()); 693 ASSERT_FALSE(reconcilor->is_reconcile_started_); 694 695 histogram_helper()->Fetch(); 696 histogram_helper()->ExpectUniqueSample( 697 "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", 698 signin_metrics::COOKIE_AND_TOKEN_PRIMARIES_DIFFERENT, 699 1); 700 histogram_helper()->ExpectUniqueSample( 701 "Signin.Reconciler.AddedToCookieJar.FirstRun", 2, 1); 702 histogram_helper()->ExpectUniqueSample( 703 "Signin.Reconciler.AddedToChrome.FirstRun", 0, 1); 704 } 705 706 TEST_P(AccountReconcilorTest, StartReconcileOnlyOnce) { 707 signin_manager()->SetAuthenticatedUsername(kTestEmail); 708 token_service()->UpdateCredentials(kTestEmail, "refresh_token"); 709 710 AccountReconcilor* reconcilor = 711 AccountReconcilorFactory::GetForProfile(profile()); 712 ASSERT_TRUE(reconcilor); 713 714 SetFakeResponse(GaiaUrls::GetInstance()->list_accounts_url().spec(), 715 "[\"f\", [[\"b\", 0, \"n\", \"user (at) 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); 719 720 ASSERT_FALSE(reconcilor->is_reconcile_started_); 721 reconcilor->StartReconcile(); 722 ASSERT_TRUE(reconcilor->is_reconcile_started_); 723 724 token_service()->IssueAllTokensForAccount("user (at) gmail.com", "access_token", 725 base::Time::Now() + base::TimeDelta::FromHours(1)); 726 727 base::RunLoop().RunUntilIdle(); 728 ASSERT_FALSE(reconcilor->is_reconcile_started_); 729 } 730 731 TEST_P(AccountReconcilorTest, StartReconcileWithSessionInfoExpiredDefault) { 732 signin_manager()->SetAuthenticatedUsername("user (at) gmail.com"); 733 token_service()->UpdateCredentials("user (at) gmail.com", "refresh_token"); 734 token_service()->UpdateCredentials("other (at) gmail.com", "refresh_token"); 735 736 EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction("user (at) gmail.com")); 737 738 SetFakeResponse(GaiaUrls::GetInstance()->list_accounts_url().spec(), 739 "[\"f\", [[\"b\", 0, \"n\", \"user (at) gmail.com\", \"p\", 0, 0, 0, 0, 0]," 740 "[\"b\", 0, \"n\", \"other (at) 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); 744 745 AccountReconcilor* reconcilor = 746 AccountReconcilorFactory::GetForProfile(profile()); 747 ASSERT_TRUE(reconcilor); 748 749 ASSERT_FALSE(reconcilor->is_reconcile_started_); 750 reconcilor->StartReconcile(); 751 ASSERT_TRUE(reconcilor->is_reconcile_started_); 752 753 token_service()->IssueAllTokensForAccount("user (at) gmail.com", "access_token", 754 base::Time::Now() + base::TimeDelta::FromHours(1)); 755 token_service()->IssueAllTokensForAccount("other (at) gmail.com", "access_token", 756 base::Time::Now() + base::TimeDelta::FromHours(1)); 757 758 base::RunLoop().RunUntilIdle(); 759 SimulateMergeSessionCompleted(reconcilor, "user (at) gmail.com", 760 GoogleServiceAuthError::AuthErrorNone()); 761 ASSERT_FALSE(reconcilor->is_reconcile_started_); 762 } 763 764 INSTANTIATE_TEST_CASE_P(AccountReconcilorMaybeEnabled, 765 AccountReconcilorTest, 766 testing::Bool()); 767