@@ -150,6 +150,28 @@ 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+ SIX_A = (socket .AF_INET6 , 0 , 0 , '' , ('2001:db8::1' , 1 ))
155+ SIX_B = (socket .AF_INET6 , 0 , 0 , '' , ('2001:db8::2' , 2 ))
156+ SIX_C = (socket .AF_INET6 , 0 , 0 , '' , ('2001:db8::3' , 3 ))
157+ SIX_D = (socket .AF_INET6 , 0 , 0 , '' , ('2001:db8::4' , 4 ))
158+ FOUR_A = (socket .AF_INET , 0 , 0 , '' , ('192.0.2.1' , 5 ))
159+ FOUR_B = (socket .AF_INET , 0 , 0 , '' , ('192.0.2.2' , 6 ))
160+ FOUR_C = (socket .AF_INET , 0 , 0 , '' , ('192.0.2.3' , 7 ))
161+ FOUR_D = (socket .AF_INET , 0 , 0 , '' , ('192.0.2.4' , 8 ))
162+
163+ addrinfos = [SIX_A , SIX_B , SIX_C , FOUR_D , FOUR_A , FOUR_B , FOUR_C , SIX_D ]
164+ expected = [SIX_A , FOUR_A , SIX_B , FOUR_B , SIX_C , FOUR_C , SIX_D , FOUR_D ]
165+
166+ self .assertEqual (expected , base_events ._interleave_addrinfos (addrinfos ))
167+
168+ expected_fafc_2 = [SIX_A , SIX_B , FOUR_A , SIX_C , FOUR_B , SIX_D , FOUR_C , FOUR_D ]
169+ self .assertEqual (
170+ expected_fafc_2 ,
171+ base_events ._interleave_addrinfos (addrinfos , first_address_family_count = 2 ),
172+ )
173+
174+
153175
154176class BaseEventLoopTests (test_utils .TestCase ):
155177
@@ -1053,6 +1075,66 @@ def test_asyncgen_finalization_by_gc_in_other_thread(self):
10531075 test_utils .run_briefly (self .loop )
10541076 self .assertTrue (status ['finalized' ])
10551077
1078+ @unittest .skipUnless (socket_helper .IPV6_ENABLED , 'no IPv6 support' )
1079+ @patch_socket
1080+ def test_create_connection_happy_eyeballs (self , m_socket ):
1081+
1082+ class MyProto (asyncio .Protocol ):
1083+ pass
1084+
1085+ async def getaddrinfo (* args , ** kw ):
1086+ return [(socket .AF_INET6 , 0 , 0 , '' , ('2001:db8::1' , 1 )),
1087+ (socket .AF_INET , 0 , 0 , '' , ('192.0.2.1' , 5 ))]
1088+
1089+ async def sock_connect (sock , address ):
1090+ if address [0 ] == '2001:db8::1' :
1091+ await asyncio .sleep (1 )
1092+ sock .connect (address )
1093+
1094+ self .loop ._add_reader = mock .Mock ()
1095+ self .loop ._add_writer = mock .Mock ()
1096+ self .loop .getaddrinfo = getaddrinfo
1097+ self .loop .sock_connect = sock_connect
1098+
1099+ coro = self .loop .create_connection (MyProto , 'example.com' , 80 , happy_eyeballs_delay = 0.3 )
1100+ transport , protocol = self .loop .run_until_complete (coro )
1101+ try :
1102+ sock = transport ._sock
1103+ sock .connect .assert_called_with (('192.0.2.1' , 5 ))
1104+ finally :
1105+ transport .close ()
1106+ test_utils .run_briefly (self .loop ) # allow transport to close
1107+
1108+ @patch_socket
1109+ def test_create_connection_happy_eyeballs_ipv4_only (self , m_socket ):
1110+
1111+ class MyProto (asyncio .Protocol ):
1112+ pass
1113+
1114+ async def getaddrinfo (* args , ** kw ):
1115+ return [(socket .AF_INET , 0 , 0 , '' , ('192.0.2.1' , 5 )),
1116+ (socket .AF_INET , 0 , 0 , '' , ('192.0.2.2' , 6 ))]
1117+
1118+ async def sock_connect (sock , address ):
1119+ if address [0 ] == '192.0.2.1' :
1120+ await asyncio .sleep (1 )
1121+ sock .connect (address )
1122+
1123+ self .loop ._add_reader = mock .Mock ()
1124+ self .loop ._add_writer = mock .Mock ()
1125+ self .loop .getaddrinfo = getaddrinfo
1126+ self .loop .sock_connect = sock_connect
1127+
1128+ coro = self .loop .create_connection (MyProto , 'example.com' , 80 , happy_eyeballs_delay = 0.3 )
1129+ transport , protocol = self .loop .run_until_complete (coro )
1130+ try :
1131+ sock = transport ._sock
1132+ sock .connect .assert_called_with (('192.0.2.2' , 6 ))
1133+ finally :
1134+ transport .close ()
1135+ test_utils .run_briefly (self .loop ) # allow transport to close
1136+
1137+
10561138
10571139class MyProto (asyncio .Protocol ):
10581140 done = None
0 commit comments