mirror of
https://github.com/python/cpython.git
synced 2025-07-12 13:55:34 +00:00

Try to clean up the socket file we create so we don't add unused noise to the file system.
264 lines
7.9 KiB
Python
264 lines
7.9 KiB
Python
import asyncio
|
|
import os
|
|
import socket
|
|
import time
|
|
import threading
|
|
import unittest
|
|
|
|
from test.support import socket_helper
|
|
from test.test_asyncio import utils as test_utils
|
|
from test.test_asyncio import functional as func_tests
|
|
|
|
|
|
def tearDownModule():
|
|
asyncio.set_event_loop_policy(None)
|
|
|
|
|
|
class BaseStartServer(func_tests.FunctionalTestCaseMixin):
|
|
|
|
def new_loop(self):
|
|
raise NotImplementedError
|
|
|
|
def test_start_server_1(self):
|
|
HELLO_MSG = b'1' * 1024 * 5 + b'\n'
|
|
|
|
def client(sock, addr):
|
|
for i in range(10):
|
|
time.sleep(0.2)
|
|
if srv.is_serving():
|
|
break
|
|
else:
|
|
raise RuntimeError
|
|
|
|
sock.settimeout(2)
|
|
sock.connect(addr)
|
|
sock.send(HELLO_MSG)
|
|
sock.recv_all(1)
|
|
sock.close()
|
|
|
|
async def serve(reader, writer):
|
|
await reader.readline()
|
|
main_task.cancel()
|
|
writer.write(b'1')
|
|
writer.close()
|
|
await writer.wait_closed()
|
|
|
|
async def main(srv):
|
|
async with srv:
|
|
await srv.serve_forever()
|
|
|
|
srv = self.loop.run_until_complete(asyncio.start_server(
|
|
serve, socket_helper.HOSTv4, 0, start_serving=False))
|
|
|
|
self.assertFalse(srv.is_serving())
|
|
|
|
main_task = self.loop.create_task(main(srv))
|
|
|
|
addr = srv.sockets[0].getsockname()
|
|
with self.assertRaises(asyncio.CancelledError):
|
|
with self.tcp_client(lambda sock: client(sock, addr)):
|
|
self.loop.run_until_complete(main_task)
|
|
|
|
self.assertEqual(srv.sockets, ())
|
|
|
|
self.assertIsNone(srv._sockets)
|
|
self.assertIsNone(srv._waiters)
|
|
self.assertFalse(srv.is_serving())
|
|
|
|
with self.assertRaisesRegex(RuntimeError, r'is closed'):
|
|
self.loop.run_until_complete(srv.serve_forever())
|
|
|
|
|
|
class SelectorStartServerTests(BaseStartServer, unittest.TestCase):
|
|
|
|
def new_loop(self):
|
|
return asyncio.SelectorEventLoop()
|
|
|
|
@socket_helper.skip_unless_bind_unix_socket
|
|
def test_start_unix_server_1(self):
|
|
HELLO_MSG = b'1' * 1024 * 5 + b'\n'
|
|
started = threading.Event()
|
|
|
|
def client(sock, addr):
|
|
sock.settimeout(2)
|
|
started.wait(5)
|
|
sock.connect(addr)
|
|
sock.send(HELLO_MSG)
|
|
sock.recv_all(1)
|
|
sock.close()
|
|
|
|
async def serve(reader, writer):
|
|
await reader.readline()
|
|
main_task.cancel()
|
|
writer.write(b'1')
|
|
writer.close()
|
|
await writer.wait_closed()
|
|
|
|
async def main(srv):
|
|
async with srv:
|
|
self.assertFalse(srv.is_serving())
|
|
await srv.start_serving()
|
|
self.assertTrue(srv.is_serving())
|
|
started.set()
|
|
await srv.serve_forever()
|
|
|
|
with test_utils.unix_socket_path() as addr:
|
|
srv = self.loop.run_until_complete(asyncio.start_unix_server(
|
|
serve, addr, start_serving=False))
|
|
|
|
main_task = self.loop.create_task(main(srv))
|
|
|
|
with self.assertRaises(asyncio.CancelledError):
|
|
with self.unix_client(lambda sock: client(sock, addr)):
|
|
self.loop.run_until_complete(main_task)
|
|
|
|
self.assertEqual(srv.sockets, ())
|
|
|
|
self.assertIsNone(srv._sockets)
|
|
self.assertIsNone(srv._waiters)
|
|
self.assertFalse(srv.is_serving())
|
|
|
|
with self.assertRaisesRegex(RuntimeError, r'is closed'):
|
|
self.loop.run_until_complete(srv.serve_forever())
|
|
|
|
|
|
class TestServer2(unittest.IsolatedAsyncioTestCase):
|
|
|
|
async def test_wait_closed_basic(self):
|
|
async def serve(*args):
|
|
pass
|
|
|
|
srv = await asyncio.start_server(serve, socket_helper.HOSTv4, 0)
|
|
self.addCleanup(srv.close)
|
|
|
|
# active count = 0, not closed: should block
|
|
task1 = asyncio.create_task(srv.wait_closed())
|
|
await asyncio.sleep(0)
|
|
self.assertFalse(task1.done())
|
|
|
|
# active count != 0, not closed: should block
|
|
srv._attach()
|
|
task2 = asyncio.create_task(srv.wait_closed())
|
|
await asyncio.sleep(0)
|
|
self.assertFalse(task1.done())
|
|
self.assertFalse(task2.done())
|
|
|
|
srv.close()
|
|
await asyncio.sleep(0)
|
|
# active count != 0, closed: should block
|
|
task3 = asyncio.create_task(srv.wait_closed())
|
|
await asyncio.sleep(0)
|
|
self.assertFalse(task1.done())
|
|
self.assertFalse(task2.done())
|
|
self.assertFalse(task3.done())
|
|
|
|
srv._detach()
|
|
# active count == 0, closed: should unblock
|
|
await task1
|
|
await task2
|
|
await task3
|
|
await srv.wait_closed() # Return immediately
|
|
|
|
async def test_wait_closed_race(self):
|
|
# Test a regression in 3.12.0, should be fixed in 3.12.1
|
|
async def serve(*args):
|
|
pass
|
|
|
|
srv = await asyncio.start_server(serve, socket_helper.HOSTv4, 0)
|
|
self.addCleanup(srv.close)
|
|
|
|
task = asyncio.create_task(srv.wait_closed())
|
|
await asyncio.sleep(0)
|
|
self.assertFalse(task.done())
|
|
srv._attach()
|
|
loop = asyncio.get_running_loop()
|
|
loop.call_soon(srv.close)
|
|
loop.call_soon(srv._detach)
|
|
await srv.wait_closed()
|
|
|
|
|
|
|
|
|
|
# Test the various corner cases of Unix server socket removal
|
|
class UnixServerCleanupTests(unittest.IsolatedAsyncioTestCase):
|
|
@socket_helper.skip_unless_bind_unix_socket
|
|
async def test_unix_server_addr_cleanup(self):
|
|
# Default scenario
|
|
with test_utils.unix_socket_path() as addr:
|
|
async def serve(*args):
|
|
pass
|
|
|
|
srv = await asyncio.start_unix_server(serve, addr)
|
|
|
|
srv.close()
|
|
self.assertFalse(os.path.exists(addr))
|
|
|
|
@socket_helper.skip_unless_bind_unix_socket
|
|
async def test_unix_server_sock_cleanup(self):
|
|
# Using already bound socket
|
|
with test_utils.unix_socket_path() as addr:
|
|
async def serve(*args):
|
|
pass
|
|
|
|
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
sock.bind(addr)
|
|
|
|
srv = await asyncio.start_unix_server(serve, sock=sock)
|
|
|
|
srv.close()
|
|
self.assertFalse(os.path.exists(addr))
|
|
|
|
@socket_helper.skip_unless_bind_unix_socket
|
|
async def test_unix_server_cleanup_gone(self):
|
|
# Someone else has already cleaned up the socket
|
|
with test_utils.unix_socket_path() as addr:
|
|
async def serve(*args):
|
|
pass
|
|
|
|
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
sock.bind(addr)
|
|
|
|
srv = await asyncio.start_unix_server(serve, sock=sock)
|
|
|
|
os.unlink(addr)
|
|
|
|
srv.close()
|
|
|
|
@socket_helper.skip_unless_bind_unix_socket
|
|
async def test_unix_server_cleanup_replaced(self):
|
|
# Someone else has replaced the socket with their own
|
|
with test_utils.unix_socket_path() as addr:
|
|
async def serve(*args):
|
|
pass
|
|
|
|
srv = await asyncio.start_unix_server(serve, addr)
|
|
|
|
os.unlink(addr)
|
|
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
sock.bind(addr)
|
|
|
|
srv.close()
|
|
self.assertTrue(os.path.exists(addr))
|
|
|
|
@socket_helper.skip_unless_bind_unix_socket
|
|
async def test_unix_server_cleanup_prevented(self):
|
|
# Automatic cleanup explicitly disabled
|
|
with test_utils.unix_socket_path() as addr:
|
|
async def serve(*args):
|
|
pass
|
|
|
|
srv = await asyncio.start_unix_server(serve, addr, cleanup_socket=False)
|
|
|
|
srv.close()
|
|
self.assertTrue(os.path.exists(addr))
|
|
|
|
|
|
@unittest.skipUnless(hasattr(asyncio, 'ProactorEventLoop'), 'Windows only')
|
|
class ProactorStartServerTests(BaseStartServer, unittest.TestCase):
|
|
|
|
def new_loop(self):
|
|
return asyncio.ProactorEventLoop()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|