|
9 | 9 |
|
10 | 10 | from airbyte_cdk.models import FailureType
|
11 | 11 | from airbyte_cdk.sources.declarative.requesters.error_handlers import HttpResponseFilter
|
| 12 | +from airbyte_cdk.sources.declarative.requesters.error_handlers.backoff_strategies import ( |
| 13 | + ConstantBackoffStrategy, |
| 14 | +) |
12 | 15 | from airbyte_cdk.sources.declarative.requesters.error_handlers.composite_error_handler import (
|
13 | 16 | CompositeErrorHandler,
|
14 | 17 | )
|
@@ -272,3 +275,77 @@ def test_max_time_is_max_of_underlying_handlers(test_name, max_times, expected_m
|
272 | 275 |
|
273 | 276 | max_time = composite_error_handler.max_time
|
274 | 277 | assert max_time == expected_max_time
|
| 278 | + |
| 279 | + |
| 280 | +@pytest.mark.parametrize( |
| 281 | + "test_name, handler_strategies, expected_strategies", |
| 282 | + [ |
| 283 | + ("test_empty_strategies", [None, None], None), |
| 284 | + ( |
| 285 | + "test_single_handler_with_strategy", |
| 286 | + [[ConstantBackoffStrategy(5, {}, {})], None], |
| 287 | + [ConstantBackoffStrategy(5, {}, {})], |
| 288 | + ), |
| 289 | + ( |
| 290 | + "test_multiple_handlers_with_strategies", |
| 291 | + [[ConstantBackoffStrategy(5, {}, {})], [ConstantBackoffStrategy(10, {}, {})]], |
| 292 | + [ConstantBackoffStrategy(5, {}, {}), ConstantBackoffStrategy(10, {}, {})], |
| 293 | + ), |
| 294 | + ( |
| 295 | + "test_some_handlers_without_strategies", |
| 296 | + [[ConstantBackoffStrategy(5, {}, {})], None, [ConstantBackoffStrategy(10, {}, {})]], |
| 297 | + [ConstantBackoffStrategy(5, {}, {}), ConstantBackoffStrategy(10, {}, {})], |
| 298 | + ), |
| 299 | + ], |
| 300 | +) |
| 301 | +def test_composite_error_handler_backoff_strategies( |
| 302 | + test_name, handler_strategies, expected_strategies |
| 303 | +): |
| 304 | + parameters = {} |
| 305 | + config = {} |
| 306 | + |
| 307 | + error_handlers = [ |
| 308 | + DefaultErrorHandler(backoff_strategies=strategies, parameters=parameters, config=config) |
| 309 | + for strategies in handler_strategies |
| 310 | + ] |
| 311 | + |
| 312 | + composite_handler = CompositeErrorHandler(error_handlers=error_handlers, parameters=parameters) |
| 313 | + |
| 314 | + assert composite_handler.backoff_strategies == expected_strategies |
| 315 | + |
| 316 | + |
| 317 | +def test_composite_error_handler_always_uses_first_strategy(): |
| 318 | + first_handler = DefaultErrorHandler( |
| 319 | + backoff_strategies=[ConstantBackoffStrategy(5, {}, {})], |
| 320 | + parameters={}, |
| 321 | + config={}, |
| 322 | + response_filters=[ |
| 323 | + HttpResponseFilter( |
| 324 | + action=ResponseAction.RETRY, http_codes={429}, config={}, parameters={} |
| 325 | + ) |
| 326 | + ], |
| 327 | + ) |
| 328 | + second_handler = DefaultErrorHandler( |
| 329 | + backoff_strategies=[ConstantBackoffStrategy(10, {}, {})], |
| 330 | + parameters={}, |
| 331 | + config={}, |
| 332 | + response_filters=[ |
| 333 | + HttpResponseFilter( |
| 334 | + action=ResponseAction.RETRY, http_codes={500}, config={}, parameters={} |
| 335 | + ) |
| 336 | + ], |
| 337 | + ) |
| 338 | + |
| 339 | + composite_handler = CompositeErrorHandler( |
| 340 | + error_handlers=[first_handler, second_handler], parameters={} |
| 341 | + ) |
| 342 | + |
| 343 | + # Test that even for a 500 error (which matches second handler's filter), |
| 344 | + # we still get both strategies with first handler's coming first |
| 345 | + response_mock = create_response(500) |
| 346 | + assert first_handler.backoff_strategies[0].backoff_time(response_mock, 1) == 5 |
| 347 | + |
| 348 | + # Verify we get both strategies in the composite handler |
| 349 | + assert len(composite_handler.backoff_strategies) == 2 |
| 350 | + assert isinstance(composite_handler.backoff_strategies[0], ConstantBackoffStrategy) |
| 351 | + assert composite_handler.backoff_strategies[1], ConstantBackoffStrategy |
0 commit comments