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
21namespace {
22
23const char kPrimaryAccountKey[] = "primary_account@example.com";
24
25enum TrackingEventType {
26  ADDED,
27  REMOVED,
28  SIGN_IN,
29  SIGN_OUT
30};
31
32std::string AccountKeyToObfuscatedId(const std::string email) {
33  return "obfid-" + email;
34}
35
36class 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
86bool CompareByUser(TrackingEvent a, TrackingEvent b) {
87  return a.account_key_ < b.account_key_;
88}
89
90std::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
106namespace gaia {
107
108class 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
151void AccountTrackerObserver::OnAccountAdded(const AccountIds& ids) {
152  events_.push_back(TrackingEvent(ADDED, ids.email, ids.gaia));
153}
154
155void AccountTrackerObserver::OnAccountRemoved(const AccountIds& ids) {
156  events_.push_back(TrackingEvent(REMOVED, ids.email, ids.gaia));
157}
158
159void 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
165void AccountTrackerObserver::Clear() {
166  events_.clear();
167}
168
169void AccountTrackerObserver::SortEventsByUser() {
170  std::stable_sort(events_.begin(), events_.end(), CompareByUser);
171}
172
173testing::AssertionResult AccountTrackerObserver::CheckEvents() {
174  std::vector<TrackingEvent> events;
175  return CheckEvents(events);
176}
177
178testing::AssertionResult AccountTrackerObserver::CheckEvents(
179    const TrackingEvent& e1) {
180  std::vector<TrackingEvent> events;
181  events.push_back(e1);
182  return CheckEvents(events);
183}
184
185testing::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
194testing::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
205testing::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
218testing::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
233testing::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
250testing::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
263class 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
357void 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
370void 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
378void 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
387TEST_F(IdentityAccountTrackerTest, PrimaryNoEventsBeforeLogin) {
388  NotifyTokenAvailable(kPrimaryAccountKey);
389  NotifyTokenRevoked(kPrimaryAccountKey);
390  NotifyLogout();
391  EXPECT_TRUE(observer()->CheckEvents());
392}
393
394TEST_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
405TEST_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
416TEST_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
427TEST_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
442TEST_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
453TEST_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
465TEST_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
480TEST_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
497TEST_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
509TEST_F(IdentityAccountTrackerTest, Revoke) {
510  SetupPrimaryLogin();
511
512  account_tracker()->OnRefreshTokenRevoked("user@example.com");
513  EXPECT_TRUE(observer()->CheckEvents());
514}
515
516TEST_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
532TEST_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
546TEST_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
561TEST_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
574TEST_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
598TEST_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
612TEST_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
669TEST_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
678TEST_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
695TEST_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
709TEST_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
718TEST_F(IdentityAccountTrackerTest, GetAccountsSignedOut) {
719  std::vector<AccountIds> ids = account_tracker()->GetAccounts();
720  EXPECT_EQ(0ul, ids.size());
721}
722
723TEST_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
738TEST_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
758TEST_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
773TEST_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
783TEST_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
793TEST_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