@@ -3637,97 +3637,8 @@ def test_set_get_priority(self):
3637
3637
self .assertEqual (new_prio , base + 1 )
3638
3638
3639
3639
3640
- import asyncore
3641
- import asynchat
3642
- import threading
3643
- class SendfileTestServer (asyncore .dispatcher , threading .Thread ):
3644
-
3645
- class Handler (asynchat .async_chat ):
3646
-
3647
- def __init__ (self , conn ):
3648
- asynchat .async_chat .__init__ (self , conn )
3649
- self .in_buffer = []
3650
- self .accumulate = True
3651
- self .closed = False
3652
- self .push (b"220 ready\r \n " )
3653
-
3654
- def handle_read (self ):
3655
- data = self .recv (4096 )
3656
- if self .accumulate :
3657
- self .in_buffer .append (data )
3658
-
3659
- def get_data (self ):
3660
- return b'' .join (self .in_buffer )
3661
-
3662
- def handle_close (self ):
3663
- self .close ()
3664
- self .closed = True
3665
-
3666
- def handle_error (self ):
3667
- raise
3668
-
3669
- def __init__ (self , address ):
3670
- threading .Thread .__init__ (self )
3671
- asyncore .dispatcher .__init__ (self )
3672
- self .create_socket (socket .AF_INET , socket .SOCK_STREAM )
3673
- self .bind (address )
3674
- self .listen (5 )
3675
- self .host , self .port = self .socket .getsockname ()[:2 ]
3676
- self .handler_instance = None
3677
- self ._active = False
3678
- self ._active_lock = threading .Lock ()
3679
-
3680
- # --- public API
3681
-
3682
- @property
3683
- def running (self ):
3684
- return self ._active
3685
-
3686
- def start (self ):
3687
- assert not self .running
3688
- self .__flag = threading .Event ()
3689
- threading .Thread .start (self )
3690
- self .__flag .wait ()
3691
-
3692
- def stop (self ):
3693
- assert self .running
3694
- self ._active = False
3695
- self .join ()
3696
-
3697
- def wait (self ):
3698
- # wait for handler connection to be closed, then stop the server
3699
- while not getattr (self .handler_instance , "closed" , False ):
3700
- time .sleep (0.001 )
3701
- self .stop ()
3702
-
3703
- # --- internals
3704
-
3705
- def run (self ):
3706
- self ._active = True
3707
- self .__flag .set ()
3708
- while self ._active and asyncore .socket_map :
3709
- self ._active_lock .acquire ()
3710
- asyncore .loop (timeout = 0.001 , count = 1 )
3711
- self ._active_lock .release ()
3712
- asyncore .close_all ()
3713
-
3714
- def handle_accept (self ):
3715
- conn , addr = self .accept ()
3716
- self .handler_instance = self .Handler (conn )
3717
-
3718
- def handle_connect (self ):
3719
- self .close ()
3720
- handle_read = handle_connect
3721
-
3722
- def writable (self ):
3723
- return 0
3724
-
3725
- def handle_error (self ):
3726
- raise
3727
-
3728
-
3729
3640
@unittest .skipUnless (hasattr (os , 'sendfile' ), "test needs os.sendfile()" )
3730
- class TestSendfile (unittest .TestCase ):
3641
+ class TestSendfile (unittest .IsolatedAsyncioTestCase ):
3731
3642
3732
3643
DATA = b"12345abcde" * 16 * 1024 # 160 KiB
3733
3644
SUPPORT_HEADERS_TRAILERS = not sys .platform .startswith ("linux" ) and \
@@ -3746,32 +3657,46 @@ def setUpClass(cls):
3746
3657
def tearDownClass (cls ):
3747
3658
os_helper .unlink (os_helper .TESTFN )
3748
3659
3749
- def setUp (self ):
3750
- self .server = SendfileTestServer ((socket_helper .HOST , 0 ))
3751
- self .server .start ()
3660
+ @staticmethod
3661
+ async def chunks (reader ):
3662
+ while not reader .at_eof ():
3663
+ yield await reader .read ()
3664
+
3665
+ async def handle_new_client (self , reader , writer ):
3666
+ self .server_buffer = b'' .join ([x async for x in self .chunks (reader )])
3667
+ writer .close ()
3668
+ self .server .close () # The test server processes a single client only
3669
+
3670
+ async def asyncSetUp (self ):
3671
+ self .server_buffer = b''
3672
+ self .server = await asyncio .start_server (self .handle_new_client ,
3673
+ socket_helper .HOSTv4 )
3674
+ server_name = self .server .sockets [0 ].getsockname ()
3752
3675
self .client = socket .socket ()
3753
- self .client .connect ((self .server .host , self .server .port ))
3754
- self .client .settimeout (1 )
3755
- # synchronize by waiting for "220 ready" response
3756
- self .client .recv (1024 )
3676
+ self .client .setblocking (False )
3677
+ await asyncio .get_running_loop ().sock_connect (self .client , server_name )
3757
3678
self .sockno = self .client .fileno ()
3758
3679
self .file = open (os_helper .TESTFN , 'rb' )
3759
3680
self .fileno = self .file .fileno ()
3760
3681
3761
- def tearDown (self ):
3682
+ async def asyncTearDown (self ):
3762
3683
self .file .close ()
3763
3684
self .client .close ()
3764
- if self .server .running :
3765
- self .server .stop ()
3766
- self .server = None
3685
+ await self .server .wait_closed ()
3686
+
3687
+ # Use the test subject instead of asyncio.loop.sendfile
3688
+ @staticmethod
3689
+ async def async_sendfile (* args , ** kwargs ):
3690
+ return await asyncio .to_thread (os .sendfile , * args , ** kwargs )
3767
3691
3768
- def sendfile_wrapper (self , * args , ** kwargs ):
3692
+ @staticmethod
3693
+ async def sendfile_wrapper (* args , ** kwargs ):
3769
3694
"""A higher level wrapper representing how an application is
3770
3695
supposed to use sendfile().
3771
3696
"""
3772
3697
while True :
3773
3698
try :
3774
- return os . sendfile (* args , ** kwargs )
3699
+ return await TestSendfile . async_sendfile (* args , ** kwargs )
3775
3700
except OSError as err :
3776
3701
if err .errno == errno .ECONNRESET :
3777
3702
# disconnected
@@ -3782,13 +3707,14 @@ def sendfile_wrapper(self, *args, **kwargs):
3782
3707
else :
3783
3708
raise
3784
3709
3785
- def test_send_whole_file (self ):
3710
+ async def test_send_whole_file (self ):
3786
3711
# normal send
3787
3712
total_sent = 0
3788
3713
offset = 0
3789
3714
nbytes = 4096
3790
3715
while total_sent < len (self .DATA ):
3791
- sent = self .sendfile_wrapper (self .sockno , self .fileno , offset , nbytes )
3716
+ sent = await self .sendfile_wrapper (self .sockno , self .fileno ,
3717
+ offset , nbytes )
3792
3718
if sent == 0 :
3793
3719
break
3794
3720
offset += sent
@@ -3799,19 +3725,19 @@ def test_send_whole_file(self):
3799
3725
self .assertEqual (total_sent , len (self .DATA ))
3800
3726
self .client .shutdown (socket .SHUT_RDWR )
3801
3727
self .client .close ()
3802
- self .server .wait ()
3803
- data = self .server .handler_instance .get_data ()
3804
- self .assertEqual (len (data ), len (self .DATA ))
3805
- self .assertEqual (data , self .DATA )
3728
+ await self .server .wait_closed ()
3729
+ self .assertEqual (len (self .server_buffer ), len (self .DATA ))
3730
+ self .assertEqual (self .server_buffer , self .DATA )
3806
3731
3807
- def test_send_at_certain_offset (self ):
3732
+ async def test_send_at_certain_offset (self ):
3808
3733
# start sending a file at a certain offset
3809
3734
total_sent = 0
3810
3735
offset = len (self .DATA ) // 2
3811
3736
must_send = len (self .DATA ) - offset
3812
3737
nbytes = 4096
3813
3738
while total_sent < must_send :
3814
- sent = self .sendfile_wrapper (self .sockno , self .fileno , offset , nbytes )
3739
+ sent = await self .sendfile_wrapper (self .sockno , self .fileno ,
3740
+ offset , nbytes )
3815
3741
if sent == 0 :
3816
3742
break
3817
3743
offset += sent
@@ -3820,18 +3746,18 @@ def test_send_at_certain_offset(self):
3820
3746
3821
3747
self .client .shutdown (socket .SHUT_RDWR )
3822
3748
self .client .close ()
3823
- self .server .wait ()
3824
- data = self .server .handler_instance .get_data ()
3749
+ await self .server .wait_closed ()
3825
3750
expected = self .DATA [len (self .DATA ) // 2 :]
3826
3751
self .assertEqual (total_sent , len (expected ))
3827
- self .assertEqual (len (data ), len (expected ))
3828
- self .assertEqual (data , expected )
3752
+ self .assertEqual (len (self . server_buffer ), len (expected ))
3753
+ self .assertEqual (self . server_buffer , expected )
3829
3754
3830
- def test_offset_overflow (self ):
3755
+ async def test_offset_overflow (self ):
3831
3756
# specify an offset > file size
3832
3757
offset = len (self .DATA ) + 4096
3833
3758
try :
3834
- sent = os .sendfile (self .sockno , self .fileno , offset , 4096 )
3759
+ sent = await self .async_sendfile (self .sockno , self .fileno ,
3760
+ offset , 4096 )
3835
3761
except OSError as e :
3836
3762
# Solaris can raise EINVAL if offset >= file length, ignore.
3837
3763
if e .errno != errno .EINVAL :
@@ -3840,39 +3766,38 @@ def test_offset_overflow(self):
3840
3766
self .assertEqual (sent , 0 )
3841
3767
self .client .shutdown (socket .SHUT_RDWR )
3842
3768
self .client .close ()
3843
- self .server .wait ()
3844
- data = self .server .handler_instance .get_data ()
3845
- self .assertEqual (data , b'' )
3769
+ await self .server .wait_closed ()
3770
+ self .assertEqual (self .server_buffer , b'' )
3846
3771
3847
- def test_invalid_offset (self ):
3772
+ async def test_invalid_offset (self ):
3848
3773
with self .assertRaises (OSError ) as cm :
3849
- os . sendfile (self .sockno , self .fileno , - 1 , 4096 )
3774
+ await self . async_sendfile (self .sockno , self .fileno , - 1 , 4096 )
3850
3775
self .assertEqual (cm .exception .errno , errno .EINVAL )
3851
3776
3852
- def test_keywords (self ):
3777
+ async def test_keywords (self ):
3853
3778
# Keyword arguments should be supported
3854
- os . sendfile (out_fd = self .sockno , in_fd = self .fileno ,
3855
- offset = 0 , count = 4096 )
3779
+ await self . async_sendfile (out_fd = self .sockno , in_fd = self .fileno ,
3780
+ offset = 0 , count = 4096 )
3856
3781
if self .SUPPORT_HEADERS_TRAILERS :
3857
- os . sendfile (out_fd = self .sockno , in_fd = self .fileno ,
3858
- offset = 0 , count = 4096 ,
3859
- headers = (), trailers = (), flags = 0 )
3782
+ await self . async_sendfile (out_fd = self .sockno , in_fd = self .fileno ,
3783
+ offset = 0 , count = 4096 ,
3784
+ headers = (), trailers = (), flags = 0 )
3860
3785
3861
3786
# --- headers / trailers tests
3862
3787
3863
3788
@requires_headers_trailers
3864
- def test_headers (self ):
3789
+ async def test_headers (self ):
3865
3790
total_sent = 0
3866
3791
expected_data = b"x" * 512 + b"y" * 256 + self .DATA [:- 1 ]
3867
- sent = os . sendfile (self .sockno , self .fileno , 0 , 4096 ,
3868
- headers = [b"x" * 512 , b"y" * 256 ])
3792
+ sent = await self . async_sendfile (self .sockno , self .fileno , 0 , 4096 ,
3793
+ headers = [b"x" * 512 , b"y" * 256 ])
3869
3794
self .assertLessEqual (sent , 512 + 256 + 4096 )
3870
3795
total_sent += sent
3871
3796
offset = 4096
3872
3797
while total_sent < len (expected_data ):
3873
3798
nbytes = min (len (expected_data ) - total_sent , 4096 )
3874
- sent = self .sendfile_wrapper (self .sockno , self .fileno ,
3875
- offset , nbytes )
3799
+ sent = await self .sendfile_wrapper (self .sockno , self .fileno ,
3800
+ offset , nbytes )
3876
3801
if sent == 0 :
3877
3802
break
3878
3803
self .assertLessEqual (sent , nbytes )
@@ -3881,51 +3806,49 @@ def test_headers(self):
3881
3806
3882
3807
self .assertEqual (total_sent , len (expected_data ))
3883
3808
self .client .close ()
3884
- self .server .wait ()
3885
- data = self .server .handler_instance .get_data ()
3886
- self .assertEqual (hash (data ), hash (expected_data ))
3809
+ await self .server .wait_closed ()
3810
+ self .assertEqual (hash (self .server_buffer ), hash (expected_data ))
3887
3811
3888
3812
@requires_headers_trailers
3889
- def test_trailers (self ):
3813
+ async def test_trailers (self ):
3890
3814
TESTFN2 = os_helper .TESTFN + "2"
3891
3815
file_data = b"abcdef"
3892
3816
3893
3817
self .addCleanup (os_helper .unlink , TESTFN2 )
3894
3818
create_file (TESTFN2 , file_data )
3895
3819
3896
3820
with open (TESTFN2 , 'rb' ) as f :
3897
- os . sendfile (self .sockno , f .fileno (), 0 , 5 ,
3898
- trailers = [b"123456" , b"789" ])
3821
+ await self . async_sendfile (self .sockno , f .fileno (), 0 , 5 ,
3822
+ trailers = [b"123456" , b"789" ])
3899
3823
self .client .close ()
3900
- self .server .wait ()
3901
- data = self .server .handler_instance .get_data ()
3902
- self .assertEqual (data , b"abcde123456789" )
3824
+ await self .server .wait_closed ()
3825
+ self .assertEqual (self .server_buffer , b"abcde123456789" )
3903
3826
3904
3827
@requires_headers_trailers
3905
3828
@requires_32b
3906
- def test_headers_overflow_32bits (self ):
3829
+ async def test_headers_overflow_32bits (self ):
3907
3830
self .server .handler_instance .accumulate = False
3908
3831
with self .assertRaises (OSError ) as cm :
3909
- os . sendfile (self .sockno , self .fileno , 0 , 0 ,
3910
- headers = [b"x" * 2 ** 16 ] * 2 ** 15 )
3832
+ await self . async_sendfile (self .sockno , self .fileno , 0 , 0 ,
3833
+ headers = [b"x" * 2 ** 16 ] * 2 ** 15 )
3911
3834
self .assertEqual (cm .exception .errno , errno .EINVAL )
3912
3835
3913
3836
@requires_headers_trailers
3914
3837
@requires_32b
3915
- def test_trailers_overflow_32bits (self ):
3838
+ async def test_trailers_overflow_32bits (self ):
3916
3839
self .server .handler_instance .accumulate = False
3917
3840
with self .assertRaises (OSError ) as cm :
3918
- os . sendfile (self .sockno , self .fileno , 0 , 0 ,
3919
- trailers = [b"x" * 2 ** 16 ] * 2 ** 15 )
3841
+ await self . async_sendfile (self .sockno , self .fileno , 0 , 0 ,
3842
+ trailers = [b"x" * 2 ** 16 ] * 2 ** 15 )
3920
3843
self .assertEqual (cm .exception .errno , errno .EINVAL )
3921
3844
3922
3845
@requires_headers_trailers
3923
3846
@unittest .skipUnless (hasattr (os , 'SF_NODISKIO' ),
3924
3847
'test needs os.SF_NODISKIO' )
3925
- def test_flags (self ):
3848
+ async def test_flags (self ):
3926
3849
try :
3927
- os . sendfile (self .sockno , self .fileno , 0 , 4096 ,
3928
- flags = os .SF_NODISKIO )
3850
+ await self . async_sendfile (self .sockno , self .fileno , 0 , 4096 ,
3851
+ flags = os .SF_NODISKIO )
3929
3852
except OSError as err :
3930
3853
if err .errno not in (errno .EBUSY , errno .EAGAIN ):
3931
3854
raise
0 commit comments