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 |