|
11 | 11 | RetryDecision, |
12 | 12 | RetryPresets, |
13 | 13 | RetryStrategyConfig, |
| 14 | + create_linear_retry_strategy, |
14 | 15 | create_retry_strategy, |
15 | 16 | ) |
16 | 17 |
|
@@ -574,3 +575,88 @@ def test_mixed_error_types_and_patterns(): |
574 | 575 |
|
575 | 576 |
|
576 | 577 | # endregion |
| 578 | + |
| 579 | + |
| 580 | +# region create_linear_retry_strategy |
| 581 | + |
| 582 | + |
| 583 | +def test_linear_retry_strategy_uses_additive_formula(): |
| 584 | + """Default config yields delays of 1s, 2s, 3s, 4s, 5s with no jitter.""" |
| 585 | + strategy = create_linear_retry_strategy() |
| 586 | + |
| 587 | + delays = [ |
| 588 | + strategy(Exception("e"), attempt).delay_seconds for attempt in range(1, 6) |
| 589 | + ] |
| 590 | + |
| 591 | + assert delays == [1, 2, 3, 4, 5] |
| 592 | + |
| 593 | + |
| 594 | +def test_linear_retry_strategy_stops_at_max_attempts(): |
| 595 | + """No retry once attempts_made reaches max_attempts.""" |
| 596 | + strategy = create_linear_retry_strategy(max_attempts=3) |
| 597 | + |
| 598 | + assert strategy(Exception("e"), 1).should_retry is True |
| 599 | + assert strategy(Exception("e"), 2).should_retry is True |
| 600 | + assert strategy(Exception("e"), 3).should_retry is False |
| 601 | + |
| 602 | + |
| 603 | +def test_linear_retry_strategy_respects_custom_initial_and_increment(): |
| 604 | + """Custom initial_delay and increment shift the additive sequence.""" |
| 605 | + strategy = create_linear_retry_strategy( |
| 606 | + max_attempts=10, |
| 607 | + initial_delay=Duration.from_seconds(2), |
| 608 | + increment=Duration.from_seconds(3), |
| 609 | + ) |
| 610 | + |
| 611 | + delays = [ |
| 612 | + strategy(Exception("e"), attempt).delay_seconds for attempt in range(1, 5) |
| 613 | + ] |
| 614 | + |
| 615 | + # 2 + 3*0, 2 + 3*1, 2 + 3*2, 2 + 3*3 |
| 616 | + assert delays == [2, 5, 8, 11] |
| 617 | + |
| 618 | + |
| 619 | +# endregion |
| 620 | + |
| 621 | + |
| 622 | +# region RetryPresets.linear / RetryPresets.fixed |
| 623 | + |
| 624 | + |
| 625 | +def test_retry_presets_linear_matches_js_defaults(): |
| 626 | + """RetryPresets.linear() yields 1s, 2s, 3s, 4s, 5s and stops after 6 attempts.""" |
| 627 | + strategy = RetryPresets.linear() |
| 628 | + |
| 629 | + delays = [ |
| 630 | + strategy(Exception("e"), attempt).delay_seconds for attempt in range(1, 6) |
| 631 | + ] |
| 632 | + assert delays == [1, 2, 3, 4, 5] |
| 633 | + assert strategy(Exception("e"), 6).should_retry is False |
| 634 | + |
| 635 | + |
| 636 | +def test_retry_presets_fixed_uses_default_interval(): |
| 637 | + """RetryPresets.fixed() defaults to a 5s constant delay with no jitter.""" |
| 638 | + strategy = RetryPresets.fixed() |
| 639 | + |
| 640 | + for attempt in range(1, 5): |
| 641 | + decision = strategy(Exception("e"), attempt) |
| 642 | + assert decision.should_retry is True |
| 643 | + assert decision.delay_seconds == 5 |
| 644 | + |
| 645 | + |
| 646 | +def test_retry_presets_fixed_respects_custom_interval(): |
| 647 | + """A caller-supplied interval is used as the constant delay.""" |
| 648 | + strategy = RetryPresets.fixed(interval=Duration.from_seconds(12)) |
| 649 | + |
| 650 | + assert strategy(Exception("e"), 1).delay_seconds == 12 |
| 651 | + assert strategy(Exception("e"), 3).delay_seconds == 12 |
| 652 | + |
| 653 | + |
| 654 | +def test_retry_presets_fixed_stops_at_max_attempts(): |
| 655 | + """RetryPresets.fixed() stops retrying after 5 attempts.""" |
| 656 | + strategy = RetryPresets.fixed() |
| 657 | + |
| 658 | + assert strategy(Exception("e"), 4).should_retry is True |
| 659 | + assert strategy(Exception("e"), 5).should_retry is False |
| 660 | + |
| 661 | + |
| 662 | +# endregion |
0 commit comments