mirror of
https://github.com/python/cpython.git
synced 2025-08-04 00:48:58 +00:00
bpo-32622: Native sendfile on windows (#5565)
* Support sendfile on Windows Proactor event loop naively.
This commit is contained in:
parent
5fb632e831
commit
a19fb3c6aa
7 changed files with 431 additions and 93 deletions
|
@ -1,14 +1,18 @@
|
|||
"""Tests for proactor_events.py"""
|
||||
|
||||
import io
|
||||
import socket
|
||||
import unittest
|
||||
import sys
|
||||
from unittest import mock
|
||||
|
||||
import asyncio
|
||||
from asyncio import events
|
||||
from asyncio.proactor_events import BaseProactorEventLoop
|
||||
from asyncio.proactor_events import _ProactorSocketTransport
|
||||
from asyncio.proactor_events import _ProactorWritePipeTransport
|
||||
from asyncio.proactor_events import _ProactorDuplexPipeTransport
|
||||
from test import support
|
||||
from test.test_asyncio import utils as test_utils
|
||||
|
||||
|
||||
|
@ -775,5 +779,117 @@ class BaseProactorEventLoopTests(test_utils.TestCase):
|
|||
self.assertFalse(future2.cancel.called)
|
||||
|
||||
|
||||
@unittest.skipIf(sys.platform != 'win32',
|
||||
'Proactor is supported on Windows only')
|
||||
class ProactorEventLoopUnixSockSendfileTests(test_utils.TestCase):
|
||||
DATA = b"12345abcde" * 16 * 1024 # 160 KiB
|
||||
|
||||
class MyProto(asyncio.Protocol):
|
||||
|
||||
def __init__(self, loop):
|
||||
self.started = False
|
||||
self.closed = False
|
||||
self.data = bytearray()
|
||||
self.fut = loop.create_future()
|
||||
self.transport = None
|
||||
|
||||
def connection_made(self, transport):
|
||||
self.started = True
|
||||
self.transport = transport
|
||||
|
||||
def data_received(self, data):
|
||||
self.data.extend(data)
|
||||
|
||||
def connection_lost(self, exc):
|
||||
self.closed = True
|
||||
self.fut.set_result(None)
|
||||
|
||||
async def wait_closed(self):
|
||||
await self.fut
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
with open(support.TESTFN, 'wb') as fp:
|
||||
fp.write(cls.DATA)
|
||||
super().setUpClass()
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
support.unlink(support.TESTFN)
|
||||
super().tearDownClass()
|
||||
|
||||
def setUp(self):
|
||||
self.loop = asyncio.ProactorEventLoop()
|
||||
self.set_event_loop(self.loop)
|
||||
self.addCleanup(self.loop.close)
|
||||
self.file = open(support.TESTFN, 'rb')
|
||||
self.addCleanup(self.file.close)
|
||||
super().setUp()
|
||||
|
||||
def make_socket(self, cleanup=True):
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock.setblocking(False)
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 1024)
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 1024)
|
||||
if cleanup:
|
||||
self.addCleanup(sock.close)
|
||||
return sock
|
||||
|
||||
def run_loop(self, coro):
|
||||
return self.loop.run_until_complete(coro)
|
||||
|
||||
def prepare(self):
|
||||
sock = self.make_socket()
|
||||
proto = self.MyProto(self.loop)
|
||||
port = support.find_unused_port()
|
||||
srv_sock = self.make_socket(cleanup=False)
|
||||
srv_sock.bind(('127.0.0.1', port))
|
||||
server = self.run_loop(self.loop.create_server(
|
||||
lambda: proto, sock=srv_sock))
|
||||
self.run_loop(self.loop.sock_connect(sock, srv_sock.getsockname()))
|
||||
|
||||
def cleanup():
|
||||
if proto.transport is not None:
|
||||
# can be None if the task was cancelled before
|
||||
# connection_made callback
|
||||
proto.transport.close()
|
||||
self.run_loop(proto.wait_closed())
|
||||
|
||||
server.close()
|
||||
self.run_loop(server.wait_closed())
|
||||
|
||||
self.addCleanup(cleanup)
|
||||
|
||||
return sock, proto
|
||||
|
||||
def test_sock_sendfile_not_a_file(self):
|
||||
sock, proto = self.prepare()
|
||||
f = object()
|
||||
with self.assertRaisesRegex(events.SendfileNotAvailableError,
|
||||
"not a regular file"):
|
||||
self.run_loop(self.loop._sock_sendfile_native(sock, f,
|
||||
0, None))
|
||||
self.assertEqual(self.file.tell(), 0)
|
||||
|
||||
def test_sock_sendfile_iobuffer(self):
|
||||
sock, proto = self.prepare()
|
||||
f = io.BytesIO()
|
||||
with self.assertRaisesRegex(events.SendfileNotAvailableError,
|
||||
"not a regular file"):
|
||||
self.run_loop(self.loop._sock_sendfile_native(sock, f,
|
||||
0, None))
|
||||
self.assertEqual(self.file.tell(), 0)
|
||||
|
||||
def test_sock_sendfile_not_regular_file(self):
|
||||
sock, proto = self.prepare()
|
||||
f = mock.Mock()
|
||||
f.fileno.return_value = -1
|
||||
with self.assertRaisesRegex(events.SendfileNotAvailableError,
|
||||
"not a regular file"):
|
||||
self.run_loop(self.loop._sock_sendfile_native(sock, f,
|
||||
0, None))
|
||||
self.assertEqual(self.file.tell(), 0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue