Skip to content

Commit dc644b9

Browse files
authored
Update test_client.py
1 parent 03684e3 commit dc644b9

1 file changed

Lines changed: 68 additions & 0 deletions

File tree

tests/test_client.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -877,5 +877,73 @@ def iter_lines(self):
877877
c.close()
878878

879879

880+
class TestClientResetHttp(unittest.TestCase):
881+
"""_reset_http replaces the httpx client so a poisoned connection
882+
pool does not doom subsequent requests."""
883+
884+
def test_reset_http_replaces_client(self):
885+
c = make_offline_client()
886+
old = c._http
887+
c._reset_http()
888+
self.assertIsNot(c._http, old)
889+
self.assertFalse(c._http.is_closed)
890+
c.close()
891+
892+
def test_reset_http_closes_old_client(self):
893+
c = make_offline_client()
894+
old = c._http
895+
with mock.patch.object(old, "close") as cl:
896+
c._reset_http()
897+
cl.assert_called_once_with()
898+
c.close()
899+
900+
def test_reset_http_tolerates_close_failure(self):
901+
c = make_offline_client()
902+
old = c._http
903+
with mock.patch.object(old, "close", side_effect=RuntimeError("boom")):
904+
c._reset_http() # must not raise
905+
self.assertIsNot(c._http, old)
906+
c.close()
907+
908+
def test_connection_error_resets_pool_for_next_request(self):
909+
"""After retries exhaust on a connection error, the next chat()
910+
call uses a fresh httpx client (not the poisoned one)."""
911+
from python_agent_harness.client import ApiError
912+
913+
c = make_offline_client(retry_max=2, retry_base_delay=0.01, retry_max_delay=0.01)
914+
# Simulate persistent connection failures
915+
with mock.patch.object(
916+
c._http, "stream", side_effect=httpx.ConnectError("refused")
917+
):
918+
with self.assertRaises(ApiError):
919+
c.chat([Message(role="user", content="hi")])
920+
# After the error, _http must be a fresh (non-poisoned) client
921+
# that was NOT the one we patched
922+
self.assertFalse(c._http.is_closed)
923+
# Verify it's a different object (reset happened)
924+
# The patched mock is on the OLD client; the new one is real
925+
self.assertNotIsInstance(c._http.stream, mock.Mock)
926+
c.close()
927+
928+
def test_cancel_during_backoff_also_resets_pool(self):
929+
"""If cancel_check fires during retry backoff, the pool is
930+
still reset so the next run starts clean."""
931+
from python_agent_harness.client import ApiError
932+
933+
c = make_offline_client(retry_max=3, retry_base_delay=60.0, retry_max_delay=60.0)
934+
old_http = c._http
935+
with mock.patch.object(
936+
c._http, "stream", side_effect=httpx.ConnectError("refused")
937+
):
938+
with self.assertRaises(ApiError):
939+
c.chat(
940+
[Message(role="user", content="hi")],
941+
cancel_check=lambda: True,
942+
)
943+
self.assertIsNot(c._http, old_http)
944+
self.assertFalse(c._http.is_closed)
945+
c.close()
946+
947+
880948
if __name__ == "__main__":
881949
unittest.main()

0 commit comments

Comments
 (0)