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@example.com";
24
25 enum TrackingEventType {
26 ADDED,
27 REMOVED,
28 SIGN_IN,
29 SIGN_OUT
30 };
31
AccountKeyToObfuscatedId(const std::string email)32 std::string AccountKeyToObfuscatedId(const std::string email) {
33 return "obfid-" + email;
34 }
35
36 class TrackingEvent {
37 public:
TrackingEvent(TrackingEventType type,const std::string & account_key,const std::string & gaia_id)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
TrackingEvent(TrackingEventType type,const std::string & account_key)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
operator ==(const TrackingEvent & event) const51 bool operator==(const TrackingEvent& event) const {
52 return type_ == event.type_ && account_key_ == event.account_key_ &&
53 gaia_id_ == event.gaia_id_;
54 }
55
ToString() const56 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
CompareByUser(TrackingEvent a,TrackingEvent b)86 bool CompareByUser(TrackingEvent a, TrackingEvent b) {
87 return a.account_key_ < b.account_key_;
88 }
89
Str(const std::vector<TrackingEvent> & events)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:
AccountTrackerObserver()110 AccountTrackerObserver() {}
~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
OnAccountAdded(const AccountIds & ids)151 void AccountTrackerObserver::OnAccountAdded(const AccountIds& ids) {
152 events_.push_back(TrackingEvent(ADDED, ids.email, ids.gaia));
153 }
154
OnAccountRemoved(const AccountIds & ids)155 void AccountTrackerObserver::OnAccountRemoved(const AccountIds& ids) {
156 events_.push_back(TrackingEvent(REMOVED, ids.email, ids.gaia));
157 }
158
OnAccountSignInChanged(const AccountIds & ids,bool is_signed_in)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
Clear()165 void AccountTrackerObserver::Clear() {
166 events_.clear();
167 }
168
SortEventsByUser()169 void AccountTrackerObserver::SortEventsByUser() {
170 std::stable_sort(events_.begin(), events_.end(), CompareByUser);
171 }
172
CheckEvents()173 testing::AssertionResult AccountTrackerObserver::CheckEvents() {
174 std::vector<TrackingEvent> events;
175 return CheckEvents(events);
176 }
177
CheckEvents(const TrackingEvent & e1)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
CheckEvents(const TrackingEvent & e1,const TrackingEvent & e2)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
CheckEvents(const TrackingEvent & e1,const TrackingEvent & e2,const TrackingEvent & e3)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
CheckEvents(const TrackingEvent & e1,const TrackingEvent & e2,const TrackingEvent & e3,const TrackingEvent & e4)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
CheckEvents(const TrackingEvent & e1,const TrackingEvent & e2,const TrackingEvent & e3,const TrackingEvent & e4,const TrackingEvent & e5)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
CheckEvents(const TrackingEvent & e1,const TrackingEvent & e2,const TrackingEvent & e3,const TrackingEvent & e4,const TrackingEvent & e5,const TrackingEvent & e6)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
CheckEvents(const std::vector<TrackingEvent> & events)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:
IdentityAccountTrackerTest()265 IdentityAccountTrackerTest() {}
266
~IdentityAccountTrackerTest()267 virtual ~IdentityAccountTrackerTest() {}
268
SetUp()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
TearDown()283 virtual void TearDown() OVERRIDE {
284 account_tracker_->RemoveObserver(&observer_);
285 account_tracker_->Shutdown();
286 }
287
observer()288 AccountTrackerObserver* observer() {
289 return &observer_;
290 }
291
account_tracker()292 AccountTracker* account_tracker() {
293 return account_tracker_.get();
294 }
295
296 // Helpers to pass fake events to the tracker.
297
NotifyLogin(const std::string account_key)298 void NotifyLogin(const std::string account_key) {
299 identity_provider()->LogIn(account_key);
300 }
301
NotifyLogout()302 void NotifyLogout() { identity_provider()->LogOut(); }
303
NotifyTokenAvailable(const std::string & username)304 void NotifyTokenAvailable(const std::string& username) {
305 fake_oauth2_token_service_->AddAccount(username);
306 }
307
NotifyTokenRevoked(const std::string & username)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
IssueAccessToken(const std::string & username)313 void IssueAccessToken(const std::string& username) {
314 fake_oauth2_token_service_->IssueAllTokensForAccount(
315 username, "access_token-" + username, base::Time::Max());
316 }
317
GetValidTokenInfoResponse(const std::string account_key)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
SetupPrimaryLogin()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
active_account_id()338 std::string active_account_id() {
339 return identity_provider()->GetActiveAccountId();
340 }
341
342 private:
identity_provider()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
ReturnOAuthUrlFetchResults(int fetcher_id,net::HttpStatusCode response_code,const std::string & response_string)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
ReturnOAuthUrlFetchSuccess(const std::string & account_key)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
ReturnOAuthUrlFetchFailure(const std::string & account_key)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
TEST_F(IdentityAccountTrackerTest,PrimaryNoEventsBeforeLogin)387 TEST_F(IdentityAccountTrackerTest, PrimaryNoEventsBeforeLogin) {
388 NotifyTokenAvailable(kPrimaryAccountKey);
389 NotifyTokenRevoked(kPrimaryAccountKey);
390 NotifyLogout();
391 EXPECT_TRUE(observer()->CheckEvents());
392 }
393
TEST_F(IdentityAccountTrackerTest,PrimaryLoginThenTokenAvailable)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
TEST_F(IdentityAccountTrackerTest,PrimaryTokenAvailableThenLogin)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
TEST_F(IdentityAccountTrackerTest,PrimaryTokenAvailableAndRevokedThenLogin)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
TEST_F(IdentityAccountTrackerTest,PrimaryRevokeThenLogout)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
TEST_F(IdentityAccountTrackerTest,PrimaryRevokeThenLogin)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
TEST_F(IdentityAccountTrackerTest,PrimaryRevokeThenTokenAvailable)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
TEST_F(IdentityAccountTrackerTest,PrimaryLogoutThenRevoke)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
TEST_F(IdentityAccountTrackerTest,PrimaryLogoutFetchCancelAvailable)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
TEST_F(IdentityAccountTrackerTest,Available)497 TEST_F(IdentityAccountTrackerTest, Available) {
498 SetupPrimaryLogin();
499
500 NotifyTokenAvailable("user@example.com");
501 EXPECT_TRUE(observer()->CheckEvents());
502
503 ReturnOAuthUrlFetchSuccess("user@example.com");
504 EXPECT_TRUE(observer()->CheckEvents(
505 TrackingEvent(ADDED, "user@example.com"),
506 TrackingEvent(SIGN_IN, "user@example.com")));
507 }
508
TEST_F(IdentityAccountTrackerTest,Revoke)509 TEST_F(IdentityAccountTrackerTest, Revoke) {
510 SetupPrimaryLogin();
511
512 account_tracker()->OnRefreshTokenRevoked("user@example.com");
513 EXPECT_TRUE(observer()->CheckEvents());
514 }
515
TEST_F(IdentityAccountTrackerTest,AvailableRevokeAvailable)516 TEST_F(IdentityAccountTrackerTest, AvailableRevokeAvailable) {
517 SetupPrimaryLogin();
518
519 NotifyTokenAvailable("user@example.com");
520 ReturnOAuthUrlFetchSuccess("user@example.com");
521 NotifyTokenRevoked("user@example.com");
522 EXPECT_TRUE(observer()->CheckEvents(
523 TrackingEvent(ADDED, "user@example.com"),
524 TrackingEvent(SIGN_IN, "user@example.com"),
525 TrackingEvent(SIGN_OUT, "user@example.com")));
526
527 NotifyTokenAvailable("user@example.com");
528 EXPECT_TRUE(observer()->CheckEvents(
529 TrackingEvent(SIGN_IN, "user@example.com")));
530 }
531
TEST_F(IdentityAccountTrackerTest,AvailableRevokeAvailableWithPendingFetch)532 TEST_F(IdentityAccountTrackerTest, AvailableRevokeAvailableWithPendingFetch) {
533 SetupPrimaryLogin();
534
535 NotifyTokenAvailable("user@example.com");
536 NotifyTokenRevoked("user@example.com");
537 EXPECT_TRUE(observer()->CheckEvents());
538
539 NotifyTokenAvailable("user@example.com");
540 ReturnOAuthUrlFetchSuccess("user@example.com");
541 EXPECT_TRUE(observer()->CheckEvents(
542 TrackingEvent(ADDED, "user@example.com"),
543 TrackingEvent(SIGN_IN, "user@example.com")));
544 }
545
TEST_F(IdentityAccountTrackerTest,AvailableRevokeRevoke)546 TEST_F(IdentityAccountTrackerTest, AvailableRevokeRevoke) {
547 SetupPrimaryLogin();
548
549 NotifyTokenAvailable("user@example.com");
550 ReturnOAuthUrlFetchSuccess("user@example.com");
551 NotifyTokenRevoked("user@example.com");
552 EXPECT_TRUE(observer()->CheckEvents(
553 TrackingEvent(ADDED, "user@example.com"),
554 TrackingEvent(SIGN_IN, "user@example.com"),
555 TrackingEvent(SIGN_OUT, "user@example.com")));
556
557 NotifyTokenRevoked("user@example.com");
558 EXPECT_TRUE(observer()->CheckEvents());
559 }
560
TEST_F(IdentityAccountTrackerTest,AvailableAvailable)561 TEST_F(IdentityAccountTrackerTest, AvailableAvailable) {
562 SetupPrimaryLogin();
563
564 NotifyTokenAvailable("user@example.com");
565 ReturnOAuthUrlFetchSuccess("user@example.com");
566 EXPECT_TRUE(observer()->CheckEvents(
567 TrackingEvent(ADDED, "user@example.com"),
568 TrackingEvent(SIGN_IN, "user@example.com")));
569
570 NotifyTokenAvailable("user@example.com");
571 EXPECT_TRUE(observer()->CheckEvents());
572 }
573
TEST_F(IdentityAccountTrackerTest,TwoAccounts)574 TEST_F(IdentityAccountTrackerTest, TwoAccounts) {
575 SetupPrimaryLogin();
576
577 NotifyTokenAvailable("alpha@example.com");
578 ReturnOAuthUrlFetchSuccess("alpha@example.com");
579 EXPECT_TRUE(observer()->CheckEvents(
580 TrackingEvent(ADDED, "alpha@example.com"),
581 TrackingEvent(SIGN_IN, "alpha@example.com")));
582
583 NotifyTokenAvailable("beta@example.com");
584 ReturnOAuthUrlFetchSuccess("beta@example.com");
585 EXPECT_TRUE(observer()->CheckEvents(
586 TrackingEvent(ADDED, "beta@example.com"),
587 TrackingEvent(SIGN_IN, "beta@example.com")));
588
589 NotifyTokenRevoked("alpha@example.com");
590 EXPECT_TRUE(
591 observer()->CheckEvents(TrackingEvent(SIGN_OUT, "alpha@example.com")));
592
593 NotifyTokenRevoked("beta@example.com");
594 EXPECT_TRUE(observer()->CheckEvents(
595 TrackingEvent(SIGN_OUT, "beta@example.com")));
596 }
597
TEST_F(IdentityAccountTrackerTest,AvailableTokenFetchFailAvailable)598 TEST_F(IdentityAccountTrackerTest, AvailableTokenFetchFailAvailable) {
599 SetupPrimaryLogin();
600
601 NotifyTokenAvailable("user@example.com");
602 ReturnOAuthUrlFetchFailure("user@example.com");
603 EXPECT_TRUE(observer()->CheckEvents());
604
605 NotifyTokenAvailable("user@example.com");
606 ReturnOAuthUrlFetchSuccess("user@example.com");
607 EXPECT_TRUE(observer()->CheckEvents(
608 TrackingEvent(ADDED, "user@example.com"),
609 TrackingEvent(SIGN_IN, "user@example.com")));
610 }
611
TEST_F(IdentityAccountTrackerTest,MultiSignOutSignIn)612 TEST_F(IdentityAccountTrackerTest, MultiSignOutSignIn) {
613 SetupPrimaryLogin();
614
615 NotifyTokenAvailable("alpha@example.com");
616 ReturnOAuthUrlFetchSuccess("alpha@example.com");
617 NotifyTokenAvailable("beta@example.com");
618 ReturnOAuthUrlFetchSuccess("beta@example.com");
619
620 observer()->SortEventsByUser();
621 EXPECT_TRUE(observer()->CheckEvents(
622 TrackingEvent(ADDED, "alpha@example.com"),
623 TrackingEvent(SIGN_IN, "alpha@example.com"),
624 TrackingEvent(ADDED, "beta@example.com"),
625 TrackingEvent(SIGN_IN, "beta@example.com")));
626
627 NotifyLogout();
628 observer()->SortEventsByUser();
629 EXPECT_TRUE(observer()->CheckEvents(
630 TrackingEvent(SIGN_OUT, "alpha@example.com"),
631 TrackingEvent(REMOVED, "alpha@example.com"),
632 TrackingEvent(SIGN_OUT, "beta@example.com"),
633 TrackingEvent(REMOVED, "beta@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@example.com");
639 NotifyTokenAvailable("gamma@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@example.com");
646 ReturnOAuthUrlFetchSuccess("gamma@example.com");
647 ReturnOAuthUrlFetchSuccess(kPrimaryAccountKey);
648 observer()->SortEventsByUser();
649 EXPECT_TRUE(observer()->CheckEvents(
650 TrackingEvent(ADDED, "beta@example.com"),
651 TrackingEvent(SIGN_IN, "beta@example.com"),
652 TrackingEvent(ADDED, "gamma@example.com"),
653 TrackingEvent(SIGN_IN, "gamma@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
TEST_F(IdentityAccountTrackerTest,MultiNoEventsBeforeLogin)669 TEST_F(IdentityAccountTrackerTest, MultiNoEventsBeforeLogin) {
670 NotifyTokenAvailable(kPrimaryAccountKey);
671 NotifyTokenAvailable("user@example.com");
672 NotifyTokenRevoked("user@example.com");
673 NotifyTokenRevoked(kPrimaryAccountKey);
674 NotifyLogout();
675 EXPECT_TRUE(observer()->CheckEvents());
676 }
677
TEST_F(IdentityAccountTrackerTest,MultiLogoutRemovesAllAccounts)678 TEST_F(IdentityAccountTrackerTest, MultiLogoutRemovesAllAccounts) {
679 NotifyLogin(kPrimaryAccountKey);
680 NotifyTokenAvailable(kPrimaryAccountKey);
681 ReturnOAuthUrlFetchSuccess(kPrimaryAccountKey);
682 NotifyTokenAvailable("user@example.com");
683 ReturnOAuthUrlFetchSuccess("user@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@example.com"),
692 TrackingEvent(REMOVED, "user@example.com")));
693 }
694
TEST_F(IdentityAccountTrackerTest,MultiRevokePrimaryDoesNotRemoveAllAccounts)695 TEST_F(IdentityAccountTrackerTest, MultiRevokePrimaryDoesNotRemoveAllAccounts) {
696 NotifyLogin(kPrimaryAccountKey);
697 NotifyTokenAvailable(kPrimaryAccountKey);
698 ReturnOAuthUrlFetchSuccess(kPrimaryAccountKey);
699 NotifyTokenAvailable("user@example.com");
700 ReturnOAuthUrlFetchSuccess("user@example.com");
701 observer()->Clear();
702
703 NotifyTokenRevoked(kPrimaryAccountKey);
704 observer()->SortEventsByUser();
705 EXPECT_TRUE(
706 observer()->CheckEvents(TrackingEvent(SIGN_OUT, kPrimaryAccountKey)));
707 }
708
TEST_F(IdentityAccountTrackerTest,GetAccountsPrimary)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
TEST_F(IdentityAccountTrackerTest,GetAccountsSignedOut)718 TEST_F(IdentityAccountTrackerTest, GetAccountsSignedOut) {
719 std::vector<AccountIds> ids = account_tracker()->GetAccounts();
720 EXPECT_EQ(0ul, ids.size());
721 }
722
TEST_F(IdentityAccountTrackerTest,GetAccountsOnlyReturnAccountsWithTokens)723 TEST_F(IdentityAccountTrackerTest, GetAccountsOnlyReturnAccountsWithTokens) {
724 SetupPrimaryLogin();
725
726 NotifyTokenAvailable("alpha@example.com");
727 NotifyTokenAvailable("beta@example.com");
728 ReturnOAuthUrlFetchSuccess("beta@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@example.com", ids[1].account_key);
735 EXPECT_EQ(AccountKeyToObfuscatedId("beta@example.com"), ids[1].gaia);
736 }
737
TEST_F(IdentityAccountTrackerTest,GetAccountsSortOrder)738 TEST_F(IdentityAccountTrackerTest, GetAccountsSortOrder) {
739 SetupPrimaryLogin();
740
741 NotifyTokenAvailable("zeta@example.com");
742 ReturnOAuthUrlFetchSuccess("zeta@example.com");
743 NotifyTokenAvailable("alpha@example.com");
744 ReturnOAuthUrlFetchSuccess("alpha@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@example.com", ids[1].account_key);
753 EXPECT_EQ(AccountKeyToObfuscatedId("alpha@example.com"), ids[1].gaia);
754 EXPECT_EQ("zeta@example.com", ids[2].account_key);
755 EXPECT_EQ(AccountKeyToObfuscatedId("zeta@example.com"), ids[2].gaia);
756 }
757
TEST_F(IdentityAccountTrackerTest,GetAccountsReturnNothingWhenPrimarySignedOut)758 TEST_F(IdentityAccountTrackerTest,
759 GetAccountsReturnNothingWhenPrimarySignedOut) {
760 SetupPrimaryLogin();
761
762 NotifyTokenAvailable("zeta@example.com");
763 ReturnOAuthUrlFetchSuccess("zeta@example.com");
764 NotifyTokenAvailable("alpha@example.com");
765 ReturnOAuthUrlFetchSuccess("alpha@example.com");
766
767 NotifyTokenRevoked(kPrimaryAccountKey);
768
769 std::vector<AccountIds> ids = account_tracker()->GetAccounts();
770 EXPECT_EQ(0ul, ids.size());
771 }
772
TEST_F(IdentityAccountTrackerTest,FindAccountIdsByGaiaIdPrimary)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
TEST_F(IdentityAccountTrackerTest,FindAccountIdsByGaiaIdNotFound)783 TEST_F(IdentityAccountTrackerTest, FindAccountIdsByGaiaIdNotFound) {
784 SetupPrimaryLogin();
785
786 AccountIds ids = account_tracker()->FindAccountIdsByGaiaId(
787 AccountKeyToObfuscatedId("notfound@example.com"));
788 EXPECT_TRUE(ids.account_key.empty());
789 EXPECT_TRUE(ids.email.empty());
790 EXPECT_TRUE(ids.gaia.empty());
791 }
792
TEST_F(IdentityAccountTrackerTest,FindAccountIdsByGaiaIdReturnEmptyWhenPrimarySignedOut)793 TEST_F(IdentityAccountTrackerTest,
794 FindAccountIdsByGaiaIdReturnEmptyWhenPrimarySignedOut) {
795 SetupPrimaryLogin();
796
797 NotifyTokenAvailable("zeta@example.com");
798 ReturnOAuthUrlFetchSuccess("zeta@example.com");
799 NotifyTokenAvailable("alpha@example.com");
800 ReturnOAuthUrlFetchSuccess("alpha@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@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