Skip to content

bpo-30064: Properly skip unstable loop.sock_connect() racing test #20494

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 28, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 26 additions & 20 deletions Lib/test/test_asyncio/test_sock_lowlevel.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,14 @@ async def recv_until():
# ProactorEventLoop could deliver hello
self.assertTrue(data.endswith(b'world'))

# After the first connect attempt before the listener is ready,
# the socket needs time to "recover" to make the next connect call.
# On Linux, a second retry will do. On Windows, the waiting time is
# unpredictable; and on FreeBSD the socket may never come back
# because it's a loopback address. Here we'll just retry for a few
# times, and have to skip the test if it's not working. See also:
# https://stackoverflow.com/a/54437602/3316267
# https://lists.freebsd.org/pipermail/freebsd-current/2005-May/049876.html
async def _basetest_sock_connect_racing(self, listener, sock):
listener.bind(('127.0.0.1', 0))
addr = listener.getsockname()
Expand All @@ -212,30 +220,26 @@ async def _basetest_sock_connect_racing(self, listener, sock):
task.cancel()

listener.listen(1)
i = 0
while True:

skip_reason = "Max retries reached"
for i in range(128):
try:
await self.loop.sock_connect(sock, addr)
break
except ConnectionRefusedError: # on Linux we need another retry
await self.loop.sock_connect(sock, addr)
break
except OSError as e: # on Windows we need more retries
# A connect request was made on an already connected socket
if getattr(e, 'winerror', 0) == 10056:
break
except ConnectionRefusedError as e:
skip_reason = e
except OSError as e:
skip_reason = e

# https://stackoverflow.com/a/54437602/3316267
# Retry only for this error:
# [WinError 10022] An invalid argument was supplied
if getattr(e, 'winerror', 0) != 10022:
raise
i += 1
if i >= 128:
raise # too many retries
# avoid touching event loop to maintain race condition
time.sleep(0.01)

# FIXME: https://bugs.python.org/issue30064#msg370143
@unittest.skipIf(True, "unstable test")
break
else:
# success
return

self.skipTest(skip_reason)

def test_sock_client_racing(self):
with test_utils.run_test_server() as httpd:
sock = socket.socket()
Expand All @@ -251,6 +255,8 @@ def test_sock_client_racing(self):
with listener, sock:
self.loop.run_until_complete(asyncio.wait_for(
self._basetest_sock_send_racing(listener, sock), 10))

def test_sock_client_connect_racing(self):
listener = socket.socket()
sock = socket.socket()
with listener, sock:
Expand Down