@@ -150,6 +150,29 @@ def test_ipaddr_info_no_inet_pton(self, m_socket):
150150 socket .SOCK_STREAM ,
151151 socket .IPPROTO_TCP ))
152152
153+ def test_interleave_addrinfos (self ):
154+ self .maxDiff = None
155+ SIX_A = (socket .AF_INET6 , 0 , 0 , '' , ('2001:db8::1' , 1 ))
156+ SIX_B = (socket .AF_INET6 , 0 , 0 , '' , ('2001:db8::2' , 2 ))
157+ SIX_C = (socket .AF_INET6 , 0 , 0 , '' , ('2001:db8::3' , 3 ))
158+ SIX_D = (socket .AF_INET6 , 0 , 0 , '' , ('2001:db8::4' , 4 ))
159+ FOUR_A = (socket .AF_INET , 0 , 0 , '' , ('192.0.2.1' , 5 ))
160+ FOUR_B = (socket .AF_INET , 0 , 0 , '' , ('192.0.2.2' , 6 ))
161+ FOUR_C = (socket .AF_INET , 0 , 0 , '' , ('192.0.2.3' , 7 ))
162+ FOUR_D = (socket .AF_INET , 0 , 0 , '' , ('192.0.2.4' , 8 ))
163+
164+ addrinfos = [SIX_A , SIX_B , SIX_C , FOUR_A , FOUR_B , FOUR_C , FOUR_D , SIX_D ]
165+ expected = [SIX_A , FOUR_A , SIX_B , FOUR_B , SIX_C , FOUR_C , SIX_D , FOUR_D ]
166+
167+ self .assertEqual (expected , base_events ._interleave_addrinfos (addrinfos ))
168+
169+ expected_fafc_2 = [SIX_A , SIX_B , FOUR_A , SIX_C , FOUR_B , SIX_D , FOUR_C , FOUR_D ]
170+ self .assertEqual (
171+ expected_fafc_2 ,
172+ base_events ._interleave_addrinfos (addrinfos , first_address_family_count = 2 ),
173+ )
174+
175+
153176
154177class BaseEventLoopTests (test_utils .TestCase ):
155178
@@ -1053,6 +1076,71 @@ def test_asyncgen_finalization_by_gc_in_other_thread(self):
10531076 test_utils .run_briefly (self .loop )
10541077 self .assertTrue (status ['finalized' ])
10551078
1079+ @unittest .skipUnless (socket_helper .IPV6_ENABLED , 'no IPv6 support' )
1080+ @patch_socket
1081+ def test_create_connection_happy_eyeballs (self , m_socket ):
1082+
1083+ class MyProto (asyncio .Protocol ):
1084+ pass
1085+
1086+ async def getaddrinfo (* args , ** kw ):
1087+ return [(socket .AF_INET6 , 0 , 0 , '' , ('2001:db8::1' , 1 )),
1088+ (socket .AF_INET , 0 , 0 , '' , ('192.0.2.1' , 5 ))]
1089+
1090+ async def sock_connect (sock , address ):
1091+ if address [0 ] == '2001:db8::1' :
1092+ await asyncio .sleep (1 )
1093+ sock .connect (address )
1094+
1095+ loop = asyncio .new_event_loop ()
1096+ loop ._add_writer = mock .Mock ()
1097+ loop ._add_writer = mock .Mock ()
1098+ loop ._add_reader = mock .Mock ()
1099+ loop .getaddrinfo = getaddrinfo
1100+ loop .sock_connect = sock_connect
1101+
1102+ coro = loop .create_connection (MyProto , 'example.com' , 80 , happy_eyeballs_delay = 0.3 )
1103+ transport , protocol = loop .run_until_complete (coro )
1104+ try :
1105+ sock = transport ._sock
1106+ sock .connect .assert_called_with (('192.0.2.1' , 5 ))
1107+ finally :
1108+ transport .close ()
1109+ test_utils .run_briefly (loop ) # allow transport to close
1110+ loop .close ()
1111+
1112+ @patch_socket
1113+ def test_create_connection_happy_eyeballs_ipv4_only (self , m_socket ):
1114+
1115+ class MyProto (asyncio .Protocol ):
1116+ pass
1117+
1118+ async def getaddrinfo (* args , ** kw ):
1119+ return [(socket .AF_INET , 0 , 0 , '' , ('192.0.2.1' , 5 )),
1120+ (socket .AF_INET , 0 , 0 , '' , ('192.0.2.2' , 6 ))]
1121+
1122+ async def sock_connect (sock , address ):
1123+ if address [0 ] == '192.0.2.1' :
1124+ await asyncio .sleep (1 )
1125+ sock .connect (address )
1126+
1127+ loop = asyncio .new_event_loop ()
1128+ loop ._add_writer = mock .Mock ()
1129+ loop ._add_writer = mock .Mock ()
1130+ loop ._add_reader = mock .Mock ()
1131+ loop .getaddrinfo = getaddrinfo
1132+ loop .sock_connect = sock_connect
1133+
1134+ coro = loop .create_connection (MyProto , 'example.com' , 80 , happy_eyeballs_delay = 0.3 )
1135+ transport , protocol = loop .run_until_complete (coro )
1136+ try :
1137+ sock = transport ._sock
1138+ sock .connect .assert_called_with (('192.0.2.2' , 6 ))
1139+ finally :
1140+ transport .close ()
1141+ test_utils .run_briefly (loop ) # allow transport to close
1142+ loop .close ()
1143+
10561144
10571145class MyProto (asyncio .Protocol ):
10581146 done = None
0 commit comments