bpo-30064: Properly skip unstable loop.sock_connect() racing test (GH… · python/cpython@6637bd4
@@ -202,6 +202,14 @@ async def recv_until():
202202# ProactorEventLoop could deliver hello
203203self.assertTrue(data.endswith(b'world'))
204204205+# After the first connect attempt before the listener is ready,
206+# the socket needs time to "recover" to make the next connect call.
207+# On Linux, a second retry will do. On Windows, the waiting time is
208+# unpredictable; and on FreeBSD the socket may never come back
209+# because it's a loopback address. Here we'll just retry for a few
210+# times, and have to skip the test if it's not working. See also:
211+# https://stackoverflow.com/a/54437602/3316267
212+# https://lists.freebsd.org/pipermail/freebsd-current/2005-May/049876.html
205213async def _basetest_sock_connect_racing(self, listener, sock):
206214listener.bind(('127.0.0.1', 0))
207215addr = listener.getsockname()
@@ -212,30 +220,26 @@ async def _basetest_sock_connect_racing(self, listener, sock):
212220task.cancel()
213221214222listener.listen(1)
215-i = 0
216-while True:
223+224+skip_reason = "Max retries reached"
225+for i in range(128):
217226try:
218227await self.loop.sock_connect(sock, addr)
219-break
220-except ConnectionRefusedError: # on Linux we need another retry
221-await self.loop.sock_connect(sock, addr)
222-break
223-except OSError as e: # on Windows we need more retries
224-# A connect request was made on an already connected socket
225-if getattr(e, 'winerror', 0) == 10056:
226-break
228+except ConnectionRefusedError as e:
229+skip_reason = e
230+except OSError as e:
231+skip_reason = e
227232228-# https://stackoverflow.com/a/54437602/3316267
233+# Retry only for this error:
234+# [WinError 10022] An invalid argument was supplied
229235if getattr(e, 'winerror', 0) != 10022:
230-raise
231-i += 1
232-if i >= 128:
233-raise # too many retries
234-# avoid touching event loop to maintain race condition
235-time.sleep(0.01)
236-237-# FIXME: https://bugs.python.org/issue30064#msg370143
238-@unittest.skipIf(True, "unstable test")
236+break
237+else:
238+# success
239+return
240+241+self.skipTest(skip_reason)
242+239243def test_sock_client_racing(self):
240244with test_utils.run_test_server() as httpd:
241245sock = socket.socket()
@@ -251,6 +255,8 @@ def test_sock_client_racing(self):
251255with listener, sock:
252256self.loop.run_until_complete(asyncio.wait_for(
253257self._basetest_sock_send_racing(listener, sock), 10))
258+259+def test_sock_client_connect_racing(self):
254260listener = socket.socket()
255261sock = socket.socket()
256262with listener, sock: