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