Skip to content

Commit e11b531

Browse files
jpbrodrick89claude
andcommitted
fix: rewrite stale-keepalive retry test without real socket dependence
The original integration-style test spun up a real uvicorn server with timeout_keep_alive=0, established a connection, slept 100 ms to give the server time to close the socket, monkeypatched urllib3's is_connected property to lie once, then asserted the resulting ConnectionError caused HTTPClient to retry. The assertion was flaky on Linux + Python 3.14 + latest deps, where either the FIN didn't arrive in 100 ms reliably or newer urllib3 transparently refreshed the stale connection — in both cases the first request succeeded without raising, so HTTPClient's retry never fired and mock.call_count came in at 1 instead of 2. That brittleness is testing real-socket timing and urllib3 internals, not HTTPClient's contract. The contract is just: "if session.request raises ConnectionError, retry once". Inject the ConnectionError at the session layer directly — same assertion, no environment dependence. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 25b6a33 commit e11b531

1 file changed

Lines changed: 23 additions & 65 deletions

File tree

tests/sdk_tests/test_tesseract.py

Lines changed: 23 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from types import SimpleNamespace
2-
from unittest.mock import Mock, patch
2+
from unittest.mock import MagicMock, Mock
33

44
import numpy as np
55
import orjson
@@ -623,77 +623,35 @@ def test_custom_error_type_with_ctx(self):
623623
assert err["loc"] == ("body", "inputs", "a")
624624

625625

626-
def test_stale_keepalive_connection_is_handled(free_port, monkeypatch):
627-
"""HTTPClient retries once when a stale keep-alive connection causes ConnectionError.
626+
def test_stale_keepalive_connection_is_handled(monkeypatch):
627+
"""HTTPClient retries once when session.request raises ConnectionError.
628628
629-
We force a stale connection by setting timeout_keep_alive=0, then monkeypatch
630-
urllib3's is_connected to lie once (simulating the race where the staleness check
631-
passes just before the server's FIN arrives).
629+
Tests the contract directly by injecting a one-shot ConnectionError at the
630+
requests.Session.request layer, avoiding the brittleness of real-socket
631+
timing (which differs across OS / Python version / urllib3 version) that an
632+
integration-style test would depend on.
632633
"""
633-
import threading
634-
import time
635-
636-
import uvicorn
637-
from fastapi import FastAPI
638-
from urllib3.connection import HTTPConnection
639-
640-
app = FastAPI()
641-
app.get("/health")(lambda: {"status": "ok"})
642-
643-
server = uvicorn.Server(
644-
uvicorn.Config(
645-
app,
646-
host="127.0.0.1",
647-
port=free_port,
648-
log_level="error",
649-
timeout_keep_alive=0,
650-
)
651-
)
652-
server_thread = threading.Thread(target=server.run, daemon=True)
653-
server_thread.start()
634+
client = HTTPClient("http://127.0.0.1:1")
654635

655-
url = f"http://127.0.0.1:{free_port}"
656-
for _ in range(50):
657-
try:
658-
requests.get(f"{url}/health", timeout=1)
659-
break
660-
except requests.ConnectionError:
661-
time.sleep(0.1)
662-
else:
663-
pytest.fail("Server did not start in time")
664-
665-
try:
666-
client = HTTPClient(url)
636+
call_count = 0
637+
response = MagicMock()
638+
response.status_code = 200
639+
response.ok = True
640+
response.content = b'{"status": "ok"}'
667641

668-
# Ensure connection is established and in keep-alive pool
669-
client._request("health")
642+
def _fail_once_then_succeed(*args, **kwargs):
643+
nonlocal call_count
644+
call_count += 1
645+
if call_count == 1:
646+
raise requests.ConnectionError("simulated stale keep-alive")
647+
return response
670648

671-
# Sleep to ensure the server has closed the connection due to timeout_keep_alive=0
672-
time.sleep(0.1)
649+
monkeypatch.setattr(client._session, "request", _fail_once_then_succeed)
673650

674-
# Make is_connected lie once (stale socket looks alive), then restore
675-
original = HTTPConnection.is_connected.fget
676-
call_count = 0
651+
result = client._request("health")
677652

678-
def _lie_once(self):
679-
nonlocal call_count
680-
call_count += 1
681-
return True if call_count == 1 else original(self)
682-
683-
monkeypatch.setattr(HTTPConnection, "is_connected", property(_lie_once))
684-
685-
with patch.object(
686-
client._session, "request", wraps=client._session.request
687-
) as mock:
688-
result = client._request("health")
689-
690-
assert result == {"status": "ok"}
691-
692-
# Ensure that the request was retried once after the ConnectionError from the stale connection
693-
assert mock.call_count == 2
694-
finally:
695-
server.should_exit = True
696-
server_thread.join(timeout=5)
653+
assert result == {"status": "ok"}
654+
assert call_count == 2
697655

698656

699657
def test_HTTPClient_timeout_fires(free_port):

0 commit comments

Comments
 (0)