@@ -150,6 +150,28 @@ def test_ipaddr_info_no_inet_pton(self, m_socket):
150
150
socket .SOCK_STREAM ,
151
151
socket .IPPROTO_TCP ))
152
152
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
+
153
175
154
176
class BaseEventLoopTests (test_utils .TestCase ):
155
177
@@ -1053,6 +1075,66 @@ def test_asyncgen_finalization_by_gc_in_other_thread(self):
1053
1075
test_utils .run_briefly (self .loop )
1054
1076
self .assertTrue (status ['finalized' ])
1055
1077
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
+
1056
1138
1057
1139
class MyProto (asyncio .Protocol ):
1058
1140
done = None
0 commit comments