| OLD | NEW |
| (Empty) |
| 1 // Copyright 2016 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 "blimp/client/core/session/identity_source.h" | |
| 6 | |
| 7 #include <memory> | |
| 8 #include <string> | |
| 9 #include <utility> | |
| 10 | |
| 11 #include "base/bind.h" | |
| 12 #include "base/callback.h" | |
| 13 #include "base/macros.h" | |
| 14 #include "base/memory/ptr_util.h" | |
| 15 #include "blimp/client/test/test_blimp_client_context_delegate.h" | |
| 16 #include "testing/gtest/include/gtest/gtest.h" | |
| 17 | |
| 18 using ::testing::_; | |
| 19 using ::testing::Return; | |
| 20 | |
| 21 namespace blimp { | |
| 22 namespace client { | |
| 23 namespace { | |
| 24 | |
| 25 class MockIdentitySource : public IdentitySource { | |
| 26 public: | |
| 27 MockIdentitySource( | |
| 28 std::unique_ptr<IdentityProvider> identity_provider, | |
| 29 base::Callback<void(const GoogleServiceAuthError&)> error_callback, | |
| 30 const IdentitySource::TokenCallback& callback) | |
| 31 : IdentitySource(std::move(identity_provider), error_callback, callback), | |
| 32 success_(0), | |
| 33 fail_(0), | |
| 34 refresh_(0), | |
| 35 token_callback_count_(0) {} | |
| 36 ~MockIdentitySource() override{}; | |
| 37 | |
| 38 void OnGetTokenSuccess(const OAuth2TokenService::Request* request, | |
| 39 const std::string& access_token, | |
| 40 const base::Time& expiration_time) override { | |
| 41 IdentitySource::OnGetTokenSuccess(request, access_token, expiration_time); | |
| 42 success_++; | |
| 43 token_ = access_token; | |
| 44 } | |
| 45 | |
| 46 void OnGetTokenFailure(const OAuth2TokenService::Request* request, | |
| 47 const GoogleServiceAuthError& error) override { | |
| 48 IdentitySource::OnGetTokenFailure(request, error); | |
| 49 fail_++; | |
| 50 token_.clear(); | |
| 51 } | |
| 52 | |
| 53 void OnRefreshTokenAvailable(const std::string& account_id) override { | |
| 54 IdentitySource::OnRefreshTokenAvailable(account_id); | |
| 55 refresh_++; | |
| 56 } | |
| 57 | |
| 58 void MockTokenCall(const std::string& token) { | |
| 59 token_callback_count_++; | |
| 60 callback_token_ = token; | |
| 61 } | |
| 62 | |
| 63 IdentityProvider* GetIdentityProvider() { return identity_provider_.get(); } | |
| 64 | |
| 65 int Succeeded() { return success_; } | |
| 66 int Failed() { return fail_; } | |
| 67 int Refreshed() { return refresh_; } | |
| 68 int TokenCallbackCount() { return token_callback_count_; } | |
| 69 // Return the token passed to TokenCallback. | |
| 70 const std::string& CallbackToken() { return callback_token_; } | |
| 71 // Return the token get from OAuth2TokenService. | |
| 72 const std::string& Token() { return token_; } | |
| 73 | |
| 74 // Reset test recording data. | |
| 75 void ResetTestRecords() { | |
| 76 success_ = 0; | |
| 77 fail_ = 0; | |
| 78 refresh_ = 0; | |
| 79 token_callback_count_ = 0; | |
| 80 callback_token_.clear(); | |
| 81 token_.clear(); | |
| 82 } | |
| 83 | |
| 84 private: | |
| 85 std::string token_; | |
| 86 int success_; | |
| 87 int fail_; | |
| 88 int refresh_; | |
| 89 | |
| 90 int token_callback_count_; | |
| 91 std::string callback_token_; | |
| 92 DISALLOW_COPY_AND_ASSIGN(MockIdentitySource); | |
| 93 }; | |
| 94 | |
| 95 class IdentitySourceTest : public testing::Test { | |
| 96 public: | |
| 97 IdentitySourceTest() = default; | |
| 98 ~IdentitySourceTest() override = default; | |
| 99 | |
| 100 private: | |
| 101 DISALLOW_COPY_AND_ASSIGN(IdentitySourceTest); | |
| 102 }; | |
| 103 | |
| 104 TEST_F(IdentitySourceTest, TestConnect) { | |
| 105 TestBlimpClientContextDelegate mock_blimp_delegate; | |
| 106 MockIdentitySource auth( | |
| 107 mock_blimp_delegate.CreateIdentityProvider(), | |
| 108 base::Bind(&TestBlimpClientContextDelegate::OnAuthenticationError, | |
| 109 base::Unretained(&mock_blimp_delegate)), | |
| 110 base::Bind(&MockIdentitySource::MockTokenCall, base::Unretained(&auth))); | |
| 111 FakeIdentityProvider* id_provider = | |
| 112 static_cast<FakeIdentityProvider*>(auth.GetIdentityProvider()); | |
| 113 FakeOAuth2TokenService* token_service = mock_blimp_delegate.GetTokenService(); | |
| 114 | |
| 115 // Connect when user is not signed in. Nothing happens. | |
| 116 id_provider->LogOut(); | |
| 117 auth.Connect(); | |
| 118 DCHECK_EQ(auth.Succeeded(), 0); | |
| 119 DCHECK_EQ(auth.Failed(), 0); | |
| 120 DCHECK_EQ(auth.Refreshed(), 0); | |
| 121 DCHECK_EQ(auth.Token(), std::string()); | |
| 122 auth.ResetTestRecords(); | |
| 123 | |
| 124 FakeOAuth2TokenServiceDelegate* mock_token_service_delegate = | |
| 125 token_service->GetFakeOAuth2TokenServiceDelegate(); | |
| 126 | |
| 127 // Connect when user signed in, but no refresh token, refresh token observer | |
| 128 // should be added. | |
| 129 std::string account = "mock_account"; | |
| 130 id_provider->LogIn(account); | |
| 131 mock_token_service_delegate->RevokeCredentials(account); | |
| 132 // Mock duplicate connect calls in this test. | |
| 133 auth.Connect(); | |
| 134 auth.Connect(); | |
| 135 DCHECK_EQ(auth.Succeeded(), 0); | |
| 136 DCHECK_EQ(auth.Failed(), 0); | |
| 137 DCHECK_EQ(auth.Refreshed(), 0); | |
| 138 DCHECK_EQ(auth.TokenCallbackCount(), 0); | |
| 139 auth.ResetTestRecords(); | |
| 140 | |
| 141 // Issue refresh token, listener should be triggered, and request should be | |
| 142 // sent. | |
| 143 mock_token_service_delegate->UpdateCredentials(account, "mock_refresh_token"); | |
| 144 DCHECK_EQ(auth.Succeeded(), 0); | |
| 145 DCHECK_EQ(auth.Failed(), 0); | |
| 146 DCHECK_EQ(auth.Refreshed(), 1); | |
| 147 DCHECK_EQ(auth.TokenCallbackCount(), 0); | |
| 148 auth.ResetTestRecords(); | |
| 149 | |
| 150 // Fire access token success, first request should be fulfilled. | |
| 151 base::Time time; | |
| 152 std::string mock_access_token = "mock_access_token"; | |
| 153 token_service->IssueAllTokensForAccount(account, mock_access_token, time); | |
| 154 DCHECK_EQ(auth.Succeeded(), 1); | |
| 155 DCHECK_EQ(auth.Failed(), 0); | |
| 156 DCHECK_EQ(auth.Token(), mock_access_token); | |
| 157 DCHECK_EQ(auth.TokenCallbackCount(), 1); | |
| 158 DCHECK_EQ(auth.CallbackToken(), mock_access_token); | |
| 159 auth.ResetTestRecords(); | |
| 160 | |
| 161 // Connect again and fire access token failed. | |
| 162 GoogleServiceAuthError error(GoogleServiceAuthError::State::REQUEST_CANCELED); | |
| 163 auth.Connect(); | |
| 164 auth.Connect(); | |
| 165 token_service->IssueErrorForAllPendingRequestsForAccount(account, error); | |
| 166 DCHECK_EQ(auth.Succeeded(), 0); | |
| 167 DCHECK_EQ(auth.Failed(), 1); | |
| 168 DCHECK_EQ(auth.Token(), std::string()); | |
| 169 DCHECK_EQ(auth.TokenCallbackCount(), 0); | |
| 170 auth.ResetTestRecords(); | |
| 171 | |
| 172 // Refresh token listener should have been removed. | |
| 173 mock_token_service_delegate->UpdateCredentials(account, "mock_refresh_token"); | |
| 174 DCHECK_EQ(auth.Refreshed(), 0); | |
| 175 auth.ResetTestRecords(); | |
| 176 | |
| 177 // Direct connect with refresh token, and no listener should be | |
| 178 // added. The request is a retry request. | |
| 179 auth.Connect(); | |
| 180 auth.Connect(); | |
| 181 token_service->IssueAllTokensForAccount(account, mock_access_token, time); | |
| 182 DCHECK_EQ(auth.Succeeded(), 1); | |
| 183 DCHECK_EQ(auth.Token(), mock_access_token); | |
| 184 mock_token_service_delegate->UpdateCredentials(account, "mock_refresh_token"); | |
| 185 DCHECK_EQ(auth.Refreshed(), 0); | |
| 186 DCHECK_EQ(auth.TokenCallbackCount(), 1); | |
| 187 DCHECK_EQ(auth.CallbackToken(), mock_access_token); | |
| 188 } | |
| 189 | |
| 190 // Test retry on token fetching when refresh token is updated during token | |
| 191 // request. | |
| 192 TEST_F(IdentitySourceTest, TestConnectRetry) { | |
| 193 TestBlimpClientContextDelegate mock_blimp_delegate; | |
| 194 MockIdentitySource auth( | |
| 195 mock_blimp_delegate.CreateIdentityProvider(), | |
| 196 base::Bind(&TestBlimpClientContextDelegate::OnAuthenticationError, | |
| 197 base::Unretained(&mock_blimp_delegate)), | |
| 198 base::Bind(&MockIdentitySource::MockTokenCall, base::Unretained(&auth))); | |
| 199 FakeOAuth2TokenService* token_service = mock_blimp_delegate.GetTokenService(); | |
| 200 FakeIdentityProvider* id_provider = | |
| 201 static_cast<FakeIdentityProvider*>(auth.GetIdentityProvider()); | |
| 202 | |
| 203 std::string account = "mock_account"; | |
| 204 std::string mock_access_token = "mock_token"; | |
| 205 id_provider->LogIn(account); | |
| 206 | |
| 207 // Prepare refresh token. | |
| 208 FakeOAuth2TokenServiceDelegate* mock_token_service_delegate = | |
| 209 token_service->GetFakeOAuth2TokenServiceDelegate(); | |
| 210 mock_token_service_delegate->UpdateCredentials(account, "mock_refresh_token"); | |
| 211 | |
| 212 // Connect and update the refresh token. | |
| 213 auth.Connect(); | |
| 214 GoogleServiceAuthError error(GoogleServiceAuthError::State::REQUEST_CANCELED); | |
| 215 token_service->IssueErrorForAllPendingRequestsForAccount(account, error); | |
| 216 | |
| 217 // At this point, the first request should be canceled, but there should be | |
| 218 // another retry request. | |
| 219 DCHECK_EQ(auth.Succeeded(), 0); | |
| 220 DCHECK_EQ(auth.Failed(), 1); | |
| 221 DCHECK_EQ(auth.Token(), std::string()); | |
| 222 DCHECK_EQ(auth.TokenCallbackCount(), 0); | |
| 223 auth.ResetTestRecords(); | |
| 224 | |
| 225 // Trigger the second request without calling connect. | |
| 226 base::Time time; | |
| 227 token_service->IssueAllTokensForAccount(account, mock_access_token, time); | |
| 228 DCHECK_EQ(auth.Succeeded(), 1); | |
| 229 DCHECK_EQ(auth.Token(), mock_access_token); | |
| 230 DCHECK_EQ(auth.TokenCallbackCount(), 1); | |
| 231 DCHECK_EQ(auth.CallbackToken(), mock_access_token); | |
| 232 } | |
| 233 | |
| 234 TEST_F(IdentitySourceTest, TestConnectFailDelegateCallback) { | |
| 235 TestBlimpClientContextDelegate mock_blimp_delegate; | |
| 236 MockIdentitySource auth( | |
| 237 mock_blimp_delegate.CreateIdentityProvider(), | |
| 238 base::Bind(&TestBlimpClientContextDelegate::OnAuthenticationError, | |
| 239 base::Unretained(&mock_blimp_delegate)), | |
| 240 base::Bind(&MockIdentitySource::MockTokenCall, base::Unretained(&auth))); | |
| 241 FakeOAuth2TokenService* token_service = mock_blimp_delegate.GetTokenService(); | |
| 242 FakeIdentityProvider* id_provider = | |
| 243 static_cast<FakeIdentityProvider*>(auth.GetIdentityProvider()); | |
| 244 | |
| 245 std::string account = "mock_account"; | |
| 246 std::string mock_access_token = "mock_token"; | |
| 247 id_provider->LogIn(account); | |
| 248 | |
| 249 // Prepare refresh token. | |
| 250 FakeOAuth2TokenServiceDelegate* mock_token_service_delegate = | |
| 251 token_service->GetFakeOAuth2TokenServiceDelegate(); | |
| 252 mock_token_service_delegate->UpdateCredentials(account, "mock_refresh_token"); | |
| 253 | |
| 254 // Expect delegate to show error message on non REQUEST_CANCELED errors. | |
| 255 auth.Connect(); | |
| 256 GoogleServiceAuthError error( | |
| 257 GoogleServiceAuthError::State::CONNECTION_FAILED); | |
| 258 | |
| 259 EXPECT_CALL(mock_blimp_delegate, OnAuthenticationError(error)) | |
| 260 .WillOnce(Return()); | |
| 261 token_service->IssueErrorForAllPendingRequestsForAccount(account, error); | |
| 262 | |
| 263 DCHECK_EQ(auth.Failed(), 1); | |
| 264 } | |
| 265 | |
| 266 TEST_F(IdentitySourceTest, CheckUserName) { | |
| 267 TestBlimpClientContextDelegate mock_blimp_delegate; | |
| 268 MockIdentitySource auth( | |
| 269 mock_blimp_delegate.CreateIdentityProvider(), | |
| 270 base::Bind(&TestBlimpClientContextDelegate::OnAuthenticationError, | |
| 271 base::Unretained(&mock_blimp_delegate)), | |
| 272 base::Bind(&MockIdentitySource::MockTokenCall, base::Unretained(&auth))); | |
| 273 | |
| 274 FakeIdentityProvider* id_provider = | |
| 275 static_cast<FakeIdentityProvider*>(auth.GetIdentityProvider()); | |
| 276 std::string account = "mock_account"; | |
| 277 | |
| 278 // Verify the user name before the login. | |
| 279 EXPECT_EQ("", auth.GetActiveUsername()); | |
| 280 | |
| 281 // Log in the mock user. | |
| 282 id_provider->LogIn(account); | |
| 283 | |
| 284 // Verify that the identity source can return the correct user name. | |
| 285 EXPECT_EQ(account, auth.GetActiveUsername()); | |
| 286 | |
| 287 // Verify the user name after the logout. | |
| 288 id_provider->LogOut(); | |
| 289 EXPECT_EQ("", auth.GetActiveUsername()); | |
| 290 } | |
| 291 | |
| 292 } // namespace | |
| 293 } // namespace client | |
| 294 } // namespace blimp | |
| OLD | NEW |