OLD | NEW |
| (Empty) |
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 <algorithm> | |
6 #include <vector> | |
7 | |
8 #include "base/message_loop/message_loop.h" | |
9 #include "base/prefs/pref_registry_simple.h" | |
10 #include "base/prefs/testing_pref_service.h" | |
11 #include "base/strings/stringprintf.h" | |
12 #include "components/signin/core/browser/account_tracker_service.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 enum TrackingEventType { | |
24 UPDATED, | |
25 REMOVED, | |
26 }; | |
27 | |
28 std::string AccountIdToEmail(const std::string account_id) { | |
29 return account_id + "@gmail.com"; | |
30 } | |
31 | |
32 std::string AccountIdToGaiaId(const std::string account_id) { | |
33 return "gaia-" + account_id; | |
34 } | |
35 | |
36 class TrackingEvent { | |
37 public: | |
38 TrackingEvent(TrackingEventType type, | |
39 const std::string& account_id, | |
40 const std::string& gaia_id) | |
41 : type_(type), | |
42 account_id_(account_id), | |
43 gaia_id_(gaia_id) {} | |
44 | |
45 TrackingEvent(TrackingEventType type, | |
46 const std::string& account_id) | |
47 : type_(type), | |
48 account_id_(account_id), | |
49 gaia_id_(AccountIdToGaiaId(account_id)) {} | |
50 | |
51 bool operator==(const TrackingEvent& event) const { | |
52 return type_ == event.type_ && account_id_ == event.account_id_ && | |
53 gaia_id_ == event.gaia_id_; | |
54 } | |
55 | |
56 std::string ToString() const { | |
57 const char * typestr = "INVALID"; | |
58 switch (type_) { | |
59 case UPDATED: | |
60 typestr = "UPD"; | |
61 break; | |
62 case REMOVED: | |
63 typestr = "REM"; | |
64 break; | |
65 } | |
66 return base::StringPrintf("{ type: %s, account_id: %s, gaia: %s }", | |
67 typestr, | |
68 account_id_.c_str(), | |
69 gaia_id_.c_str()); | |
70 } | |
71 | |
72 private: | |
73 friend bool CompareByUser(TrackingEvent a, TrackingEvent b); | |
74 | |
75 TrackingEventType type_; | |
76 std::string account_id_; | |
77 std::string gaia_id_; | |
78 }; | |
79 | |
80 bool CompareByUser(TrackingEvent a, TrackingEvent b) { | |
81 return a.account_id_ < b.account_id_; | |
82 } | |
83 | |
84 std::string Str(const std::vector<TrackingEvent>& events) { | |
85 std::string str = "["; | |
86 bool needs_comma = false; | |
87 for (std::vector<TrackingEvent>::const_iterator it = | |
88 events.begin(); it != events.end(); ++it) { | |
89 if (needs_comma) | |
90 str += ",\n "; | |
91 needs_comma = true; | |
92 str += it->ToString(); | |
93 } | |
94 str += "]"; | |
95 return str; | |
96 } | |
97 | |
98 class AccountTrackerObserver : public AccountTrackerService::Observer { | |
99 public: | |
100 AccountTrackerObserver() {} | |
101 virtual ~AccountTrackerObserver() {} | |
102 | |
103 void Clear(); | |
104 void SortEventsByUser(); | |
105 | |
106 testing::AssertionResult CheckEvents(); | |
107 testing::AssertionResult CheckEvents(const TrackingEvent& e1); | |
108 testing::AssertionResult CheckEvents(const TrackingEvent& e1, | |
109 const TrackingEvent& e2); | |
110 testing::AssertionResult CheckEvents(const TrackingEvent& e1, | |
111 const TrackingEvent& e2, | |
112 const TrackingEvent& e3); | |
113 | |
114 private: | |
115 // AccountTrackerService::Observer implementation | |
116 virtual void OnAccountUpdated( | |
117 const AccountTrackerService::AccountInfo& ids) OVERRIDE; | |
118 virtual void OnAccountRemoved( | |
119 const AccountTrackerService::AccountInfo& ids) OVERRIDE; | |
120 | |
121 testing::AssertionResult CheckEvents( | |
122 const std::vector<TrackingEvent>& events); | |
123 | |
124 std::vector<TrackingEvent> events_; | |
125 }; | |
126 | |
127 void AccountTrackerObserver::OnAccountUpdated( | |
128 const AccountTrackerService::AccountInfo& ids) { | |
129 events_.push_back(TrackingEvent(UPDATED, ids.account_id, ids.gaia)); | |
130 } | |
131 | |
132 void AccountTrackerObserver::OnAccountRemoved( | |
133 const AccountTrackerService::AccountInfo& ids) { | |
134 events_.push_back(TrackingEvent(REMOVED, ids.account_id, ids.gaia)); | |
135 } | |
136 | |
137 void AccountTrackerObserver::Clear() { | |
138 events_.clear(); | |
139 } | |
140 | |
141 void AccountTrackerObserver::SortEventsByUser() { | |
142 std::stable_sort(events_.begin(), events_.end(), CompareByUser); | |
143 } | |
144 | |
145 testing::AssertionResult AccountTrackerObserver::CheckEvents() { | |
146 std::vector<TrackingEvent> events; | |
147 return CheckEvents(events); | |
148 } | |
149 | |
150 testing::AssertionResult AccountTrackerObserver::CheckEvents( | |
151 const TrackingEvent& e1) { | |
152 std::vector<TrackingEvent> events; | |
153 events.push_back(e1); | |
154 return CheckEvents(events); | |
155 } | |
156 | |
157 testing::AssertionResult AccountTrackerObserver::CheckEvents( | |
158 const TrackingEvent& e1, | |
159 const TrackingEvent& e2) { | |
160 std::vector<TrackingEvent> events; | |
161 events.push_back(e1); | |
162 events.push_back(e2); | |
163 return CheckEvents(events); | |
164 } | |
165 | |
166 testing::AssertionResult AccountTrackerObserver::CheckEvents( | |
167 const TrackingEvent& e1, | |
168 const TrackingEvent& e2, | |
169 const TrackingEvent& e3) { | |
170 std::vector<TrackingEvent> events; | |
171 events.push_back(e1); | |
172 events.push_back(e2); | |
173 events.push_back(e3); | |
174 return CheckEvents(events); | |
175 } | |
176 | |
177 testing::AssertionResult AccountTrackerObserver::CheckEvents( | |
178 const std::vector<TrackingEvent>& events) { | |
179 std::string maybe_newline = (events.size() + events_.size()) > 2 ? "\n" : ""; | |
180 testing::AssertionResult result( | |
181 (events_ == events) | |
182 ? testing::AssertionSuccess() | |
183 : (testing::AssertionFailure() | |
184 << "Expected " << maybe_newline << Str(events) << ", " | |
185 << maybe_newline << "Got " << maybe_newline << Str(events_))); | |
186 events_.clear(); | |
187 return result; | |
188 } | |
189 | |
190 } // namespace | |
191 | |
192 class AccountTrackerServiceTest : public testing::Test { | |
193 public: | |
194 AccountTrackerServiceTest() {} | |
195 | |
196 virtual ~AccountTrackerServiceTest() {} | |
197 | |
198 virtual void SetUp() OVERRIDE { | |
199 fake_oauth2_token_service_.reset(new FakeOAuth2TokenService()); | |
200 | |
201 pref_service_.registry()->RegisterListPref( | |
202 AccountTrackerService::kAccountInfoPref); | |
203 | |
204 account_tracker_.reset(new AccountTrackerService()); | |
205 account_tracker_->Initialize(fake_oauth2_token_service_.get(), | |
206 &pref_service_, | |
207 new net::TestURLRequestContextGetter( | |
208 message_loop_.message_loop_proxy())); | |
209 account_tracker_->AddObserver(&observer_); | |
210 } | |
211 | |
212 virtual void TearDown() OVERRIDE { | |
213 account_tracker_->RemoveObserver(&observer_); | |
214 account_tracker_->Shutdown(); | |
215 } | |
216 | |
217 void SimulateTokenAvailable(const std::string& account_id) { | |
218 fake_oauth2_token_service_->AddAccount(account_id); | |
219 } | |
220 | |
221 void SimulateTokenRevoked(const std::string& account_id) { | |
222 fake_oauth2_token_service_->RemoveAccount(account_id); | |
223 } | |
224 | |
225 // Helpers to fake access token and user info fetching | |
226 void IssueAccessToken(const std::string& account_id) { | |
227 fake_oauth2_token_service_->IssueAllTokensForAccount( | |
228 account_id, "access_token-" + account_id, base::Time::Max()); | |
229 } | |
230 | |
231 std::string GenerateValidTokenInfoResponse(const std::string& account_id) { | |
232 return base::StringPrintf("{\"id\": \"%s\", \"email\": \"%s\"}", | |
233 AccountIdToGaiaId(account_id).c_str(), | |
234 AccountIdToEmail(account_id).c_str()); | |
235 } | |
236 | |
237 void ReturnOAuthUrlFetchSuccess(const std::string& account_id); | |
238 void ReturnOAuthUrlFetchFailure(const std::string& account_id); | |
239 | |
240 base::MessageLoopForIO* message_loop() { return &message_loop_; } | |
241 AccountTrackerService* account_tracker() { return account_tracker_.get(); } | |
242 AccountTrackerObserver* observer() { return &observer_; } | |
243 OAuth2TokenService* token_service() { | |
244 return fake_oauth2_token_service_.get(); | |
245 } | |
246 TestingPrefServiceSimple* pref_service() { return &pref_service_; } | |
247 | |
248 private: | |
249 void ReturnOAuthUrlFetchResults(int fetcher_id, | |
250 net::HttpStatusCode response_code, | |
251 const std::string& response_string); | |
252 | |
253 base::MessageLoopForIO message_loop_; | |
254 net::TestURLFetcherFactory test_fetcher_factory_; | |
255 scoped_ptr<FakeOAuth2TokenService> fake_oauth2_token_service_; | |
256 TestingPrefServiceSimple pref_service_; | |
257 scoped_ptr<AccountTrackerService> account_tracker_; | |
258 AccountTrackerObserver observer_; | |
259 }; | |
260 | |
261 void AccountTrackerServiceTest::ReturnOAuthUrlFetchResults( | |
262 int fetcher_id, | |
263 net::HttpStatusCode response_code, | |
264 const std::string& response_string) { | |
265 net::TestURLFetcher* fetcher = | |
266 test_fetcher_factory_.GetFetcherByID(fetcher_id); | |
267 ASSERT_TRUE(fetcher); | |
268 fetcher->set_response_code(response_code); | |
269 fetcher->SetResponseString(response_string); | |
270 fetcher->delegate()->OnURLFetchComplete(fetcher); | |
271 } | |
272 | |
273 void AccountTrackerServiceTest::ReturnOAuthUrlFetchSuccess( | |
274 const std::string& account_id) { | |
275 IssueAccessToken(account_id); | |
276 ReturnOAuthUrlFetchResults(gaia::GaiaOAuthClient::kUrlFetcherId, | |
277 net::HTTP_OK, | |
278 GenerateValidTokenInfoResponse(account_id)); | |
279 } | |
280 | |
281 void AccountTrackerServiceTest::ReturnOAuthUrlFetchFailure( | |
282 const std::string& account_id) { | |
283 IssueAccessToken(account_id); | |
284 ReturnOAuthUrlFetchResults( | |
285 gaia::GaiaOAuthClient::kUrlFetcherId, net::HTTP_BAD_REQUEST, ""); | |
286 } | |
287 | |
288 TEST_F(AccountTrackerServiceTest, Basic) { | |
289 } | |
290 | |
291 TEST_F(AccountTrackerServiceTest, TokenAvailable) { | |
292 SimulateTokenAvailable("alpha"); | |
293 ASSERT_FALSE(account_tracker()->IsAllUserInfoFetched()); | |
294 ASSERT_TRUE(observer()->CheckEvents()); | |
295 } | |
296 | |
297 TEST_F(AccountTrackerServiceTest, TokenAvailable_Revoked) { | |
298 SimulateTokenAvailable("alpha"); | |
299 SimulateTokenRevoked("alpha"); | |
300 ASSERT_TRUE(account_tracker()->IsAllUserInfoFetched()); | |
301 ASSERT_TRUE(observer()->CheckEvents()); | |
302 } | |
303 | |
304 TEST_F(AccountTrackerServiceTest, TokenAvailable_UserInfo) { | |
305 SimulateTokenAvailable("alpha"); | |
306 ReturnOAuthUrlFetchSuccess("alpha"); | |
307 ASSERT_TRUE(account_tracker()->IsAllUserInfoFetched()); | |
308 ASSERT_TRUE(observer()->CheckEvents(TrackingEvent(UPDATED, "alpha"))); | |
309 } | |
310 | |
311 TEST_F(AccountTrackerServiceTest, TokenAvailable_UserInfo_Revoked) { | |
312 SimulateTokenAvailable("alpha"); | |
313 ReturnOAuthUrlFetchSuccess("alpha"); | |
314 ASSERT_TRUE(account_tracker()->IsAllUserInfoFetched()); | |
315 ASSERT_TRUE(observer()->CheckEvents(TrackingEvent(UPDATED, "alpha"))); | |
316 SimulateTokenRevoked("alpha"); | |
317 ASSERT_TRUE(observer()->CheckEvents(TrackingEvent(REMOVED, "alpha"))); | |
318 } | |
319 | |
320 TEST_F(AccountTrackerServiceTest, TokenAvailable_UserInfoFailed) { | |
321 SimulateTokenAvailable("alpha"); | |
322 ReturnOAuthUrlFetchFailure("alpha"); | |
323 ASSERT_TRUE(account_tracker()->IsAllUserInfoFetched()); | |
324 ASSERT_TRUE(observer()->CheckEvents()); | |
325 } | |
326 | |
327 TEST_F(AccountTrackerServiceTest, TokenAlreadyExists) { | |
328 SimulateTokenAvailable("alpha"); | |
329 AccountTrackerService tracker; | |
330 AccountTrackerObserver observer; | |
331 tracker.AddObserver(&observer); | |
332 tracker.Initialize(token_service(), | |
333 pref_service(), | |
334 new net::TestURLRequestContextGetter( | |
335 message_loop()->message_loop_proxy())); | |
336 ASSERT_FALSE(tracker.IsAllUserInfoFetched()); | |
337 ASSERT_TRUE(observer.CheckEvents()); | |
338 tracker.RemoveObserver(&observer); | |
339 tracker.Shutdown(); | |
340 } | |
341 | |
342 TEST_F(AccountTrackerServiceTest, TwoTokenAvailable_TwoUserInfo) { | |
343 SimulateTokenAvailable("alpha"); | |
344 SimulateTokenAvailable("beta"); | |
345 ReturnOAuthUrlFetchSuccess("alpha"); | |
346 ReturnOAuthUrlFetchSuccess("beta"); | |
347 ASSERT_TRUE(account_tracker()->IsAllUserInfoFetched()); | |
348 ASSERT_TRUE(observer()->CheckEvents(TrackingEvent(UPDATED, "alpha"), | |
349 TrackingEvent(UPDATED, "beta"))); | |
350 } | |
351 | |
352 TEST_F(AccountTrackerServiceTest, TwoTokenAvailable_OneUserInfo) { | |
353 SimulateTokenAvailable("alpha"); | |
354 SimulateTokenAvailable("beta"); | |
355 ReturnOAuthUrlFetchSuccess("beta"); | |
356 ASSERT_FALSE(account_tracker()->IsAllUserInfoFetched()); | |
357 ASSERT_TRUE(observer()->CheckEvents(TrackingEvent(UPDATED, "beta"))); | |
358 ReturnOAuthUrlFetchSuccess("alpha"); | |
359 ASSERT_TRUE(account_tracker()->IsAllUserInfoFetched()); | |
360 ASSERT_TRUE(observer()->CheckEvents(TrackingEvent(UPDATED, "alpha"))); | |
361 } | |
362 | |
363 TEST_F(AccountTrackerServiceTest, GetAccounts) { | |
364 SimulateTokenAvailable("alpha"); | |
365 SimulateTokenAvailable("beta"); | |
366 SimulateTokenAvailable("gamma"); | |
367 ReturnOAuthUrlFetchSuccess("alpha"); | |
368 ReturnOAuthUrlFetchSuccess("beta"); | |
369 ReturnOAuthUrlFetchSuccess("gamma"); | |
370 | |
371 std::vector<AccountTrackerService::AccountInfo> infos = | |
372 account_tracker()->GetAccounts(); | |
373 | |
374 EXPECT_EQ(3u, infos.size()); | |
375 EXPECT_EQ("alpha", infos[0].account_id); | |
376 EXPECT_EQ(AccountIdToGaiaId("alpha"), infos[0].gaia); | |
377 EXPECT_EQ(AccountIdToEmail("alpha"), infos[0].email); | |
378 EXPECT_EQ("beta", infos[1].account_id); | |
379 EXPECT_EQ(AccountIdToGaiaId("beta"), infos[1].gaia); | |
380 EXPECT_EQ(AccountIdToEmail("beta"), infos[1].email); | |
381 EXPECT_EQ("gamma", infos[2].account_id); | |
382 EXPECT_EQ(AccountIdToGaiaId("gamma"), infos[2].gaia); | |
383 EXPECT_EQ(AccountIdToEmail("gamma"), infos[2].email); | |
384 } | |
385 | |
386 TEST_F(AccountTrackerServiceTest, GetAccountInfo_Empty) { | |
387 AccountTrackerService::AccountInfo info = | |
388 account_tracker()->GetAccountInfo("alpha"); | |
389 ASSERT_EQ("", info.account_id); | |
390 } | |
391 | |
392 TEST_F(AccountTrackerServiceTest, GetAccountInfo_TokenAvailable) { | |
393 SimulateTokenAvailable("alpha"); | |
394 AccountTrackerService::AccountInfo info = | |
395 account_tracker()->GetAccountInfo("alpha"); | |
396 ASSERT_EQ("alpha", info.account_id); | |
397 ASSERT_EQ("", info.gaia); | |
398 ASSERT_EQ("", info.email); | |
399 } | |
400 | |
401 TEST_F(AccountTrackerServiceTest, GetAccountInfo_TokenAvailable_UserInfo) { | |
402 SimulateTokenAvailable("alpha"); | |
403 ReturnOAuthUrlFetchSuccess("alpha"); | |
404 AccountTrackerService::AccountInfo info = | |
405 account_tracker()->GetAccountInfo("alpha"); | |
406 ASSERT_EQ("alpha", info.account_id); | |
407 ASSERT_EQ(AccountIdToGaiaId("alpha"), info.gaia); | |
408 ASSERT_EQ(AccountIdToEmail("alpha"), info.email); | |
409 } | |
410 | |
411 TEST_F(AccountTrackerServiceTest, FindAccountInfoByGaiaId) { | |
412 SimulateTokenAvailable("alpha"); | |
413 ReturnOAuthUrlFetchSuccess("alpha"); | |
414 | |
415 std::string gaia_id = AccountIdToGaiaId("alpha"); | |
416 AccountTrackerService::AccountInfo info = | |
417 account_tracker()->FindAccountInfoByGaiaId(gaia_id); | |
418 ASSERT_EQ("alpha", info.account_id); | |
419 ASSERT_EQ(gaia_id, info.gaia); | |
420 | |
421 gaia_id = AccountIdToGaiaId("beta"); | |
422 info = account_tracker()->FindAccountInfoByGaiaId(gaia_id); | |
423 ASSERT_EQ("", info.account_id); | |
424 } | |
425 | |
426 TEST_F(AccountTrackerServiceTest, FindAccountInfoByEmail) { | |
427 SimulateTokenAvailable("alpha"); | |
428 ReturnOAuthUrlFetchSuccess("alpha"); | |
429 | |
430 std::string email = AccountIdToEmail("alpha"); | |
431 AccountTrackerService::AccountInfo info = | |
432 account_tracker()->FindAccountInfoByEmail(email); | |
433 ASSERT_EQ("alpha", info.account_id); | |
434 ASSERT_EQ(email, info.email); | |
435 | |
436 // Should also work with "canonically-equal" email addresses. | |
437 info = account_tracker()->FindAccountInfoByEmail("Alpha@Gmail.COM"); | |
438 ASSERT_EQ("alpha", info.account_id); | |
439 ASSERT_EQ(email, info.email); | |
440 info = account_tracker()->FindAccountInfoByEmail("al.pha@gmail.com"); | |
441 ASSERT_EQ("alpha", info.account_id); | |
442 ASSERT_EQ(email, info.email); | |
443 | |
444 email = AccountIdToEmail("beta"); | |
445 info = account_tracker()->FindAccountInfoByEmail(email); | |
446 ASSERT_EQ("", info.account_id); | |
447 } | |
448 | |
449 TEST_F(AccountTrackerServiceTest, Persistence) { | |
450 // Create a tracker and add two accounts. This should cause the accounts | |
451 // to be saved to persistence. | |
452 { | |
453 AccountTrackerService tracker; | |
454 tracker.Initialize(token_service(), | |
455 pref_service(), | |
456 new net::TestURLRequestContextGetter( | |
457 message_loop()->message_loop_proxy())); | |
458 SimulateTokenAvailable("alpha"); | |
459 ReturnOAuthUrlFetchSuccess("alpha"); | |
460 SimulateTokenAvailable("beta"); | |
461 ReturnOAuthUrlFetchSuccess("beta"); | |
462 tracker.Shutdown(); | |
463 } | |
464 | |
465 // Create a new tracker and make sure it loads the accounts corectly from | |
466 // persistence. | |
467 { | |
468 AccountTrackerService tracker; | |
469 tracker.AddObserver(observer()); | |
470 tracker.Initialize(token_service(), | |
471 pref_service(), | |
472 new net::TestURLRequestContextGetter( | |
473 message_loop()->message_loop_proxy())); | |
474 ASSERT_TRUE(observer()->CheckEvents(TrackingEvent(UPDATED, "alpha"), | |
475 TrackingEvent(UPDATED, "beta"))); | |
476 | |
477 std::vector<AccountTrackerService::AccountInfo> infos = | |
478 tracker.GetAccounts(); | |
479 ASSERT_EQ(2u, infos.size()); | |
480 EXPECT_EQ(AccountIdToGaiaId("alpha"), infos[0].gaia); | |
481 EXPECT_EQ(AccountIdToEmail("alpha"), infos[0].email); | |
482 EXPECT_EQ("beta", infos[1].account_id); | |
483 EXPECT_EQ(AccountIdToGaiaId("beta"), infos[1].gaia); | |
484 EXPECT_EQ(AccountIdToEmail("beta"), infos[1].email); | |
485 | |
486 // Remove account. | |
487 SimulateTokenRevoked("alpha"); | |
488 tracker.RemoveObserver(observer()); | |
489 tracker.Shutdown(); | |
490 } | |
491 | |
492 // Create a new tracker and make sure it loads the single account from | |
493 // persistence. | |
494 { | |
495 AccountTrackerService tracker; | |
496 tracker.Initialize(token_service(), | |
497 pref_service(), | |
498 new net::TestURLRequestContextGetter( | |
499 message_loop()->message_loop_proxy())); | |
500 | |
501 std::vector<AccountTrackerService::AccountInfo> infos = | |
502 tracker.GetAccounts(); | |
503 ASSERT_EQ(1u, infos.size()); | |
504 EXPECT_EQ("beta", infos[0].account_id); | |
505 EXPECT_EQ(AccountIdToGaiaId("beta"), infos[0].gaia); | |
506 EXPECT_EQ(AccountIdToEmail("beta"), infos[0].email); | |
507 tracker.Shutdown(); | |
508 } | |
509 } | |
OLD | NEW |