Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions releasenotes/notes/strengthen-retry-test-assertions-715.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
other:
- Strengthen tests for retry controller representations, the incremental wait
cap, and cumulative idle time. Remove obsolete string-strategy constructor
smoke tests that did not exercise retry behavior.
26 changes: 20 additions & 6 deletions tests/test_asyncio.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,11 @@ async def test_stop_after_attempt(self) -> None:
assert thing.counter == 2

def test_repr(self) -> None:
repr(tasyncio.AsyncRetrying())
retrying = tasyncio.AsyncRetrying()
result = repr(retrying)
assert result.startswith("<AsyncRetrying object at 0x")
assert f"sleep={retrying.sleep}, " in result
assert result.endswith("name=None)>")

def test_retry_attributes(self) -> None:
assert hasattr(_retryable_coroutine, "retry")
Expand Down Expand Up @@ -578,14 +582,24 @@ async def test_retry_function_attributes(self) -> None:
- retry object statistics are synced with function statistics
"""

self.assertTrue(
await _retryable_coroutine_with_2_attempts(NoIOErrorAfterCount(1))
)
with (
mock.patch.object(
_retryable_coroutine_with_2_attempts.retry, "wait", wait_fixed(0.25)
),
mock.patch.object(
_retryable_coroutine_with_2_attempts.retry,
"sleep",
new=mock.AsyncMock(),
),
):
self.assertTrue(
await _retryable_coroutine_with_2_attempts(NoIOErrorAfterCount(1))
)

expected_stats = {
"attempt_number": 2,
"delay_since_first_attempt": mock.ANY,
"idle_for": mock.ANY,
"idle_for": 0.25,
"start_time": mock.ANY,
}
self.assertEqual(
Expand All @@ -610,7 +624,7 @@ async def test_retry_function_attributes(self) -> None:
expected_stats = {
"attempt_number": 1,
"delay_since_first_attempt": mock.ANY,
"idle_for": mock.ANY,
"idle_for": 0,
"start_time": mock.ANY,
}
self.assertEqual(
Expand Down
34 changes: 24 additions & 10 deletions tests/test_tenacity.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,12 @@ def __call__(
) -> typing.Any:
pass

repr(ConcreteRetrying())
retrying = ConcreteRetrying(name="test")
result = repr(retrying)
assert result.startswith("<ConcreteRetrying object at 0x")
for attribute in ("stop", "wait", "sleep", "retry", "before", "after"):
assert f"{attribute}={getattr(retrying, attribute)}, " in result
assert result.endswith("name='test')>")

def test_callstate_repr(self) -> None:
rs = RetryCallState(None, None, (), {}) # type: ignore[arg-type]
Expand Down Expand Up @@ -268,9 +273,6 @@ def test_stop_before_delay(self) -> None:
self.assertTrue(r.stop(make_retry_state(2, 1, upcoming_sleep=0)))
self.assertTrue(r.stop(make_retry_state(2, 1.001, upcoming_sleep=0)))

def test_legacy_explicit_stop_type(self) -> None:
Retrying(stop="stop_after_attempt") # type: ignore[arg-type]

def test_stop_func_with_retry_state(self) -> None:
def stop_func(retry_state: RetryCallState) -> bool:
rs = retry_state
Expand Down Expand Up @@ -306,6 +308,15 @@ def test_incrementing_sleep(self) -> None:
self.assertEqual(600, r.wait(make_retry_state(2, 6546)))
self.assertEqual(700, r.wait(make_retry_state(3, 6546)))

def test_incrementing_sleep_with_max(self) -> None:
for max_wait in (3, datetime.timedelta(seconds=3)):
with self.subTest(max_wait=max_wait):
wait = tenacity.wait_incrementing(start=1, increment=1, max=max_wait)
self.assertEqual(
[1, 2, 3, 3, 3, 3],
[wait(make_retry_state(attempt, 0)) for attempt in range(1, 7)],
)

def test_random_sleep(self) -> None:
for min_, max_ in (
(1, 20),
Expand Down Expand Up @@ -427,9 +438,6 @@ def test_exponential_with_min_wait_andmax__wait(self) -> None:
self.assertEqual(r.wait(make_retry_state(9, 0)), 100)
self.assertEqual(r.wait(make_retry_state(20, 0)), 100)

def test_legacy_explicit_wait_type(self) -> None:
Retrying(wait="exponential_sleep") # type: ignore[arg-type]

def test_wait_func(self) -> None:
def wait_func(retry_state: RetryCallState) -> typing.Any:
return retry_state.attempt_number * retry_state.seconds_since_start # type: ignore[operator]
Expand Down Expand Up @@ -1570,12 +1578,18 @@ def test_retry_function_attributes(self) -> None:
- retry object statistics are synced with function statistics
"""

self.assertTrue(_retryable_test_with_stop(NoneReturnUntilAfterCount(2)))
with (
mock.patch.object(
_retryable_test_with_stop.retry, "wait", tenacity.wait_fixed(0.25)
),
mock.patch.object(_retryable_test_with_stop.retry, "sleep"),
):
self.assertTrue(_retryable_test_with_stop(NoneReturnUntilAfterCount(2)))

expected_stats = {
"attempt_number": 3,
"delay_since_first_attempt": mock.ANY,
"idle_for": mock.ANY,
"idle_for": 0.5,
"start_time": mock.ANY,
}
self.assertEqual(_retryable_test_with_stop.statistics, expected_stats)
Expand All @@ -1592,7 +1606,7 @@ def test_retry_function_attributes(self) -> None:
expected_stats = {
"attempt_number": 1,
"delay_since_first_attempt": mock.ANY,
"idle_for": mock.ANY,
"idle_for": 0,
"start_time": mock.ANY,
}
self.assertEqual(_retryable_test_with_stop.statistics, expected_stats)
Expand Down
6 changes: 5 additions & 1 deletion tests/test_tornado.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,11 @@ def test_stop_after_attempt(self) -> Generator[Any, Any, None]:
assert thing.counter == 2

def test_repr(self) -> None:
repr(tornadoweb.TornadoRetrying())
retrying = tornadoweb.TornadoRetrying()
result = repr(retrying)
assert result.startswith("<TornadoRetrying object at 0x")
assert f"sleep={retrying.sleep}, " in result
assert result.endswith("name=None)>")

def test_old_tornado(self) -> None:
old_attr = gen.is_coroutine_function
Expand Down
Loading