o
    ¯bì2  ã                   @   s   d Z ddlZddlZddlZzddlZW n ey   dZY nw ddlmZ ddlm	Z	m
Z
 ddlmZmZ ddlmZmZ ddlmZmZmZmZmZmZmZmZmZmZmZ ddlmZ dd	lm Z  dd
l!m"Z" ee	j# $e
¡ dƒG dd„ de"ƒƒZ%ee	j# $e
¡ dƒG dd„ de"ƒƒZ&dS )z
Whitebox tests for TCP APIs.
é    N)ÚskipIf)Ú
interfacesÚreactor)ÚgatherResultsÚmaybeDeferred)ÚProtocolÚServerFactory)Ú_ACCEPT_ERRORSÚEAGAINÚECONNABORTEDÚEINPROGRESSÚEMFILEÚENFILEÚENOBUFSÚENOMEMÚEPERMÚEWOULDBLOCKÚPort)Úlog)Úplatform)ÚTestCasez?This test only applies to reactors that implement IReactorFDsetc                   @   sF   e Zd ZdZdZdd„ Zdd„ Zdd„ Zee	 
¡ d	kd
ƒdd„ ƒZdS )ÚPlatformAssumptionsTestsz4
    Test assumptions about platform behaviors.
    i    c                 C   s`   g | _ td ur.ddlm} t|ƒ ƒd }t tj¡| _t tj|| jd f¡ |d | _	d S d S )Nr   )Ú_listOpenFDsé   é   éd   )
ÚopenSocketsÚresourceÚtwisted.internet.processr   ÚlenÚ	getrlimitÚRLIMIT_NOFILEÚoriginalFileLimitÚ	setrlimitÚsocketLimit)Úselfr   ÚnewLimit© r'   úA/usr/lib/python3/dist-packages/twisted/test/test_tcp_internals.pyÚsetUp4   s   ÿòzPlatformAssumptionsTests.setUpc                 C   s\   | j r| j  ¡  ¡  | j std ur,t tj¡d }t| jd |ƒ}t tj||f¡ d S d S )Nr   r   )	r   ÚpopÚcloser   r    r!   Úminr"   r#   )r%   ÚcurrentHardLimitÚnewSoftLimitr'   r'   r(   ÚtearDownF   s   ÿùz!PlatformAssumptionsTests.tearDownc                 C   s   t   ¡ }| j |¡ |S )z|
        Create and return a new socket object, also tracking it so it can be
        closed in the test tear down.
        )Úsocketr   Úappend)r%   Úsr'   r'   r(   r0   R   s   zPlatformAssumptionsTests.socketÚwin32zhWindows requires an unacceptably large amount of resources to provoke this behavior in the naive manner.c                 C   sÞ   |   ¡ }| d¡ | ¡ d }| d¡ |   ¡ }| d¡ t| jƒD ]%}z|   ¡  W q" tyG } z|jd t	t
fv rBW Y d}~ n‚ d}~ww |  d¡ |  | d|f¡dtf¡ |  t j|j¡}|  |jd t	t
f¡ dS )	z˜
        Test that the platform accept(2) call fails with either L{EMFILE} or
        L{ENOBUFS} when there are too many file descriptors open.
        )ú	127.0.0.1r   r   é   Fr   Nz7Could provoke neither EMFILE nor ENOBUFS from platform.r4   )r0   ÚbindÚgetsocknameÚlistenÚsetblockingÚranger$   ÚOSErrorÚargsr   r   ÚfailÚassertInÚ
connect_exr   ÚassertRaisesÚerrorÚaccept)r%   ÚportÚserverPortNumberÚclientÚiÚeÚexcr'   r'   r(   Útest_acceptOutOfFiles[   s*   


€ú
ÿz.PlatformAssumptionsTests.test_acceptOutOfFilesN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r$   r)   r/   r0   r   r   ÚgetTyperI   r'   r'   r'   r(   r   )   s    	
þr   c                   @   s¼   e Zd ZdZdd„ Zdd„ Zdd„ Zdd	„ Zd
d„ Zdd„ Z	dd„ Z
ee ¡ dkdƒdd„ ƒZee ¡ dkdƒdd„ ƒZeej d¡dkdƒdd„ ƒZee ¡ dkdƒdd„ ƒZdd „ Zd!S )"ÚSelectReactorTestsz7
    Tests for select-specific failure conditions.
    c                 C   s   g | _ g | _t | jj¡ d S ©N)ÚportsÚmessagesr   ÚaddObserverr1   ©r%   r'   r'   r(   r)   ‘   s   zSelectReactorTests.setUpc                 C   s"   t  | jj¡ tdd„ | jD ƒƒS )Nc                 S   s   g | ]}t |jƒ‘qS r'   )r   ÚstopListening)Ú.0Úpr'   r'   r(   Ú
<listcomp>˜   s    z/SelectReactorTests.tearDown.<locals>.<listcomp>)r   ÚremoveObserverrR   r1   r   rQ   rT   r'   r'   r(   r/   –   s   zSelectReactorTests.tearDownc                 C   s&   t |||d�}| ¡  | j |¡ |S )z
        Create, start, and return a new L{Port}, also tracking it so it can
        be stopped in the test tear down.
        ©Ú	interface)r   ÚstartListeningrQ   r1   )r%   Ú
portNumberÚfactoryr[   rW   r'   r'   r(   rC   š   s   zSelectReactorTests.portc                    s‚   G ‡fdd„dƒ}t ƒ }| jd|dd�}|  |d|ƒ ¡ | ¡  d‰tjˆ ‰ ‡ ‡fdd	„| jD ƒ}|  t|ƒdd
| jf ¡ dS )a¢  
        Test behavior in the face of an exception from C{accept(2)}.

        On any exception which indicates the platform is unable or unwilling
        to allocate further resources to us, the existing port should remain
        listening, a message should be logged, and the exception should not
        propagate outward from doRead.

        @param socketErrorNumber: The errno to simulate from accept.
        c                       ó   e Zd ZdZ‡ fdd„ZdS )z9SelectReactorTests._acceptFailureTest.<locals>.FakeSocketzI
            Pretend to be a socket in an overloaded system.
            c                    s   t ˆ t ˆ ¡ƒ‚rP   )r;   ÚosÚstrerrorrT   ©ÚsocketErrorNumberr'   r(   rB   µ   s   z@SelectReactorTests._acceptFailureTest.<locals>.FakeSocket.acceptN©rJ   rK   rL   rM   rB   r'   rb   r'   r(   Ú
FakeSocket°   s    re   r   r4   rZ   r0   z/Could not accept new connection ({acceptError})c                    s(   g | ]}|  d ¡ˆko|  d¡ˆ k‘qS )Ú
log_formatÚacceptError)Úget)rV   Úmsg)ÚexpectedErrorCodeÚexpectedFormatr'   r(   rX   À   s
    ýýz9SelectReactorTests._acceptFailureTest.<locals>.<listcomp>z+Log event for failed accept not found in %rN)	r   rC   ÚpatchÚdoReadÚerrnoÚ	errorcoderR   ÚassertGreaterr   )r%   rc   re   r^   rC   ÚmatchingMessagesr'   )rj   rk   rc   r(   Ú_acceptFailureTest¤   s   
û
ýz%SelectReactorTests._acceptFailureTestc                 C   ó
   |   t¡S )a*  
        C{accept(2)} can fail with C{EMFILE} when there are too many open file
        descriptors in the process.  Test that this doesn't negatively impact
        any other existing connections.

        C{EMFILE} mainly occurs on Linux when the open file rlimit is
        encountered.
        )rr   r   rT   r'   r'   r(   Útest_tooManyFilesFromAcceptÍ   ó   
	z.SelectReactorTests.test_tooManyFilesFromAcceptc                 C   rs   )zö
        Similar to L{test_tooManyFilesFromAccept}, but test the case where
        C{accept(2)} fails with C{ENOBUFS}.

        This mainly occurs on Windows and FreeBSD, but may be possible on
        Linux and other platforms as well.
        )rr   r   rT   r'   r'   r(   Útest_noBufferSpaceFromAcceptØ   ó   
z/SelectReactorTests.test_noBufferSpaceFromAcceptc                 C   rs   )zù
        Similar to L{test_tooManyFilesFromAccept}, but test the case where
        C{accept(2)} fails with C{ECONNABORTED}.

        It is not clear whether this is actually possible for TCP
        connections on modern versions of Linux.
        )rr   r   rT   r'   r'   r(   Ú test_connectionAbortedFromAcceptâ   rw   z3SelectReactorTests.test_connectionAbortedFromAcceptr3   z(Windows accept(2) cannot generate ENFILEc                 C   rs   )zà
        Similar to L{test_tooManyFilesFromAccept}, but test the case where
        C{accept(2)} fails with C{ENFILE}.

        This can occur on Linux when the system has exhausted (!) its supply
        of inodes.
        )rr   r   rT   r'   r'   r(   Útest_noFilesFromAcceptì   ru   z)SelectReactorTests.test_noFilesFromAcceptz(Windows accept(2) cannot generate ENOMEMc                 C   rs   )a³  
        Similar to L{test_tooManyFilesFromAccept}, but test the case where
        C{accept(2)} fails with C{ENOMEM}.

        On Linux at least, this can sensibly occur, even in a Python program
        (which eats memory like no ones business), when memory has become
        fragmented or low memory has been filled (d_alloc calls
        kmem_cache_alloc calls kmalloc - kmalloc only allocates out of low
        memory).
        )rr   r   rT   r'   r'   r(   Útest_noMemoryFromAccept÷   s   
z*SelectReactorTests.test_noMemoryFromAcceptÚINFRASTRUCTUREÚAZUREPIPELINESz(Hangs on Azure Pipelines due to firewallc                    s²   t ƒ }t|_| jd|dd�‰|  ˆj¡ g ‰ ‡ fdd„}|  |¡ ‡fdd„}ˆ  |ƒ ¡ dˆ_ˆ ¡  |  	ˆjd¡ ˆ  |ƒ ¡ ˆ ¡  |  
ˆjd¡ ˆ ¡  |  
ˆjd¡ d	S )
zð
        L{tcp.Port.doRead} increases the number of consecutive
        C{accept} calls it performs if all of the previous C{accept}
        calls succeed; otherwise, it reduces the number to the amount
        of successful calls.
        r   r4   rZ   c                     s   ˆ D ]} |   ¡  qd S rP   )r+   ©rE   )Úclientsr'   r(   ÚcloseAll  s   
ÿz7SelectReactorTests.test_acceptScaling.<locals>.closeAllc                     s(   t   t jt j¡} |  dˆ  ¡ jf¡ | S )Nr4   )r0   ÚAF_INETÚSOCK_STREAMÚconnectÚgetHostrC   r}   )rC   r'   r(   r‚     s   z6SelectReactorTests.test_acceptScaling.<locals>.connectr   N)r   r   ÚprotocolrC   Ú
addCleanuprU   r1   ÚnumberAcceptsrm   rp   ÚassertEqual)r%   r^   r   r‚   r'   )r~   rC   r(   Útest_acceptScaling  s"   
z%SelectReactorTests.test_acceptScalingz'Windows accept(2) cannot generate EPERMc                    sž   d‰dg‰ G ‡ ‡‡fdd„dƒ}t ˆƒD ]}ˆ tj|ƒ j¡ qˆ ˆj|ƒ j¡ dg‰ tƒ }ˆjd|dd�}d|_ˆ 	|d|ƒ ¡ | 
¡  ˆ |jd¡ d	S )
z»
        C{accept(2)} returning C{EPERM} is treated as a transient
        failure and the call retried no more than the maximum number
        of consecutive C{accept(2)} calls.
        é{   r   c                       s    e Zd ZdZ‡ ‡‡fdd„ZdS )zLSelectReactorTests.test_permissionFailure.<locals>.FakeSocketWithAcceptLimitú«
            Pretend to be a socket in an overloaded system whose
            C{accept} method can only be called
            C{maximumNumberOfAccepts} times.
            c                    s6   ˆ d  d7  < ˆ d ˆkrˆ  d¡ ttt t¡ƒ‚)Nr   r   z(Maximum number of accept calls exceeded.)r=   r;   r   r`   ra   ©Úoself©ÚacceptCallsÚmaximumNumberOfAcceptsr%   r'   r(   rB   C  s   
zSSelectReactorTests.test_permissionFailure.<locals>.FakeSocketWithAcceptLimit.acceptNrd   r'   r�   r'   r(   ÚFakeSocketWithAcceptLimit<  s    r�   r4   rZ   r0   r   N)r:   r@   r0   rA   rB   ÚfailureExceptionr   rC   r†   rl   rm   ÚassertEquals)r%   r�   Ú_r^   rC   r'   r�   r(   Útest_permissionFailure2  s   z)SelectReactorTests.test_permissionFailurec                    s¦   t tƒ}| tttg¡ tdd„ |D ƒƒd ‰ G ‡ fdd„dƒ}tƒ }| jd|dd�}|  	|d	|ƒ ¡ | 
¡  |  tj¡}|  dt|ƒ¡ |  |d jjd ˆ ¡ d
S )z}
        A C{socket.error} raised by C{accept(2)} whose C{errno} is
        unknown to the recovery logic is logged.
        c                 s   s   � | ]
}t |tƒr|V  qd S rP   )Ú
isinstanceÚint)rV   rA   r'   r'   r(   Ú	<genexpr>g  s   € zBSelectReactorTests.test_unknownSocketErrorRaise.<locals>.<genexpr>r   c                       r_   )zYSelectReactorTests.test_unknownSocketErrorRaise.<locals>.FakeSocketWithUnknownAcceptErrorrŠ   c                    s
   t ˆ dƒ‚)Nzunknown socket error message)r;   r‹   ©ÚunknownAcceptErrorr'   r(   rB   q  s   
z`SelectReactorTests.test_unknownSocketErrorRaise.<locals>.FakeSocketWithUnknownAcceptError.acceptNrd   r'   r˜   r'   r(   Ú FakeSocketWithUnknownAcceptErrorj  s    rš   r   r4   rZ   r0   N)Úlistr	   Úextendr
   r   r   Úmaxr   rC   rl   rm   ÚflushLoggedErrorsr0   rA   r‡   r   Úvaluer<   )r%   ÚknownErrorsrš   r^   rC   Úfailuresr'   r˜   r(   Útest_unknownSocketErrorRaise^  s   ÿ
z/SelectReactorTests.test_unknownSocketErrorRaiseN)rJ   rK   rL   rM   r)   r/   rC   rr   rt   rv   rx   r   r   rN   ry   rz   r`   Úenvironrh   rˆ   r”   r¢   r'   r'   r'   r(   rO   ˆ   s*    
)




þ
)
+rO   )'rM   rn   r`   r0   r   ÚImportErrorÚunittestr   Útwisted.internetr   r   Útwisted.internet.deferr   r   Útwisted.internet.protocolr   r   Útwisted.internet.tcpr	   r
   r   r   r   r   r   r   r   r   r   Útwisted.pythonr   Útwisted.python.runtimer   Útwisted.trial.unittestr   ÚIReactorFDSetÚ
providedByr   rO   r'   r'   r'   r(   Ú<module>   s6   ÿ4þ[þ