1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "google_apis/gaia/account_tracker.h" 6 7 #include <algorithm> 8 #include <vector> 9 10 #include "base/message_loop/message_loop.h" 11 #include "base/strings/stringprintf.h" 12 #include "google_apis/gaia/fake_identity_provider.h" 13 #include "google_apis/gaia/fake_oauth2_token_service.h" 14 #include "google_apis/gaia/gaia_oauth_client.h" 15 #include "net/http/http_status_code.h" 16 #include "net/url_request/test_url_fetcher_factory.h" 17 #include "net/url_request/url_fetcher_delegate.h" 18 #include "net/url_request/url_request_test_util.h" 19 #include "testing/gtest/include/gtest/gtest.h" 20 21 namespace { 22 23 const char kPrimaryAccountKey[] = "primary_account (at) example.com"; 24 25 enum TrackingEventType { 26 ADDED, 27 REMOVED, 28 SIGN_IN, 29 SIGN_OUT 30 }; 31 32 std::string AccountKeyToObfuscatedId(const std::string email) { 33 return "obfid-" + email; 34 } 35 36 class TrackingEvent { 37 public: 38 TrackingEvent(TrackingEventType type, 39 const std::string& account_key, 40 const std::string& gaia_id) 41 : type_(type), 42 account_key_(account_key), 43 gaia_id_(gaia_id) {} 44 45 TrackingEvent(TrackingEventType type, 46 const std::string& account_key) 47 : type_(type), 48 account_key_(account_key), 49 gaia_id_(AccountKeyToObfuscatedId(account_key)) {} 50 51 bool operator==(const TrackingEvent& event) const { 52 return type_ == event.type_ && account_key_ == event.account_key_ && 53 gaia_id_ == event.gaia_id_; 54 } 55 56 std::string ToString() const { 57 const char * typestr = "INVALID"; 58 switch (type_) { 59 case ADDED: 60 typestr = "ADD"; 61 break; 62 case REMOVED: 63 typestr = "REM"; 64 break; 65 case SIGN_IN: 66 typestr = " IN"; 67 break; 68 case SIGN_OUT: 69 typestr = "OUT"; 70 break; 71 } 72 return base::StringPrintf("{ type: %s, email: %s, gaia: %s }", 73 typestr, 74 account_key_.c_str(), 75 gaia_id_.c_str()); 76 } 77 78 private: 79 friend bool CompareByUser(TrackingEvent a, TrackingEvent b); 80 81 TrackingEventType type_; 82 std::string account_key_; 83 std::string gaia_id_; 84 }; 85 86 bool CompareByUser(TrackingEvent a, TrackingEvent b) { 87 return a.account_key_ < b.account_key_; 88 } 89 90 std::string Str(const std::vector<TrackingEvent>& events) { 91 std::string str = "["; 92 bool needs_comma = false; 93 for (std::vector<TrackingEvent>::const_iterator it = 94 events.begin(); it != events.end(); ++it) { 95 if (needs_comma) 96 str += ",\n "; 97 needs_comma = true; 98 str += it->ToString(); 99 } 100 str += "]"; 101 return str; 102 } 103 104 } // namespace 105 106 namespace gaia { 107 108 class AccountTrackerObserver : public AccountTracker::Observer { 109 public: 110 AccountTrackerObserver() {} 111 virtual ~AccountTrackerObserver() {} 112 113 testing::AssertionResult CheckEvents(); 114 testing::AssertionResult CheckEvents(const TrackingEvent& e1); 115 testing::AssertionResult CheckEvents(const TrackingEvent& e1, 116 const TrackingEvent& e2); 117 testing::AssertionResult CheckEvents(const TrackingEvent& e1, 118 const TrackingEvent& e2, 119 const TrackingEvent& e3); 120 testing::AssertionResult CheckEvents(const TrackingEvent& e1, 121 const TrackingEvent& e2, 122 const TrackingEvent& e3, 123 const TrackingEvent& e4); 124 testing::AssertionResult CheckEvents(const TrackingEvent& e1, 125 const TrackingEvent& e2, 126 const TrackingEvent& e3, 127 const TrackingEvent& e4, 128 const TrackingEvent& e5); 129 testing::AssertionResult CheckEvents(const TrackingEvent& e1, 130 const TrackingEvent& e2, 131 const TrackingEvent& e3, 132 const TrackingEvent& e4, 133 const TrackingEvent& e5, 134 const TrackingEvent& e6); 135 void Clear(); 136 void SortEventsByUser(); 137 138 // AccountTracker::Observer implementation 139 virtual void OnAccountAdded(const AccountIds& ids) OVERRIDE; 140 virtual void OnAccountRemoved(const AccountIds& ids) OVERRIDE; 141 virtual void OnAccountSignInChanged(const AccountIds& ids, bool is_signed_in) 142 OVERRIDE; 143 144 private: 145 testing::AssertionResult CheckEvents( 146 const std::vector<TrackingEvent>& events); 147 148 std::vector<TrackingEvent> events_; 149 }; 150 151 void AccountTrackerObserver::OnAccountAdded(const AccountIds& ids) { 152 events_.push_back(TrackingEvent(ADDED, ids.email, ids.gaia)); 153 } 154 155 void AccountTrackerObserver::OnAccountRemoved(const AccountIds& ids) { 156 events_.push_back(TrackingEvent(REMOVED, ids.email, ids.gaia)); 157 } 158 159 void AccountTrackerObserver::OnAccountSignInChanged(const AccountIds& ids, 160 bool is_signed_in) { 161 events_.push_back( 162 TrackingEvent(is_signed_in ? SIGN_IN : SIGN_OUT, ids.email, ids.gaia)); 163 } 164 165 void AccountTrackerObserver::Clear() { 166 events_.clear(); 167 } 168 169 void AccountTrackerObserver::SortEventsByUser() { 170 std::stable_sort(events_.begin(), events_.end(), CompareByUser); 171 } 172 173 testing::AssertionResult AccountTrackerObserver::CheckEvents() { 174 std::vector<TrackingEvent> events; 175 return CheckEvents(events); 176 } 177 178 testing::AssertionResult AccountTrackerObserver::CheckEvents( 179 const TrackingEvent& e1) { 180 std::vector<TrackingEvent> events; 181 events.push_back(e1); 182 return CheckEvents(events); 183 } 184 185 testing::AssertionResult AccountTrackerObserver::CheckEvents( 186 const TrackingEvent& e1, 187 const TrackingEvent& e2) { 188 std::vector<TrackingEvent> events; 189 events.push_back(e1); 190 events.push_back(e2); 191 return CheckEvents(events); 192 } 193 194 testing::AssertionResult AccountTrackerObserver::CheckEvents( 195 const TrackingEvent& e1, 196 const TrackingEvent& e2, 197 const TrackingEvent& e3) { 198 std::vector<TrackingEvent> events; 199 events.push_back(e1); 200 events.push_back(e2); 201 events.push_back(e3); 202 return CheckEvents(events); 203 } 204 205 testing::AssertionResult AccountTrackerObserver::CheckEvents( 206 const TrackingEvent& e1, 207 const TrackingEvent& e2, 208 const TrackingEvent& e3, 209 const TrackingEvent& e4) { 210 std::vector<TrackingEvent> events; 211 events.push_back(e1); 212 events.push_back(e2); 213 events.push_back(e3); 214 events.push_back(e4); 215 return CheckEvents(events); 216 } 217 218 testing::AssertionResult AccountTrackerObserver::CheckEvents( 219 const TrackingEvent& e1, 220 const TrackingEvent& e2, 221 const TrackingEvent& e3, 222 const TrackingEvent& e4, 223 const TrackingEvent& e5) { 224 std::vector<TrackingEvent> events; 225 events.push_back(e1); 226 events.push_back(e2); 227 events.push_back(e3); 228 events.push_back(e4); 229 events.push_back(e5); 230 return CheckEvents(events); 231 } 232 233 testing::AssertionResult AccountTrackerObserver::CheckEvents( 234 const TrackingEvent& e1, 235 const TrackingEvent& e2, 236 const TrackingEvent& e3, 237 const TrackingEvent& e4, 238 const TrackingEvent& e5, 239 const TrackingEvent& e6) { 240 std::vector<TrackingEvent> events; 241 events.push_back(e1); 242 events.push_back(e2); 243 events.push_back(e3); 244 events.push_back(e4); 245 events.push_back(e5); 246 events.push_back(e6); 247 return CheckEvents(events); 248 } 249 250 testing::AssertionResult AccountTrackerObserver::CheckEvents( 251 const std::vector<TrackingEvent>& events) { 252 std::string maybe_newline = (events.size() + events_.size()) > 2 ? "\n" : ""; 253 testing::AssertionResult result( 254 (events_ == events) 255 ? testing::AssertionSuccess() 256 : (testing::AssertionFailure() 257 << "Expected " << maybe_newline << Str(events) << ", " 258 << maybe_newline << "Got " << maybe_newline << Str(events_))); 259 events_.clear(); 260 return result; 261 } 262 263 class IdentityAccountTrackerTest : public testing::Test { 264 public: 265 IdentityAccountTrackerTest() {} 266 267 virtual ~IdentityAccountTrackerTest() {} 268 269 virtual void SetUp() OVERRIDE { 270 271 fake_oauth2_token_service_.reset(new FakeOAuth2TokenService()); 272 273 fake_identity_provider_.reset( 274 new FakeIdentityProvider(fake_oauth2_token_service_.get())); 275 276 account_tracker_.reset( 277 new AccountTracker(fake_identity_provider_.get(), 278 new net::TestURLRequestContextGetter( 279 message_loop_.message_loop_proxy()))); 280 account_tracker_->AddObserver(&observer_); 281 } 282 283 virtual void TearDown() OVERRIDE { 284 account_tracker_->RemoveObserver(&observer_); 285 account_tracker_->Shutdown(); 286 } 287 288 AccountTrackerObserver* observer() { 289 return &observer_; 290 } 291 292 AccountTracker* account_tracker() { 293 return account_tracker_.get(); 294 } 295 296 // Helpers to pass fake events to the tracker. 297 298 void NotifyLogin(const std::string account_key) { 299 identity_provider()->LogIn(account_key); 300 } 301 302 void NotifyLogout() { identity_provider()->LogOut(); } 303 304 void NotifyTokenAvailable(const std::string& username) { 305 fake_oauth2_token_service_->AddAccount(username); 306 } 307 308 void NotifyTokenRevoked(const std::string& username) { 309 fake_oauth2_token_service_->RemoveAccount(username); 310 } 311 312 // Helpers to fake access token and user info fetching 313 void IssueAccessToken(const std::string& username) { 314 fake_oauth2_token_service_->IssueAllTokensForAccount( 315 username, "access_token-" + username, base::Time::Max()); 316 } 317 318 std::string GetValidTokenInfoResponse(const std::string account_key) { 319 return std::string("{ \"id\": \"") + AccountKeyToObfuscatedId(account_key) + 320 "\" }"; 321 } 322 323 void ReturnOAuthUrlFetchResults(int fetcher_id, 324 net::HttpStatusCode response_code, 325 const std::string& response_string); 326 327 void ReturnOAuthUrlFetchSuccess(const std::string& account_key); 328 void ReturnOAuthUrlFetchFailure(const std::string& account_key); 329 330 void SetupPrimaryLogin() { 331 // Initial setup for tests that start with a signed in profile. 332 NotifyLogin(kPrimaryAccountKey); 333 NotifyTokenAvailable(kPrimaryAccountKey); 334 ReturnOAuthUrlFetchSuccess(kPrimaryAccountKey); 335 observer()->Clear(); 336 } 337 338 std::string active_account_id() { 339 return identity_provider()->GetActiveAccountId(); 340 } 341 342 private: 343 FakeIdentityProvider* identity_provider() { 344 return static_cast<FakeIdentityProvider*>( 345 account_tracker_->identity_provider()); 346 } 347 348 base::MessageLoopForIO message_loop_; // net:: stuff needs IO message loop. 349 net::TestURLFetcherFactory test_fetcher_factory_; 350 scoped_ptr<FakeOAuth2TokenService> fake_oauth2_token_service_; 351 scoped_ptr<FakeIdentityProvider> fake_identity_provider_; 352 353 scoped_ptr<AccountTracker> account_tracker_; 354 AccountTrackerObserver observer_; 355 }; 356 357 void IdentityAccountTrackerTest::ReturnOAuthUrlFetchResults( 358 int fetcher_id, 359 net::HttpStatusCode response_code, 360 const std::string& response_string) { 361 362 net::TestURLFetcher* fetcher = 363 test_fetcher_factory_.GetFetcherByID(fetcher_id); 364 ASSERT_TRUE(fetcher); 365 fetcher->set_response_code(response_code); 366 fetcher->SetResponseString(response_string); 367 fetcher->delegate()->OnURLFetchComplete(fetcher); 368 } 369 370 void IdentityAccountTrackerTest::ReturnOAuthUrlFetchSuccess( 371 const std::string& account_key) { 372 IssueAccessToken(account_key); 373 ReturnOAuthUrlFetchResults(gaia::GaiaOAuthClient::kUrlFetcherId, 374 net::HTTP_OK, 375 GetValidTokenInfoResponse(account_key)); 376 } 377 378 void IdentityAccountTrackerTest::ReturnOAuthUrlFetchFailure( 379 const std::string& account_key) { 380 IssueAccessToken(account_key); 381 ReturnOAuthUrlFetchResults( 382 gaia::GaiaOAuthClient::kUrlFetcherId, net::HTTP_BAD_REQUEST, ""); 383 } 384 385 // Primary tests just involve the Active account 386 387 TEST_F(IdentityAccountTrackerTest, PrimaryNoEventsBeforeLogin) { 388 NotifyTokenAvailable(kPrimaryAccountKey); 389 NotifyTokenRevoked(kPrimaryAccountKey); 390 NotifyLogout(); 391 EXPECT_TRUE(observer()->CheckEvents()); 392 } 393 394 TEST_F(IdentityAccountTrackerTest, PrimaryLoginThenTokenAvailable) { 395 NotifyLogin(kPrimaryAccountKey); 396 NotifyTokenAvailable(kPrimaryAccountKey); 397 EXPECT_TRUE(observer()->CheckEvents()); 398 399 ReturnOAuthUrlFetchSuccess(kPrimaryAccountKey); 400 EXPECT_TRUE( 401 observer()->CheckEvents(TrackingEvent(ADDED, kPrimaryAccountKey), 402 TrackingEvent(SIGN_IN, kPrimaryAccountKey))); 403 } 404 405 TEST_F(IdentityAccountTrackerTest, PrimaryTokenAvailableThenLogin) { 406 NotifyTokenAvailable(kPrimaryAccountKey); 407 EXPECT_TRUE(observer()->CheckEvents()); 408 409 NotifyLogin(kPrimaryAccountKey); 410 ReturnOAuthUrlFetchSuccess(kPrimaryAccountKey); 411 EXPECT_TRUE( 412 observer()->CheckEvents(TrackingEvent(ADDED, kPrimaryAccountKey), 413 TrackingEvent(SIGN_IN, kPrimaryAccountKey))); 414 } 415 416 TEST_F(IdentityAccountTrackerTest, PrimaryTokenAvailableAndRevokedThenLogin) { 417 NotifyTokenAvailable(kPrimaryAccountKey); 418 EXPECT_TRUE(observer()->CheckEvents()); 419 420 NotifyLogin(kPrimaryAccountKey); 421 ReturnOAuthUrlFetchSuccess(kPrimaryAccountKey); 422 EXPECT_TRUE( 423 observer()->CheckEvents(TrackingEvent(ADDED, kPrimaryAccountKey), 424 TrackingEvent(SIGN_IN, kPrimaryAccountKey))); 425 } 426 427 TEST_F(IdentityAccountTrackerTest, PrimaryRevokeThenLogout) { 428 NotifyLogin(kPrimaryAccountKey); 429 NotifyTokenAvailable(kPrimaryAccountKey); 430 ReturnOAuthUrlFetchSuccess(kPrimaryAccountKey); 431 observer()->Clear(); 432 433 NotifyTokenRevoked(kPrimaryAccountKey); 434 EXPECT_TRUE( 435 observer()->CheckEvents(TrackingEvent(SIGN_OUT, kPrimaryAccountKey))); 436 437 NotifyLogout(); 438 EXPECT_TRUE( 439 observer()->CheckEvents(TrackingEvent(REMOVED, kPrimaryAccountKey))); 440 } 441 442 TEST_F(IdentityAccountTrackerTest, PrimaryRevokeThenLogin) { 443 NotifyLogin(kPrimaryAccountKey); 444 NotifyTokenAvailable(kPrimaryAccountKey); 445 ReturnOAuthUrlFetchSuccess(kPrimaryAccountKey); 446 NotifyTokenRevoked(kPrimaryAccountKey); 447 observer()->Clear(); 448 449 NotifyLogin(kPrimaryAccountKey); 450 EXPECT_TRUE(observer()->CheckEvents()); 451 } 452 453 TEST_F(IdentityAccountTrackerTest, PrimaryRevokeThenTokenAvailable) { 454 NotifyLogin(kPrimaryAccountKey); 455 NotifyTokenAvailable(kPrimaryAccountKey); 456 ReturnOAuthUrlFetchSuccess(kPrimaryAccountKey); 457 NotifyTokenRevoked(kPrimaryAccountKey); 458 observer()->Clear(); 459 460 NotifyTokenAvailable(kPrimaryAccountKey); 461 EXPECT_TRUE( 462 observer()->CheckEvents(TrackingEvent(SIGN_IN, kPrimaryAccountKey))); 463 } 464 465 TEST_F(IdentityAccountTrackerTest, PrimaryLogoutThenRevoke) { 466 NotifyLogin(kPrimaryAccountKey); 467 NotifyTokenAvailable(kPrimaryAccountKey); 468 ReturnOAuthUrlFetchSuccess(kPrimaryAccountKey); 469 observer()->Clear(); 470 471 NotifyLogout(); 472 EXPECT_TRUE( 473 observer()->CheckEvents(TrackingEvent(SIGN_OUT, kPrimaryAccountKey), 474 TrackingEvent(REMOVED, kPrimaryAccountKey))); 475 476 NotifyTokenRevoked(kPrimaryAccountKey); 477 EXPECT_TRUE(observer()->CheckEvents()); 478 } 479 480 TEST_F(IdentityAccountTrackerTest, PrimaryLogoutFetchCancelAvailable) { 481 NotifyLogin(kPrimaryAccountKey); 482 NotifyTokenAvailable(kPrimaryAccountKey); 483 // TokenAvailable kicks off a fetch. Logout without satisfying it. 484 NotifyLogout(); 485 EXPECT_TRUE(observer()->CheckEvents()); 486 487 NotifyLogin(kPrimaryAccountKey); 488 NotifyTokenAvailable(kPrimaryAccountKey); 489 ReturnOAuthUrlFetchSuccess(kPrimaryAccountKey); 490 EXPECT_TRUE(observer()->CheckEvents( 491 TrackingEvent(ADDED, kPrimaryAccountKey), 492 TrackingEvent(SIGN_IN, kPrimaryAccountKey))); 493 } 494 495 // Non-primary accounts 496 497 TEST_F(IdentityAccountTrackerTest, Available) { 498 SetupPrimaryLogin(); 499 500 NotifyTokenAvailable("user (at) example.com"); 501 EXPECT_TRUE(observer()->CheckEvents()); 502 503 ReturnOAuthUrlFetchSuccess("user (at) example.com"); 504 EXPECT_TRUE(observer()->CheckEvents( 505 TrackingEvent(ADDED, "user (at) example.com"), 506 TrackingEvent(SIGN_IN, "user (at) example.com"))); 507 } 508 509 TEST_F(IdentityAccountTrackerTest, Revoke) { 510 SetupPrimaryLogin(); 511 512 account_tracker()->OnRefreshTokenRevoked("user (at) example.com"); 513 EXPECT_TRUE(observer()->CheckEvents()); 514 } 515 516 TEST_F(IdentityAccountTrackerTest, AvailableRevokeAvailable) { 517 SetupPrimaryLogin(); 518 519 NotifyTokenAvailable("user (at) example.com"); 520 ReturnOAuthUrlFetchSuccess("user (at) example.com"); 521 NotifyTokenRevoked("user (at) example.com"); 522 EXPECT_TRUE(observer()->CheckEvents( 523 TrackingEvent(ADDED, "user (at) example.com"), 524 TrackingEvent(SIGN_IN, "user (at) example.com"), 525 TrackingEvent(SIGN_OUT, "user (at) example.com"))); 526 527 NotifyTokenAvailable("user (at) example.com"); 528 EXPECT_TRUE(observer()->CheckEvents( 529 TrackingEvent(SIGN_IN, "user (at) example.com"))); 530 } 531 532 TEST_F(IdentityAccountTrackerTest, AvailableRevokeAvailableWithPendingFetch) { 533 SetupPrimaryLogin(); 534 535 NotifyTokenAvailable("user (at) example.com"); 536 NotifyTokenRevoked("user (at) example.com"); 537 EXPECT_TRUE(observer()->CheckEvents()); 538 539 NotifyTokenAvailable("user (at) example.com"); 540 ReturnOAuthUrlFetchSuccess("user (at) example.com"); 541 EXPECT_TRUE(observer()->CheckEvents( 542 TrackingEvent(ADDED, "user (at) example.com"), 543 TrackingEvent(SIGN_IN, "user (at) example.com"))); 544 } 545 546 TEST_F(IdentityAccountTrackerTest, AvailableRevokeRevoke) { 547 SetupPrimaryLogin(); 548 549 NotifyTokenAvailable("user (at) example.com"); 550 ReturnOAuthUrlFetchSuccess("user (at) example.com"); 551 NotifyTokenRevoked("user (at) example.com"); 552 EXPECT_TRUE(observer()->CheckEvents( 553 TrackingEvent(ADDED, "user (at) example.com"), 554 TrackingEvent(SIGN_IN, "user (at) example.com"), 555 TrackingEvent(SIGN_OUT, "user (at) example.com"))); 556 557 NotifyTokenRevoked("user (at) example.com"); 558 EXPECT_TRUE(observer()->CheckEvents()); 559 } 560 561 TEST_F(IdentityAccountTrackerTest, AvailableAvailable) { 562 SetupPrimaryLogin(); 563 564 NotifyTokenAvailable("user (at) example.com"); 565 ReturnOAuthUrlFetchSuccess("user (at) example.com"); 566 EXPECT_TRUE(observer()->CheckEvents( 567 TrackingEvent(ADDED, "user (at) example.com"), 568 TrackingEvent(SIGN_IN, "user (at) example.com"))); 569 570 NotifyTokenAvailable("user (at) example.com"); 571 EXPECT_TRUE(observer()->CheckEvents()); 572 } 573 574 TEST_F(IdentityAccountTrackerTest, TwoAccounts) { 575 SetupPrimaryLogin(); 576 577 NotifyTokenAvailable("alpha (at) example.com"); 578 ReturnOAuthUrlFetchSuccess("alpha (at) example.com"); 579 EXPECT_TRUE(observer()->CheckEvents( 580 TrackingEvent(ADDED, "alpha (at) example.com"), 581 TrackingEvent(SIGN_IN, "alpha (at) example.com"))); 582 583 NotifyTokenAvailable("beta (at) example.com"); 584 ReturnOAuthUrlFetchSuccess("beta (at) example.com"); 585 EXPECT_TRUE(observer()->CheckEvents( 586 TrackingEvent(ADDED, "beta (at) example.com"), 587 TrackingEvent(SIGN_IN, "beta (at) example.com"))); 588 589 NotifyTokenRevoked("alpha (at) example.com"); 590 EXPECT_TRUE( 591 observer()->CheckEvents(TrackingEvent(SIGN_OUT, "alpha (at) example.com"))); 592 593 NotifyTokenRevoked("beta (at) example.com"); 594 EXPECT_TRUE(observer()->CheckEvents( 595 TrackingEvent(SIGN_OUT, "beta (at) example.com"))); 596 } 597 598 TEST_F(IdentityAccountTrackerTest, AvailableTokenFetchFailAvailable) { 599 SetupPrimaryLogin(); 600 601 NotifyTokenAvailable("user (at) example.com"); 602 ReturnOAuthUrlFetchFailure("user (at) example.com"); 603 EXPECT_TRUE(observer()->CheckEvents()); 604 605 NotifyTokenAvailable("user (at) example.com"); 606 ReturnOAuthUrlFetchSuccess("user (at) example.com"); 607 EXPECT_TRUE(observer()->CheckEvents( 608 TrackingEvent(ADDED, "user (at) example.com"), 609 TrackingEvent(SIGN_IN, "user (at) example.com"))); 610 } 611 612 TEST_F(IdentityAccountTrackerTest, MultiSignOutSignIn) { 613 SetupPrimaryLogin(); 614 615 NotifyTokenAvailable("alpha (at) example.com"); 616 ReturnOAuthUrlFetchSuccess("alpha (at) example.com"); 617 NotifyTokenAvailable("beta (at) example.com"); 618 ReturnOAuthUrlFetchSuccess("beta (at) example.com"); 619 620 observer()->SortEventsByUser(); 621 EXPECT_TRUE(observer()->CheckEvents( 622 TrackingEvent(ADDED, "alpha (at) example.com"), 623 TrackingEvent(SIGN_IN, "alpha (at) example.com"), 624 TrackingEvent(ADDED, "beta (at) example.com"), 625 TrackingEvent(SIGN_IN, "beta (at) example.com"))); 626 627 NotifyLogout(); 628 observer()->SortEventsByUser(); 629 EXPECT_TRUE(observer()->CheckEvents( 630 TrackingEvent(SIGN_OUT, "alpha (at) example.com"), 631 TrackingEvent(REMOVED, "alpha (at) example.com"), 632 TrackingEvent(SIGN_OUT, "beta (at) example.com"), 633 TrackingEvent(REMOVED, "beta (at) example.com"), 634 TrackingEvent(SIGN_OUT, kPrimaryAccountKey), 635 TrackingEvent(REMOVED, kPrimaryAccountKey))); 636 637 // No events fire at all while profile is signed out. 638 NotifyTokenRevoked("alpha (at) example.com"); 639 NotifyTokenAvailable("gamma (at) example.com"); 640 EXPECT_TRUE(observer()->CheckEvents()); 641 642 // Signing the profile in again will resume tracking all accounts. 643 NotifyLogin(kPrimaryAccountKey); 644 NotifyTokenAvailable(kPrimaryAccountKey); 645 ReturnOAuthUrlFetchSuccess("beta (at) example.com"); 646 ReturnOAuthUrlFetchSuccess("gamma (at) example.com"); 647 ReturnOAuthUrlFetchSuccess(kPrimaryAccountKey); 648 observer()->SortEventsByUser(); 649 EXPECT_TRUE(observer()->CheckEvents( 650 TrackingEvent(ADDED, "beta (at) example.com"), 651 TrackingEvent(SIGN_IN, "beta (at) example.com"), 652 TrackingEvent(ADDED, "gamma (at) example.com"), 653 TrackingEvent(SIGN_IN, "gamma (at) example.com"), 654 TrackingEvent(ADDED, kPrimaryAccountKey), 655 TrackingEvent(SIGN_IN, kPrimaryAccountKey))); 656 657 // Revoking the primary token does not affect other accounts. 658 NotifyTokenRevoked(kPrimaryAccountKey); 659 EXPECT_TRUE(observer()->CheckEvents( 660 TrackingEvent(SIGN_OUT, kPrimaryAccountKey))); 661 662 NotifyTokenAvailable(kPrimaryAccountKey); 663 EXPECT_TRUE(observer()->CheckEvents( 664 TrackingEvent(SIGN_IN, kPrimaryAccountKey))); 665 } 666 667 // Primary/non-primary interactions 668 669 TEST_F(IdentityAccountTrackerTest, MultiNoEventsBeforeLogin) { 670 NotifyTokenAvailable(kPrimaryAccountKey); 671 NotifyTokenAvailable("user (at) example.com"); 672 NotifyTokenRevoked("user (at) example.com"); 673 NotifyTokenRevoked(kPrimaryAccountKey); 674 NotifyLogout(); 675 EXPECT_TRUE(observer()->CheckEvents()); 676 } 677 678 TEST_F(IdentityAccountTrackerTest, MultiLogoutRemovesAllAccounts) { 679 NotifyLogin(kPrimaryAccountKey); 680 NotifyTokenAvailable(kPrimaryAccountKey); 681 ReturnOAuthUrlFetchSuccess(kPrimaryAccountKey); 682 NotifyTokenAvailable("user (at) example.com"); 683 ReturnOAuthUrlFetchSuccess("user (at) example.com"); 684 observer()->Clear(); 685 686 NotifyLogout(); 687 observer()->SortEventsByUser(); 688 EXPECT_TRUE( 689 observer()->CheckEvents(TrackingEvent(SIGN_OUT, kPrimaryAccountKey), 690 TrackingEvent(REMOVED, kPrimaryAccountKey), 691 TrackingEvent(SIGN_OUT, "user (at) example.com"), 692 TrackingEvent(REMOVED, "user (at) example.com"))); 693 } 694 695 TEST_F(IdentityAccountTrackerTest, MultiRevokePrimaryDoesNotRemoveAllAccounts) { 696 NotifyLogin(kPrimaryAccountKey); 697 NotifyTokenAvailable(kPrimaryAccountKey); 698 ReturnOAuthUrlFetchSuccess(kPrimaryAccountKey); 699 NotifyTokenAvailable("user (at) example.com"); 700 ReturnOAuthUrlFetchSuccess("user (at) example.com"); 701 observer()->Clear(); 702 703 NotifyTokenRevoked(kPrimaryAccountKey); 704 observer()->SortEventsByUser(); 705 EXPECT_TRUE( 706 observer()->CheckEvents(TrackingEvent(SIGN_OUT, kPrimaryAccountKey))); 707 } 708 709 TEST_F(IdentityAccountTrackerTest, GetAccountsPrimary) { 710 SetupPrimaryLogin(); 711 712 std::vector<AccountIds> ids = account_tracker()->GetAccounts(); 713 EXPECT_EQ(1ul, ids.size()); 714 EXPECT_EQ(kPrimaryAccountKey, ids[0].account_key); 715 EXPECT_EQ(AccountKeyToObfuscatedId(kPrimaryAccountKey), ids[0].gaia); 716 } 717 718 TEST_F(IdentityAccountTrackerTest, GetAccountsSignedOut) { 719 std::vector<AccountIds> ids = account_tracker()->GetAccounts(); 720 EXPECT_EQ(0ul, ids.size()); 721 } 722 723 TEST_F(IdentityAccountTrackerTest, GetAccountsOnlyReturnAccountsWithTokens) { 724 SetupPrimaryLogin(); 725 726 NotifyTokenAvailable("alpha (at) example.com"); 727 NotifyTokenAvailable("beta (at) example.com"); 728 ReturnOAuthUrlFetchSuccess("beta (at) example.com"); 729 730 std::vector<AccountIds> ids = account_tracker()->GetAccounts(); 731 EXPECT_EQ(2ul, ids.size()); 732 EXPECT_EQ(kPrimaryAccountKey, ids[0].account_key); 733 EXPECT_EQ(AccountKeyToObfuscatedId(kPrimaryAccountKey), ids[0].gaia); 734 EXPECT_EQ("beta (at) example.com", ids[1].account_key); 735 EXPECT_EQ(AccountKeyToObfuscatedId("beta (at) example.com"), ids[1].gaia); 736 } 737 738 TEST_F(IdentityAccountTrackerTest, GetAccountsSortOrder) { 739 SetupPrimaryLogin(); 740 741 NotifyTokenAvailable("zeta (at) example.com"); 742 ReturnOAuthUrlFetchSuccess("zeta (at) example.com"); 743 NotifyTokenAvailable("alpha (at) example.com"); 744 ReturnOAuthUrlFetchSuccess("alpha (at) example.com"); 745 746 // The primary account will be first in the vector. Remaining accounts 747 // will be sorted by gaia ID. 748 std::vector<AccountIds> ids = account_tracker()->GetAccounts(); 749 EXPECT_EQ(3ul, ids.size()); 750 EXPECT_EQ(kPrimaryAccountKey, ids[0].account_key); 751 EXPECT_EQ(AccountKeyToObfuscatedId(kPrimaryAccountKey), ids[0].gaia); 752 EXPECT_EQ("alpha (at) example.com", ids[1].account_key); 753 EXPECT_EQ(AccountKeyToObfuscatedId("alpha (at) example.com"), ids[1].gaia); 754 EXPECT_EQ("zeta (at) example.com", ids[2].account_key); 755 EXPECT_EQ(AccountKeyToObfuscatedId("zeta (at) example.com"), ids[2].gaia); 756 } 757 758 TEST_F(IdentityAccountTrackerTest, 759 GetAccountsReturnNothingWhenPrimarySignedOut) { 760 SetupPrimaryLogin(); 761 762 NotifyTokenAvailable("zeta (at) example.com"); 763 ReturnOAuthUrlFetchSuccess("zeta (at) example.com"); 764 NotifyTokenAvailable("alpha (at) example.com"); 765 ReturnOAuthUrlFetchSuccess("alpha (at) example.com"); 766 767 NotifyTokenRevoked(kPrimaryAccountKey); 768 769 std::vector<AccountIds> ids = account_tracker()->GetAccounts(); 770 EXPECT_EQ(0ul, ids.size()); 771 } 772 773 TEST_F(IdentityAccountTrackerTest, FindAccountIdsByGaiaIdPrimary) { 774 SetupPrimaryLogin(); 775 776 AccountIds ids = account_tracker()->FindAccountIdsByGaiaId( 777 AccountKeyToObfuscatedId(kPrimaryAccountKey)); 778 EXPECT_EQ(kPrimaryAccountKey, ids.account_key); 779 EXPECT_EQ(kPrimaryAccountKey, ids.email); 780 EXPECT_EQ(AccountKeyToObfuscatedId(kPrimaryAccountKey), ids.gaia); 781 } 782 783 TEST_F(IdentityAccountTrackerTest, FindAccountIdsByGaiaIdNotFound) { 784 SetupPrimaryLogin(); 785 786 AccountIds ids = account_tracker()->FindAccountIdsByGaiaId( 787 AccountKeyToObfuscatedId("notfound (at) example.com")); 788 EXPECT_TRUE(ids.account_key.empty()); 789 EXPECT_TRUE(ids.email.empty()); 790 EXPECT_TRUE(ids.gaia.empty()); 791 } 792 793 TEST_F(IdentityAccountTrackerTest, 794 FindAccountIdsByGaiaIdReturnEmptyWhenPrimarySignedOut) { 795 SetupPrimaryLogin(); 796 797 NotifyTokenAvailable("zeta (at) example.com"); 798 ReturnOAuthUrlFetchSuccess("zeta (at) example.com"); 799 NotifyTokenAvailable("alpha (at) example.com"); 800 ReturnOAuthUrlFetchSuccess("alpha (at) example.com"); 801 802 NotifyTokenRevoked(kPrimaryAccountKey); 803 804 AccountIds ids = 805 account_tracker()->FindAccountIdsByGaiaId(kPrimaryAccountKey); 806 EXPECT_TRUE(ids.account_key.empty()); 807 EXPECT_TRUE(ids.email.empty()); 808 EXPECT_TRUE(ids.gaia.empty()); 809 810 ids = account_tracker()->FindAccountIdsByGaiaId("alpha (at) example.com"); 811 EXPECT_TRUE(ids.account_key.empty()); 812 EXPECT_TRUE(ids.email.empty()); 813 EXPECT_TRUE(ids.gaia.empty()); 814 } 815 816 } // namespace gaia 817