@@ -150,6 +150,29 @@ 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
+ 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
+
153
176
154
177
class BaseEventLoopTests (test_utils .TestCase ):
155
178
@@ -1053,6 +1076,71 @@ def test_asyncgen_finalization_by_gc_in_other_thread(self):
1053
1076
test_utils .run_briefly (self .loop )
1054
1077
self .assertTrue (status ['finalized' ])
1055
1078
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
+
1056
1144
1057
1145
class MyProto (asyncio .Protocol ):
1058
1146
done = None
0 commit comments