• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2010 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 // This file defines a unit test for the profile's token service.
6 
7 #include "chrome/browser/net/gaia/token_service_unittest.h"
8 
9 #include "base/command_line.h"
10 #include "base/synchronization/waitable_event.h"
11 #include "chrome/browser/password_manager/encryptor.h"
12 #include "chrome/common/chrome_switches.h"
13 #include "chrome/common/net/gaia/gaia_auth_fetcher_unittest.h"
14 #include "chrome/common/net/gaia/gaia_constants.h"
15 #include "chrome/common/net/test_url_fetcher_factory.h"
16 
TokenAvailableTracker()17 TokenAvailableTracker::TokenAvailableTracker() {}
18 
~TokenAvailableTracker()19 TokenAvailableTracker::~TokenAvailableTracker() {}
20 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)21 void TokenAvailableTracker::Observe(NotificationType type,
22                                     const NotificationSource& source,
23                                     const NotificationDetails& details) {
24   TestNotificationTracker::Observe(type, source, details);
25   if (type == NotificationType::TOKEN_AVAILABLE) {
26     Details<const TokenService::TokenAvailableDetails> full = details;
27     details_ = *full.ptr();
28   }
29 }
30 
TokenFailedTracker()31 TokenFailedTracker::TokenFailedTracker() {}
32 
~TokenFailedTracker()33 TokenFailedTracker::~TokenFailedTracker() {}
34 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)35 void TokenFailedTracker::Observe(NotificationType type,
36                                  const NotificationSource& source,
37                                  const NotificationDetails& details) {
38   TestNotificationTracker::Observe(type, source, details);
39   if (type == NotificationType::TOKEN_REQUEST_FAILED) {
40     Details<const TokenService::TokenRequestFailedDetails> full = details;
41     details_ = *full.ptr();
42   }
43 }
44 
TokenServiceTestHarness()45 TokenServiceTestHarness::TokenServiceTestHarness()
46     : ui_thread_(BrowserThread::UI, &message_loop_),
47       db_thread_(BrowserThread::DB) {
48 }
49 
~TokenServiceTestHarness()50 TokenServiceTestHarness::~TokenServiceTestHarness() {}
51 
SetUp()52 void TokenServiceTestHarness::SetUp() {
53 #if defined(OS_MACOSX)
54   Encryptor::UseMockKeychain(true);
55 #endif
56   credentials_.sid = "sid";
57   credentials_.lsid = "lsid";
58   credentials_.token = "token";
59   credentials_.data = "data";
60 
61   ASSERT_TRUE(db_thread_.Start());
62 
63   profile_.reset(new TestingProfile());
64   profile_->CreateWebDataService(false);
65   WaitForDBLoadCompletion();
66 
67   success_tracker_.ListenFor(NotificationType::TOKEN_AVAILABLE,
68                              Source<TokenService>(&service_));
69   failure_tracker_.ListenFor(NotificationType::TOKEN_REQUEST_FAILED,
70                              Source<TokenService>(&service_));
71 
72   service_.Initialize("test", profile_.get());
73 
74   URLFetcher::set_factory(NULL);
75 }
76 
TearDown()77 void TokenServiceTestHarness::TearDown() {
78   // You have to destroy the profile before the db_thread_ stops.
79   if (profile_.get()) {
80     profile_.reset(NULL);
81   }
82 
83   db_thread_.Stop();
84   MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask);
85   MessageLoop::current()->Run();
86 }
87 
WaitForDBLoadCompletion()88 void TokenServiceTestHarness::WaitForDBLoadCompletion() {
89   // The WebDB does all work on the DB thread. This will add an event
90   // to the end of the DB thread, so when we reach this task, all DB
91   // operations should be complete.
92   base::WaitableEvent done(false, false);
93   BrowserThread::PostTask(
94       BrowserThread::DB, FROM_HERE, new SignalingTask(&done));
95   done.Wait();
96 
97   // Notifications should be returned from the DB thread onto the UI thread.
98   message_loop_.RunAllPending();
99 }
100 
101 class TokenServiceTest : public TokenServiceTestHarness {
102  public:
SetUp()103   virtual void SetUp() {
104     TokenServiceTestHarness::SetUp();
105     service_.UpdateCredentials(credentials_);
106   }
107 };
108 
TEST_F(TokenServiceTest,SanityCheck)109 TEST_F(TokenServiceTest, SanityCheck) {
110   EXPECT_TRUE(service_.HasLsid());
111   EXPECT_EQ(service_.GetLsid(), "lsid");
112   EXPECT_FALSE(service_.HasTokenForService("nonexistent service"));
113 }
114 
TEST_F(TokenServiceTest,NoToken)115 TEST_F(TokenServiceTest, NoToken) {
116   EXPECT_FALSE(service_.HasTokenForService("nonexistent service"));
117   EXPECT_EQ(service_.GetTokenForService("nonexistent service"), std::string());
118 }
119 
TEST_F(TokenServiceTest,NotificationSuccess)120 TEST_F(TokenServiceTest, NotificationSuccess) {
121   EXPECT_EQ(0U, success_tracker_.size());
122   EXPECT_EQ(0U, failure_tracker_.size());
123   service_.OnIssueAuthTokenSuccess(GaiaConstants::kSyncService, "token");
124   EXPECT_EQ(1U, success_tracker_.size());
125   EXPECT_EQ(0U, failure_tracker_.size());
126 
127   TokenService::TokenAvailableDetails details = success_tracker_.details();
128   // MSVC doesn't like this comparison as EQ.
129   EXPECT_TRUE(details.service() == GaiaConstants::kSyncService);
130   EXPECT_EQ(details.token(), "token");
131 }
132 
TEST_F(TokenServiceTest,NotificationFailed)133 TEST_F(TokenServiceTest, NotificationFailed) {
134   EXPECT_EQ(0U, success_tracker_.size());
135   EXPECT_EQ(0U, failure_tracker_.size());
136   GoogleServiceAuthError error(GoogleServiceAuthError::REQUEST_CANCELED);
137   service_.OnIssueAuthTokenFailure(GaiaConstants::kSyncService, error);
138   EXPECT_EQ(0U, success_tracker_.size());
139   EXPECT_EQ(1U, failure_tracker_.size());
140 
141   TokenService::TokenRequestFailedDetails details = failure_tracker_.details();
142 
143   // MSVC doesn't like this comparison as EQ.
144   EXPECT_TRUE(details.service() == GaiaConstants::kSyncService);
145   EXPECT_TRUE(details.error() == error);  // Struct has no print function.
146 }
147 
TEST_F(TokenServiceTest,OnTokenSuccessUpdate)148 TEST_F(TokenServiceTest, OnTokenSuccessUpdate) {
149   service_.OnIssueAuthTokenSuccess(GaiaConstants::kSyncService, "token");
150   EXPECT_TRUE(service_.HasTokenForService(GaiaConstants::kSyncService));
151   EXPECT_EQ(service_.GetTokenForService(GaiaConstants::kSyncService), "token");
152 
153   service_.OnIssueAuthTokenSuccess(GaiaConstants::kSyncService, "token2");
154   EXPECT_TRUE(service_.HasTokenForService(GaiaConstants::kSyncService));
155   EXPECT_EQ(service_.GetTokenForService(GaiaConstants::kSyncService), "token2");
156 
157   service_.OnIssueAuthTokenSuccess(GaiaConstants::kSyncService, "");
158   EXPECT_TRUE(service_.HasTokenForService(GaiaConstants::kSyncService));
159   EXPECT_EQ(service_.GetTokenForService(GaiaConstants::kSyncService), "");
160 }
161 
TEST_F(TokenServiceTest,OnTokenSuccess)162 TEST_F(TokenServiceTest, OnTokenSuccess) {
163   // Don't "start fetching", just go ahead and issue the callback.
164   service_.OnIssueAuthTokenSuccess(GaiaConstants::kSyncService, "token");
165   EXPECT_TRUE(service_.HasTokenForService(GaiaConstants::kSyncService));
166   EXPECT_FALSE(service_.HasTokenForService(GaiaConstants::kTalkService));
167   // Gaia returns the entire result as the token so while this is a shared
168   // result with ClientLogin, it doesn't matter, we should still get it back.
169   EXPECT_EQ(service_.GetTokenForService(GaiaConstants::kSyncService), "token");
170 
171   // Check the second service.
172   service_.OnIssueAuthTokenSuccess(GaiaConstants::kTalkService, "token2");
173   EXPECT_TRUE(service_.HasTokenForService(GaiaConstants::kTalkService));
174   EXPECT_EQ(service_.GetTokenForService(GaiaConstants::kTalkService), "token2");
175 
176   // It didn't change.
177   EXPECT_EQ(service_.GetTokenForService(GaiaConstants::kSyncService), "token");
178 }
179 
TEST_F(TokenServiceTest,ResetSimple)180 TEST_F(TokenServiceTest, ResetSimple) {
181   service_.OnIssueAuthTokenSuccess(GaiaConstants::kSyncService, "token");
182   EXPECT_TRUE(service_.HasTokenForService(GaiaConstants::kSyncService));
183   EXPECT_TRUE(service_.HasLsid());
184 
185   service_.ResetCredentialsInMemory();
186 
187   EXPECT_FALSE(service_.HasTokenForService(GaiaConstants::kSyncService));
188   EXPECT_FALSE(service_.HasLsid());
189 }
190 
TEST_F(TokenServiceTest,ResetComplex)191 TEST_F(TokenServiceTest, ResetComplex) {
192   TestURLFetcherFactory factory;
193   URLFetcher::set_factory(&factory);
194   service_.StartFetchingTokens();
195   // You have to call delegates by hand with the test fetcher,
196   // Let's pretend only one returned.
197 
198   service_.OnIssueAuthTokenSuccess(GaiaConstants::kSyncService, "eraseme");
199   EXPECT_TRUE(service_.HasTokenForService(GaiaConstants::kSyncService));
200   EXPECT_EQ(service_.GetTokenForService(GaiaConstants::kSyncService),
201             "eraseme");
202   EXPECT_FALSE(service_.HasTokenForService(GaiaConstants::kTalkService));
203 
204   service_.ResetCredentialsInMemory();
205   EXPECT_FALSE(service_.HasTokenForService(GaiaConstants::kSyncService));
206   EXPECT_FALSE(service_.HasTokenForService(GaiaConstants::kTalkService));
207 
208   // Now start using it again.
209   service_.UpdateCredentials(credentials_);
210   service_.StartFetchingTokens();
211 
212   service_.OnIssueAuthTokenSuccess(GaiaConstants::kSyncService, "token");
213   service_.OnIssueAuthTokenSuccess(GaiaConstants::kTalkService, "token2");
214 
215   EXPECT_EQ(service_.GetTokenForService(GaiaConstants::kSyncService), "token");
216   EXPECT_EQ(service_.GetTokenForService(GaiaConstants::kTalkService), "token2");
217 }
218 
TEST_F(TokenServiceTest,FullIntegration)219 TEST_F(TokenServiceTest, FullIntegration) {
220   MockFactory<MockFetcher> factory;
221   std::string result = "SID=sid\nLSID=lsid\nAuth=auth\n";
222   factory.set_results(result);
223   URLFetcher::set_factory(&factory);
224   EXPECT_FALSE(service_.HasTokenForService(GaiaConstants::kSyncService));
225   EXPECT_FALSE(service_.HasTokenForService(GaiaConstants::kTalkService));
226   service_.StartFetchingTokens();
227   URLFetcher::set_factory(NULL);
228 
229   EXPECT_TRUE(service_.HasTokenForService(GaiaConstants::kSyncService));
230   EXPECT_TRUE(service_.HasTokenForService(GaiaConstants::kTalkService));
231   // Gaia returns the entire result as the token so while this is a shared
232   // result with ClientLogin, it doesn't matter, we should still get it back.
233   EXPECT_EQ(service_.GetTokenForService(GaiaConstants::kSyncService), result);
234   EXPECT_EQ(service_.GetTokenForService(GaiaConstants::kTalkService), result);
235 
236   service_.ResetCredentialsInMemory();
237   EXPECT_FALSE(service_.HasTokenForService(GaiaConstants::kSyncService));
238   EXPECT_FALSE(service_.HasTokenForService(GaiaConstants::kTalkService));
239 }
240 
TEST_F(TokenServiceTest,LoadTokensIntoMemoryBasic)241 TEST_F(TokenServiceTest, LoadTokensIntoMemoryBasic) {
242   // Validate that the method sets proper data in notifications and map.
243   std::map<std::string, std::string> db_tokens;
244   std::map<std::string, std::string> memory_tokens;
245 
246   service_.LoadTokensIntoMemory(db_tokens, &memory_tokens);
247   EXPECT_TRUE(db_tokens.empty());
248   EXPECT_TRUE(memory_tokens.empty());
249   EXPECT_EQ(0U, success_tracker_.size());
250 
251   db_tokens[GaiaConstants::kSyncService] = "token";
252   service_.LoadTokensIntoMemory(db_tokens, &memory_tokens);
253   EXPECT_EQ(1U, success_tracker_.size());
254 
255   TokenService::TokenAvailableDetails details = success_tracker_.details();
256   // MSVC doesn't like this comparison as EQ.
257   EXPECT_TRUE(details.service() == GaiaConstants::kSyncService);
258   EXPECT_EQ(details.token(), "token");
259   EXPECT_EQ(1U, memory_tokens.count(GaiaConstants::kSyncService));
260   EXPECT_EQ(memory_tokens[GaiaConstants::kSyncService], "token");
261 }
262 
TEST_F(TokenServiceTest,LoadTokensIntoMemoryAdvanced)263 TEST_F(TokenServiceTest, LoadTokensIntoMemoryAdvanced) {
264   // LoadTokensIntoMemory should avoid setting tokens already in the
265   // token map.
266   std::map<std::string, std::string> db_tokens;
267   std::map<std::string, std::string> memory_tokens;
268 
269   db_tokens["ignore"] = "token";
270 
271   service_.LoadTokensIntoMemory(db_tokens, &memory_tokens);
272   EXPECT_TRUE(memory_tokens.empty());
273   db_tokens[GaiaConstants::kSyncService] = "pepper";
274 
275   service_.LoadTokensIntoMemory(db_tokens, &memory_tokens);
276   EXPECT_EQ(1U, memory_tokens.count(GaiaConstants::kSyncService));
277   EXPECT_EQ(memory_tokens[GaiaConstants::kSyncService], "pepper");
278   EXPECT_EQ(1U, success_tracker_.size());
279   success_tracker_.Reset();
280 
281   // SyncService token is already in memory. Pretend we got it off
282   // the disk as well, but an older token.
283   db_tokens[GaiaConstants::kSyncService] = "ignoreme";
284   db_tokens[GaiaConstants::kTalkService] = "tomato";
285   service_.LoadTokensIntoMemory(db_tokens, &memory_tokens);
286 
287   EXPECT_EQ(2U, memory_tokens.size());
288   EXPECT_EQ(1U, memory_tokens.count(GaiaConstants::kTalkService));
289   EXPECT_EQ(memory_tokens[GaiaConstants::kTalkService], "tomato");
290   EXPECT_EQ(1U, success_tracker_.size());
291   EXPECT_EQ(1U, memory_tokens.count(GaiaConstants::kSyncService));
292   EXPECT_EQ(memory_tokens[GaiaConstants::kSyncService], "pepper");
293 }
294 
TEST_F(TokenServiceTest,WebDBLoadIntegration)295 TEST_F(TokenServiceTest, WebDBLoadIntegration) {
296   service_.LoadTokensFromDB();
297   WaitForDBLoadCompletion();
298   EXPECT_EQ(0U, success_tracker_.size());
299 
300   // Should result in DB write.
301   service_.OnIssueAuthTokenSuccess(GaiaConstants::kSyncService, "token");
302   EXPECT_EQ(1U, success_tracker_.size());
303 
304   EXPECT_TRUE(service_.HasTokenForService(GaiaConstants::kSyncService));
305   // Clean slate.
306   service_.ResetCredentialsInMemory();
307   success_tracker_.Reset();
308   EXPECT_FALSE(service_.HasTokenForService(GaiaConstants::kSyncService));
309 
310   service_.LoadTokensFromDB();
311   WaitForDBLoadCompletion();
312 
313   EXPECT_EQ(1U, success_tracker_.size());
314   EXPECT_TRUE(service_.HasTokenForService(GaiaConstants::kSyncService));
315   EXPECT_FALSE(service_.HasTokenForService(GaiaConstants::kTalkService));
316   EXPECT_FALSE(service_.HasLsid());
317 }
318 
TEST_F(TokenServiceTest,MultipleLoadResetIntegration)319 TEST_F(TokenServiceTest, MultipleLoadResetIntegration) {
320   // Should result in DB write.
321   service_.OnIssueAuthTokenSuccess(GaiaConstants::kSyncService, "token");
322   service_.ResetCredentialsInMemory();
323   success_tracker_.Reset();
324   EXPECT_FALSE(service_.HasTokenForService(GaiaConstants::kSyncService));
325 
326   service_.LoadTokensFromDB();
327   WaitForDBLoadCompletion();
328 
329   service_.LoadTokensFromDB();  // Should do nothing.
330   WaitForDBLoadCompletion();
331 
332   EXPECT_EQ(1U, success_tracker_.size());
333   EXPECT_TRUE(service_.HasTokenForService(GaiaConstants::kSyncService));
334   EXPECT_FALSE(service_.HasTokenForService(GaiaConstants::kTalkService));
335   EXPECT_FALSE(service_.HasLsid());
336 
337   // Reset it one more time so there's no surprises.
338   service_.ResetCredentialsInMemory();
339   success_tracker_.Reset();
340 
341   service_.LoadTokensFromDB();
342   WaitForDBLoadCompletion();
343 
344   EXPECT_EQ(1U, success_tracker_.size());
345   EXPECT_TRUE(service_.HasTokenForService(GaiaConstants::kSyncService));
346 }
347 
348 #ifndef NDEBUG
349 class TokenServiceCommandLineTest : public TokenServiceTestHarness {
350  public:
SetUp()351   virtual void SetUp() {
352     CommandLine original_cl(*CommandLine::ForCurrentProcess());
353     CommandLine::ForCurrentProcess()->AppendSwitchASCII(
354         switches::kSetToken, "my_service:my_value");
355     TokenServiceTestHarness::SetUp();
356     service_.UpdateCredentials(credentials_);
357 
358     *CommandLine::ForCurrentProcess() = original_cl;
359   }
360 };
361 
TEST_F(TokenServiceCommandLineTest,TestValueOverride)362 TEST_F(TokenServiceCommandLineTest, TestValueOverride) {
363   EXPECT_TRUE(service_.HasTokenForService("my_service"));
364   EXPECT_EQ("my_value", service_.GetTokenForService("my_service"));
365 }
366 #endif   // ifndef NDEBUG
367