Skip to content

Commit 9a152dd

Browse files
committed
Add a test on error followed by success
1 parent 7a4ab73 commit 9a152dd

1 file changed

Lines changed: 35 additions & 0 deletions

File tree

tests/test_connection.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import selectors
66
import socket
77
import ssl
8+
import sys
89
import threading
910
import time
1011
import types
@@ -603,6 +604,40 @@ def test_connect_breaks_exception_reference_cycle(self):
603604
assert connect_frame is not None
604605
assert connect_frame.f_locals.get("err") is None
605606

607+
def test_connect_breaks_reference_cycle_when_a_later_address_succeeds(self):
608+
"""
609+
When an address fails but a later one connects, _connect must not
610+
return while still holding the caught exception.
611+
The exception's traceback references the frame, so a retained local
612+
would form a cycle only reclaimable by the GC.
613+
"""
614+
conn = Connection(host="localhost", port=6379)
615+
addr_infos = [
616+
(socket.AF_INET, socket.SOCK_STREAM, 0, "", ("127.0.0.1", 6379)),
617+
(socket.AF_INET, socket.SOCK_STREAM, 0, "", ("127.0.0.2", 6379)),
618+
]
619+
620+
# _connect calls getaddrinfo, so hook that as a way to peek the caller
621+
connect_frames = []
622+
623+
def capturing_getaddrinfo(*args, **kwargs):
624+
connect_frames.append(sys._getframe(1))
625+
return addr_infos
626+
627+
failing_sock, working_sock = MagicMock(), MagicMock()
628+
failing_sock.connect.side_effect = OSError("refused")
629+
630+
with (
631+
patch.object(socket, "getaddrinfo", capturing_getaddrinfo),
632+
patch.object(socket, "socket", side_effect=[failing_sock, working_sock]),
633+
):
634+
assert conn._connect() is working_sock
635+
636+
# Error should be cleared in the connect frame
637+
assert len(connect_frames) == 1
638+
(connect_frame,) = connect_frames
639+
assert connect_frame.f_locals.get("err") is None
640+
606641
@pytest.mark.parametrize(
607642
"connection_kwargs",
608643
[

0 commit comments

Comments
 (0)