]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
GH-79033: Fix asyncio.Server.wait_closed() (#98582)
authorGuido van Rossum <guido@python.org>
Thu, 24 Nov 2022 15:32:58 +0000 (07:32 -0800)
committerGitHub <noreply@github.com>
Thu, 24 Nov 2022 15:32:58 +0000 (08:32 -0700)
It was a no-op when used as recommended (after close()).

I had to debug one test (test__sock_sendfile_native_failure) --
the cleanup sequence for the test fixture was botched.

Hopefully that's not a portend of problems in user code --
this has never worked so people may well be doing this wrong. :-(

Co-authored-by: kumar aditya
Lib/asyncio/base_events.py
Lib/test/test_asyncio/test_base_events.py
Lib/test/test_asyncio/test_server.py
Misc/NEWS.d/next/Library/2022-11-22-19-31-26.gh-issue-79033.MW6kHq.rst [new file with mode: 0644]

index 91d32e3939dcd36854e7c046cfe8a7caf73085de..f2f93758c3a817ecb15ac619b50045761068fcb4 100644 (file)
@@ -377,7 +377,7 @@ class Server(events.AbstractServer):
             self._serving_forever_fut = None
 
     async def wait_closed(self):
-        if self._sockets is None or self._waiters is None:
+        if self._waiters is None or self._active_count == 0:
             return
         waiter = self._loop.create_future()
         self._waiters.append(waiter)
index 2dcb20c1cec7f96852f59f012e32371d4f655ac7..7421d18dc636c8adaad5985365c5e6c1138bb444 100644 (file)
@@ -2052,11 +2052,11 @@ class BaseLoopSockSendfileTests(test_utils.TestCase):
 
         def cleanup():
             server.close()
-            self.run_loop(server.wait_closed())
             sock.close()
             if proto.transport is not None:
                 proto.transport.close()
                 self.run_loop(proto.wait_closed())
+            self.run_loop(server.wait_closed())
 
         self.addCleanup(cleanup)
 
index 860d62d52ef1eaebd56a19fdaa57ccd7a8d7ff2f..06d8b60f219f1a3f41e9305e3a089ce5c592b1fd 100644 (file)
@@ -120,6 +120,33 @@ class SelectorStartServerTests(BaseStartServer, unittest.TestCase):
                 self.loop.run_until_complete(srv.serve_forever())
 
 
+class TestServer2(unittest.IsolatedAsyncioTestCase):
+
+    async def test_wait_closed(self):
+        async def serve(*args):
+            pass
+
+        srv = await asyncio.start_server(serve, socket_helper.HOSTv4, 0)
+
+        # active count = 0
+        task1 = asyncio.create_task(srv.wait_closed())
+        await asyncio.sleep(0)
+        self.assertTrue(task1.done())
+
+        # active count != 0
+        srv._attach()
+        task2 = asyncio.create_task(srv.wait_closed())
+        await asyncio.sleep(0)
+        self.assertFalse(task2.done())
+
+        srv.close()
+        await asyncio.sleep(0)
+        self.assertFalse(task2.done())
+
+        srv._detach()
+        await task2
+
+
 @unittest.skipUnless(hasattr(asyncio, 'ProactorEventLoop'), 'Windows only')
 class ProactorStartServerTests(BaseStartServer, unittest.TestCase):
 
diff --git a/Misc/NEWS.d/next/Library/2022-11-22-19-31-26.gh-issue-79033.MW6kHq.rst b/Misc/NEWS.d/next/Library/2022-11-22-19-31-26.gh-issue-79033.MW6kHq.rst
new file mode 100644 (file)
index 0000000..4b12fd9
--- /dev/null
@@ -0,0 +1 @@
+Fix :func:`asyncio.Server.wait_closed` to actually do what the docs promise -- wait for all existing connections to complete, after closing the server.