]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-30064: Properly skip unstable loop.sock_connect() racing test (GH-20494)
authorFantix King <fantix.king@gmail.com>
Thu, 28 May 2020 21:56:42 +0000 (16:56 -0500)
committerGitHub <noreply@github.com>
Thu, 28 May 2020 21:56:42 +0000 (14:56 -0700)
Lib/test/test_asyncio/test_sock_lowlevel.py

index e0583c041956411013e41c89f335caf791d0394e..2c8ce6b657c14abe6bdb397e38a64d00a05835ef 100644 (file)
@@ -202,6 +202,14 @@ class BaseSockTestsMixin:
             # 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()
@@ -212,30 +220,26 @@ class BaseSockTestsMixin:
         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()
@@ -251,6 +255,8 @@ class BaseSockTestsMixin:
         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: