22# does add tests for a few functions which have been determined to be more
33# portable than they had been thought to be.
44
5+ import asyncio
56import codecs
67import contextlib
78import decimal
2324import sys
2425import sysconfig
2526import tempfile
26- import threading
2727import time
2828import types
2929import unittest
3333from test .support import import_helper
3434from test .support import os_helper
3535from test .support import socket_helper
36- from test .support import threading_helper
3736from test .support import warnings_helper
3837from platform import win32_is_iot
3938
40- with warnings .catch_warnings ():
41- warnings .simplefilter ('ignore' , DeprecationWarning )
42- import asynchat
43- import asyncore
44-
4539try :
4640 import resource
4741except ImportError :
@@ -101,6 +95,10 @@ def create_file(filename, content=b'content'):
10195 'on AIX, splice() only accepts sockets' )
10296
10397
98+ def tearDownModule ():
99+ asyncio .set_event_loop_policy (None )
100+
101+
104102class MiscTests (unittest .TestCase ):
105103 def test_getcwd (self ):
106104 cwd = os .getcwd ()
@@ -3228,94 +3226,8 @@ def test_set_get_priority(self):
32283226 raise
32293227
32303228
3231- class SendfileTestServer (asyncore .dispatcher , threading .Thread ):
3232-
3233- class Handler (asynchat .async_chat ):
3234-
3235- def __init__ (self , conn ):
3236- asynchat .async_chat .__init__ (self , conn )
3237- self .in_buffer = []
3238- self .accumulate = True
3239- self .closed = False
3240- self .push (b"220 ready\r \n " )
3241-
3242- def handle_read (self ):
3243- data = self .recv (4096 )
3244- if self .accumulate :
3245- self .in_buffer .append (data )
3246-
3247- def get_data (self ):
3248- return b'' .join (self .in_buffer )
3249-
3250- def handle_close (self ):
3251- self .close ()
3252- self .closed = True
3253-
3254- def handle_error (self ):
3255- raise
3256-
3257- def __init__ (self , address ):
3258- threading .Thread .__init__ (self )
3259- asyncore .dispatcher .__init__ (self )
3260- self .create_socket (socket .AF_INET , socket .SOCK_STREAM )
3261- self .bind (address )
3262- self .listen (5 )
3263- self .host , self .port = self .socket .getsockname ()[:2 ]
3264- self .handler_instance = None
3265- self ._active = False
3266- self ._active_lock = threading .Lock ()
3267-
3268- # --- public API
3269-
3270- @property
3271- def running (self ):
3272- return self ._active
3273-
3274- def start (self ):
3275- assert not self .running
3276- self .__flag = threading .Event ()
3277- threading .Thread .start (self )
3278- self .__flag .wait ()
3279-
3280- def stop (self ):
3281- assert self .running
3282- self ._active = False
3283- self .join ()
3284-
3285- def wait (self ):
3286- # wait for handler connection to be closed, then stop the server
3287- while not getattr (self .handler_instance , "closed" , False ):
3288- time .sleep (0.001 )
3289- self .stop ()
3290-
3291- # --- internals
3292-
3293- def run (self ):
3294- self ._active = True
3295- self .__flag .set ()
3296- while self ._active and asyncore .socket_map :
3297- self ._active_lock .acquire ()
3298- asyncore .loop (timeout = 0.001 , count = 1 )
3299- self ._active_lock .release ()
3300- asyncore .close_all ()
3301-
3302- def handle_accept (self ):
3303- conn , addr = self .accept ()
3304- self .handler_instance = self .Handler (conn )
3305-
3306- def handle_connect (self ):
3307- self .close ()
3308- handle_read = handle_connect
3309-
3310- def writable (self ):
3311- return 0
3312-
3313- def handle_error (self ):
3314- raise
3315-
3316-
33173229@unittest .skipUnless (hasattr (os , 'sendfile' ), "test needs os.sendfile()" )
3318- class TestSendfile (unittest .TestCase ):
3230+ class TestSendfile (unittest .IsolatedAsyncioTestCase ):
33193231
33203232 DATA = b"12345abcde" * 16 * 1024 # 160 KiB
33213233 SUPPORT_HEADERS_TRAILERS = not sys .platform .startswith ("linux" ) and \
@@ -3328,40 +3240,52 @@ class TestSendfile(unittest.TestCase):
33283240
33293241 @classmethod
33303242 def setUpClass (cls ):
3331- cls .key = threading_helper .threading_setup ()
33323243 create_file (os_helper .TESTFN , cls .DATA )
33333244
33343245 @classmethod
33353246 def tearDownClass (cls ):
3336- threading_helper .threading_cleanup (* cls .key )
33373247 os_helper .unlink (os_helper .TESTFN )
33383248
3339- def setUp (self ):
3340- self .server = SendfileTestServer ((socket_helper .HOST , 0 ))
3341- self .server .start ()
3249+ @staticmethod
3250+ async def chunks (reader ):
3251+ while not reader .at_eof ():
3252+ yield await reader .read ()
3253+
3254+ async def handle_new_client (self , reader , writer ):
3255+ self .server_buffer = b'' .join ([x async for x in self .chunks (reader )])
3256+ writer .close ()
3257+ self .server .close () # The test server processes a single client only
3258+
3259+ async def asyncSetUp (self ):
3260+ self .server_buffer = b''
3261+ self .server = await asyncio .start_server (self .handle_new_client ,
3262+ socket_helper .HOSTv4 )
3263+ server_name = self .server .sockets [0 ].getsockname ()
33423264 self .client = socket .socket ()
3343- self .client .connect ((self .server .host , self .server .port ))
3344- self .client .settimeout (1 )
3345- # synchronize by waiting for "220 ready" response
3346- self .client .recv (1024 )
3265+ self .client .setblocking (False )
3266+ await asyncio .get_running_loop ().sock_connect (self .client , server_name )
33473267 self .sockno = self .client .fileno ()
33483268 self .file = open (os_helper .TESTFN , 'rb' )
33493269 self .fileno = self .file .fileno ()
33503270
3351- def tearDown (self ):
3271+ async def asyncTearDown (self ):
33523272 self .file .close ()
33533273 self .client .close ()
3354- if self .server .running :
3355- self .server .stop ()
3356- self .server = None
3274+ await self .server .wait_closed ()
3275+
3276+ # Use the test subject instead of asyncio.loop.sendfile
3277+ @staticmethod
3278+ async def async_sendfile (* args , ** kwargs ):
3279+ return await asyncio .to_thread (os .sendfile , * args , ** kwargs )
33573280
3358- def sendfile_wrapper (self , * args , ** kwargs ):
3281+ @staticmethod
3282+ async def sendfile_wrapper (* args , ** kwargs ):
33593283 """A higher level wrapper representing how an application is
33603284 supposed to use sendfile().
33613285 """
33623286 while True :
33633287 try :
3364- return os . sendfile (* args , ** kwargs )
3288+ return await TestSendfile . async_sendfile (* args , ** kwargs )
33653289 except OSError as err :
33663290 if err .errno == errno .ECONNRESET :
33673291 # disconnected
@@ -3372,13 +3296,14 @@ def sendfile_wrapper(self, *args, **kwargs):
33723296 else :
33733297 raise
33743298
3375- def test_send_whole_file (self ):
3299+ async def test_send_whole_file (self ):
33763300 # normal send
33773301 total_sent = 0
33783302 offset = 0
33793303 nbytes = 4096
33803304 while total_sent < len (self .DATA ):
3381- sent = self .sendfile_wrapper (self .sockno , self .fileno , offset , nbytes )
3305+ sent = await self .sendfile_wrapper (self .sockno , self .fileno ,
3306+ offset , nbytes )
33823307 if sent == 0 :
33833308 break
33843309 offset += sent
@@ -3389,19 +3314,19 @@ def test_send_whole_file(self):
33893314 self .assertEqual (total_sent , len (self .DATA ))
33903315 self .client .shutdown (socket .SHUT_RDWR )
33913316 self .client .close ()
3392- self .server .wait ()
3393- data = self .server .handler_instance .get_data ()
3394- self .assertEqual (len (data ), len (self .DATA ))
3395- self .assertEqual (data , self .DATA )
3317+ await self .server .wait_closed ()
3318+ self .assertEqual (len (self .server_buffer ), len (self .DATA ))
3319+ self .assertEqual (self .server_buffer , self .DATA )
33963320
3397- def test_send_at_certain_offset (self ):
3321+ async def test_send_at_certain_offset (self ):
33983322 # start sending a file at a certain offset
33993323 total_sent = 0
34003324 offset = len (self .DATA ) // 2
34013325 must_send = len (self .DATA ) - offset
34023326 nbytes = 4096
34033327 while total_sent < must_send :
3404- sent = self .sendfile_wrapper (self .sockno , self .fileno , offset , nbytes )
3328+ sent = await self .sendfile_wrapper (self .sockno , self .fileno ,
3329+ offset , nbytes )
34053330 if sent == 0 :
34063331 break
34073332 offset += sent
@@ -3410,18 +3335,18 @@ def test_send_at_certain_offset(self):
34103335
34113336 self .client .shutdown (socket .SHUT_RDWR )
34123337 self .client .close ()
3413- self .server .wait ()
3414- data = self .server .handler_instance .get_data ()
3338+ await self .server .wait_closed ()
34153339 expected = self .DATA [len (self .DATA ) // 2 :]
34163340 self .assertEqual (total_sent , len (expected ))
3417- self .assertEqual (len (data ), len (expected ))
3418- self .assertEqual (data , expected )
3341+ self .assertEqual (len (self . server_buffer ), len (expected ))
3342+ self .assertEqual (self . server_buffer , expected )
34193343
3420- def test_offset_overflow (self ):
3344+ async def test_offset_overflow (self ):
34213345 # specify an offset > file size
34223346 offset = len (self .DATA ) + 4096
34233347 try :
3424- sent = os .sendfile (self .sockno , self .fileno , offset , 4096 )
3348+ sent = await self .async_sendfile (self .sockno , self .fileno ,
3349+ offset , 4096 )
34253350 except OSError as e :
34263351 # Solaris can raise EINVAL if offset >= file length, ignore.
34273352 if e .errno != errno .EINVAL :
@@ -3430,39 +3355,38 @@ def test_offset_overflow(self):
34303355 self .assertEqual (sent , 0 )
34313356 self .client .shutdown (socket .SHUT_RDWR )
34323357 self .client .close ()
3433- self .server .wait ()
3434- data = self .server .handler_instance .get_data ()
3435- self .assertEqual (data , b'' )
3358+ await self .server .wait_closed ()
3359+ self .assertEqual (self .server_buffer , b'' )
34363360
3437- def test_invalid_offset (self ):
3361+ async def test_invalid_offset (self ):
34383362 with self .assertRaises (OSError ) as cm :
3439- os . sendfile (self .sockno , self .fileno , - 1 , 4096 )
3363+ await self . async_sendfile (self .sockno , self .fileno , - 1 , 4096 )
34403364 self .assertEqual (cm .exception .errno , errno .EINVAL )
34413365
3442- def test_keywords (self ):
3366+ async def test_keywords (self ):
34433367 # Keyword arguments should be supported
3444- os . sendfile (out_fd = self .sockno , in_fd = self .fileno ,
3445- offset = 0 , count = 4096 )
3368+ await self . async_sendfile (out_fd = self .sockno , in_fd = self .fileno ,
3369+ offset = 0 , count = 4096 )
34463370 if self .SUPPORT_HEADERS_TRAILERS :
3447- os . sendfile (out_fd = self .sockno , in_fd = self .fileno ,
3448- offset = 0 , count = 4096 ,
3449- headers = (), trailers = (), flags = 0 )
3371+ await self . async_sendfile (out_fd = self .sockno , in_fd = self .fileno ,
3372+ offset = 0 , count = 4096 ,
3373+ headers = (), trailers = (), flags = 0 )
34503374
34513375 # --- headers / trailers tests
34523376
34533377 @requires_headers_trailers
3454- def test_headers (self ):
3378+ async def test_headers (self ):
34553379 total_sent = 0
34563380 expected_data = b"x" * 512 + b"y" * 256 + self .DATA [:- 1 ]
3457- sent = os . sendfile (self .sockno , self .fileno , 0 , 4096 ,
3458- headers = [b"x" * 512 , b"y" * 256 ])
3381+ sent = await self . async_sendfile (self .sockno , self .fileno , 0 , 4096 ,
3382+ headers = [b"x" * 512 , b"y" * 256 ])
34593383 self .assertLessEqual (sent , 512 + 256 + 4096 )
34603384 total_sent += sent
34613385 offset = 4096
34623386 while total_sent < len (expected_data ):
34633387 nbytes = min (len (expected_data ) - total_sent , 4096 )
3464- sent = self .sendfile_wrapper (self .sockno , self .fileno ,
3465- offset , nbytes )
3388+ sent = await self .sendfile_wrapper (self .sockno , self .fileno ,
3389+ offset , nbytes )
34663390 if sent == 0 :
34673391 break
34683392 self .assertLessEqual (sent , nbytes )
@@ -3471,51 +3395,49 @@ def test_headers(self):
34713395
34723396 self .assertEqual (total_sent , len (expected_data ))
34733397 self .client .close ()
3474- self .server .wait ()
3475- data = self .server .handler_instance .get_data ()
3476- self .assertEqual (hash (data ), hash (expected_data ))
3398+ await self .server .wait_closed ()
3399+ self .assertEqual (hash (self .server_buffer ), hash (expected_data ))
34773400
34783401 @requires_headers_trailers
3479- def test_trailers (self ):
3402+ async def test_trailers (self ):
34803403 TESTFN2 = os_helper .TESTFN + "2"
34813404 file_data = b"abcdef"
34823405
34833406 self .addCleanup (os_helper .unlink , TESTFN2 )
34843407 create_file (TESTFN2 , file_data )
34853408
34863409 with open (TESTFN2 , 'rb' ) as f :
3487- os . sendfile (self .sockno , f .fileno (), 0 , 5 ,
3488- trailers = [b"123456" , b"789" ])
3410+ await self . async_sendfile (self .sockno , f .fileno (), 0 , 5 ,
3411+ trailers = [b"123456" , b"789" ])
34893412 self .client .close ()
3490- self .server .wait ()
3491- data = self .server .handler_instance .get_data ()
3492- self .assertEqual (data , b"abcde123456789" )
3413+ await self .server .wait_closed ()
3414+ self .assertEqual (self .server_buffer , b"abcde123456789" )
34933415
34943416 @requires_headers_trailers
34953417 @requires_32b
3496- def test_headers_overflow_32bits (self ):
3418+ async def test_headers_overflow_32bits (self ):
34973419 self .server .handler_instance .accumulate = False
34983420 with self .assertRaises (OSError ) as cm :
3499- os . sendfile (self .sockno , self .fileno , 0 , 0 ,
3500- headers = [b"x" * 2 ** 16 ] * 2 ** 15 )
3421+ await self . async_sendfile (self .sockno , self .fileno , 0 , 0 ,
3422+ headers = [b"x" * 2 ** 16 ] * 2 ** 15 )
35013423 self .assertEqual (cm .exception .errno , errno .EINVAL )
35023424
35033425 @requires_headers_trailers
35043426 @requires_32b
3505- def test_trailers_overflow_32bits (self ):
3427+ async def test_trailers_overflow_32bits (self ):
35063428 self .server .handler_instance .accumulate = False
35073429 with self .assertRaises (OSError ) as cm :
3508- os . sendfile (self .sockno , self .fileno , 0 , 0 ,
3509- trailers = [b"x" * 2 ** 16 ] * 2 ** 15 )
3430+ await self . async_sendfile (self .sockno , self .fileno , 0 , 0 ,
3431+ trailers = [b"x" * 2 ** 16 ] * 2 ** 15 )
35103432 self .assertEqual (cm .exception .errno , errno .EINVAL )
35113433
35123434 @requires_headers_trailers
35133435 @unittest .skipUnless (hasattr (os , 'SF_NODISKIO' ),
35143436 'test needs os.SF_NODISKIO' )
3515- def test_flags (self ):
3437+ async def test_flags (self ):
35163438 try :
3517- os . sendfile (self .sockno , self .fileno , 0 , 4096 ,
3518- flags = os .SF_NODISKIO )
3439+ await self . async_sendfile (self .sockno , self .fileno , 0 , 4096 ,
3440+ flags = os .SF_NODISKIO )
35193441 except OSError as err :
35203442 if err .errno not in (errno .EBUSY , errno .EAGAIN ):
35213443 raise
0 commit comments