|
1 | 1 | import re
|
2 |
| -from datetime import datetime, timedelta |
| 2 | +from datetime import datetime, timedelta, timezone |
3 | 3 | from unittest.mock import MagicMock, patch
|
4 | 4 |
|
5 | 5 | import pytest
|
@@ -41,7 +41,7 @@ def test_update_rate_limit(self):
|
41 | 41 |
|
42 | 42 | assert token_manager.rate_limit == 5000
|
43 | 43 | assert token_manager.rate_limit_remaining == 4999
|
44 |
| - assert token_manager.rate_limit_reset == 1372700873 |
| 44 | + assert token_manager.rate_limit_reset == datetime(2013, 7, 1, 17, 47, 53) |
45 | 45 | assert token_manager.rate_limit_used == 1
|
46 | 46 |
|
47 | 47 | def test_is_valid_token_successful(self):
|
@@ -165,6 +165,135 @@ def test_successful_token_generation(self):
|
165 | 165 | assert token_manager.token == "valid_token"
|
166 | 166 | assert token_manager.token_expires_at == token_time
|
167 | 167 |
|
| 168 | + def test_has_calls_remaining_regenerates_a_token_if_close_to_expiry(self): |
| 169 | + unexpired_time = datetime.now() + timedelta(days=1) |
| 170 | + expired_time = datetime.now() - timedelta(days=1) |
| 171 | + with patch.object(AppTokenManager, "is_valid_token", return_value=True), patch( |
| 172 | + "tap_github.authenticator.generate_app_access_token", |
| 173 | + return_value=("valid_token", unexpired_time), |
| 174 | + ): |
| 175 | + mock_response_headers = { |
| 176 | + "X-RateLimit-Limit": "5000", |
| 177 | + "X-RateLimit-Remaining": "4999", |
| 178 | + "X-RateLimit-Reset": "1372700873", |
| 179 | + "X-RateLimit-Used": "1", |
| 180 | + } |
| 181 | + |
| 182 | + token_manager = AppTokenManager("12345;;key\\ncontent;;67890") |
| 183 | + token_manager.logger = MagicMock() |
| 184 | + token_manager.token_expires_at = expired_time |
| 185 | + token_manager.update_rate_limit(mock_response_headers) |
| 186 | + |
| 187 | + assert token_manager.has_calls_remaining() |
| 188 | + # calling has_calls_remaining() will trigger the token generation function to be called again, |
| 189 | + # so token_expires_at should have been reset back to the mocked unexpired_time |
| 190 | + assert token_manager.token_expires_at == unexpired_time |
| 191 | + token_manager.logger.info.assert_called_once() |
| 192 | + assert ( |
| 193 | + "GitHub app token refresh succeeded." |
| 194 | + in token_manager.logger.info.call_args[0][0] |
| 195 | + ) |
| 196 | + |
| 197 | + def test_has_calls_remaining_logs_warning_if_token_regeneration_fails(self): |
| 198 | + unexpired_time = datetime.now() + timedelta(days=1) |
| 199 | + expired_time = datetime.now() - timedelta(days=1) |
| 200 | + with patch.object( |
| 201 | + AppTokenManager, "is_valid_token", return_value=True |
| 202 | + ) as mock_is_valid, patch( |
| 203 | + "tap_github.authenticator.generate_app_access_token", |
| 204 | + return_value=("valid_token", unexpired_time), |
| 205 | + ): |
| 206 | + mock_response_headers = { |
| 207 | + "X-RateLimit-Limit": "5000", |
| 208 | + "X-RateLimit-Remaining": "4999", |
| 209 | + "X-RateLimit-Reset": "1372700873", |
| 210 | + "X-RateLimit-Used": "1", |
| 211 | + } |
| 212 | + |
| 213 | + token_manager = AppTokenManager("12345;;key\\ncontent;;67890") |
| 214 | + token_manager.logger = MagicMock() |
| 215 | + token_manager.token_expires_at = expired_time |
| 216 | + token_manager.update_rate_limit(mock_response_headers) |
| 217 | + |
| 218 | + mock_is_valid.return_value = False |
| 219 | + assert not token_manager.has_calls_remaining() |
| 220 | + token_manager.logger.warn.assert_called_once() |
| 221 | + assert ( |
| 222 | + "GitHub app token refresh failed." |
| 223 | + in token_manager.logger.warn.call_args[0][0] |
| 224 | + ) |
| 225 | + |
| 226 | + def test_has_calls_remaining_succeeds_if_token_new_and_never_used(self): |
| 227 | + unexpired_time = datetime.now() + timedelta(days=1) |
| 228 | + with patch.object(AppTokenManager, "is_valid_token", return_value=True), patch( |
| 229 | + "tap_github.authenticator.generate_app_access_token", |
| 230 | + return_value=("valid_token", unexpired_time), |
| 231 | + ): |
| 232 | + token_manager = AppTokenManager("12345;;key\\ncontent;;67890") |
| 233 | + assert token_manager.has_calls_remaining() |
| 234 | + |
| 235 | + def test_has_calls_remaining_succeeds_if_time_and_requests_left(self): |
| 236 | + unexpired_time = datetime.now() + timedelta(days=1) |
| 237 | + with patch.object(AppTokenManager, "is_valid_token", return_value=True), patch( |
| 238 | + "tap_github.authenticator.generate_app_access_token", |
| 239 | + return_value=("valid_token", unexpired_time), |
| 240 | + ): |
| 241 | + mock_response_headers = { |
| 242 | + "X-RateLimit-Limit": "5000", |
| 243 | + "X-RateLimit-Remaining": "4999", |
| 244 | + "X-RateLimit-Reset": "1372700873", |
| 245 | + "X-RateLimit-Used": "1", |
| 246 | + } |
| 247 | + |
| 248 | + token_manager = AppTokenManager("12345;;key\\ncontent;;67890") |
| 249 | + token_manager.update_rate_limit(mock_response_headers) |
| 250 | + |
| 251 | + assert token_manager.has_calls_remaining() |
| 252 | + |
| 253 | + def test_has_calls_remaining_succeeds_if_time_left_and_reset_time_reached(self): |
| 254 | + unexpired_time = datetime.now() + timedelta(days=1) |
| 255 | + with patch.object(AppTokenManager, "is_valid_token", return_value=True), patch( |
| 256 | + "tap_github.authenticator.generate_app_access_token", |
| 257 | + return_value=("valid_token", unexpired_time), |
| 258 | + ): |
| 259 | + mock_response_headers = { |
| 260 | + "X-RateLimit-Limit": "5000", |
| 261 | + "X-RateLimit-Remaining": "1", |
| 262 | + "X-RateLimit-Reset": "1372700873", |
| 263 | + "X-RateLimit-Used": "4999", |
| 264 | + } |
| 265 | + |
| 266 | + token_manager = AppTokenManager( |
| 267 | + "12345;;key\\ncontent;;67890", rate_limit_buffer=1000 |
| 268 | + ) |
| 269 | + token_manager.update_rate_limit(mock_response_headers) |
| 270 | + |
| 271 | + assert token_manager.has_calls_remaining() |
| 272 | + |
| 273 | + def test_has_calls_remaining_fails_if_time_left_and_few_calls_remaining_and_reset_time_not_reached( |
| 274 | + self, |
| 275 | + ): |
| 276 | + unexpired_time = datetime.now() + timedelta(days=1) |
| 277 | + with patch.object(AppTokenManager, "is_valid_token", return_value=True), patch( |
| 278 | + "tap_github.authenticator.generate_app_access_token", |
| 279 | + return_value=("valid_token", unexpired_time), |
| 280 | + ): |
| 281 | + mock_response_headers = { |
| 282 | + "X-RateLimit-Limit": "5000", |
| 283 | + "X-RateLimit-Remaining": "1", |
| 284 | + "X-RateLimit-Reset": str( |
| 285 | + int((datetime.now() + timedelta(days=100)).timestamp()) |
| 286 | + ), |
| 287 | + "X-RateLimit-Used": "4999", |
| 288 | + } |
| 289 | + |
| 290 | + token_manager = AppTokenManager( |
| 291 | + "12345;;key\\ncontent;;67890", rate_limit_buffer=1000 |
| 292 | + ) |
| 293 | + token_manager.update_rate_limit(mock_response_headers) |
| 294 | + |
| 295 | + assert not token_manager.has_calls_remaining() |
| 296 | + |
168 | 297 |
|
169 | 298 | @pytest.fixture
|
170 | 299 | def mock_stream():
|
|
0 commit comments