U
    2ÜŸjì2  ã                   @   s"  d Z ddlZddlZddlZzddlZW n ek
r@   dZY nX 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 k	rXddlm} t|ƒ ƒd }t tj¡| _t tj|| jd f¡ |d | _	d S )Nr   )Ú_listOpenFDsé   é   éd   )
ÚopenSocketsÚresourceZtwisted.internet.processr   ÚlenÚ	getrlimitÚRLIMIT_NOFILEÚoriginalFileLimitÚ	setrlimitÚsocketLimit)Úselfr   ZnewLimit© r%   úC/tmp/pip-unpacked-wheel-4b529toj/twisted/test/test_tcp_internals.pyÚsetUp4   s     ÿzPlatformAssumptionsTests.setUpc                 C   sT   | j r| j  ¡  ¡  q td k	rPt tj¡d }t| jd |ƒ}t tj||f¡ d S )Nr   r   )	r   ÚpopÚcloser   r   r    Úminr!   r"   )r$   ZcurrentHardLimitZ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&   r,   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 ]T}z|   ¡  W qD tk
r– } z$|jd t	t
fkr„W Y ¢ q¤n‚ W 5 d}~X Y qDX qD|  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.r0   )r,   ÚbindÚgetsocknameÚlistenÚsetblockingÚranger#   ÚOSErrorÚargsr   r   ÚfailZassertInÚ
connect_exr   ÚassertRaisesÚerrorÚaccept)r$   ÚportZserverPortNumberÚclientÚiÚeÚexcr%   r%   r&   Útest_acceptOutOfFiles[   s(    



 ÿz.PlatformAssumptionsTests.test_acceptOutOfFilesN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r#   r'   r+   r,   r   r   ÚgetTyperC   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   ZaddObserverr-   ©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   ZremoveObserverrL   r-   r   rK   rM   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   ZstartListeningrK   r-   )r$   Z
portNumberÚfactoryrS   rP   r%   r%   r&   r>   š   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                       s   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 ˆ ¡ƒ‚d S rJ   )r7   ÚosÚstrerrorrM   ©ÚsocketErrorNumberr%   r&   r=   µ   s    z@SelectReactorTests._acceptFailureTest.<locals>.FakeSocket.acceptN©rD   rE   rF   rG   r=   r%   rW   r%   r&   Ú
FakeSocket°   s   rZ   r   r0   rR   r,   z/Could not accept new connection ({acceptError})c                    s(   g | ] }|  d ¡ˆko"|  d¡ˆ k‘qS )Z
log_formatZacceptError)Úget)rO   Úmsg)ÚexpectedErrorCodeÚexpectedFormatr%   r&   rQ   À   s   ýz9SelectReactorTests._acceptFailureTest.<locals>.<listcomp>z+Log event for failed accept not found in %rN)	r   r>   ÚpatchÚdoReadÚerrnoÚ	errorcoderL   ÚassertGreaterr   )r$   rX   rZ   rT   r>   ZmatchingMessagesr%   )r]   r^   rX   r&   Ú_acceptFailureTest¤   s    
û
ýz%SelectReactorTests._acceptFailureTestc                 C   s
   |   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.
        )rd   r   rM   r%   r%   r&   Útest_tooManyFilesFromAcceptÍ   s    	z.SelectReactorTests.test_tooManyFilesFromAcceptc                 C   s
   |   t¡S )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.
        )rd   r   rM   r%   r%   r&   Útest_noBufferSpaceFromAcceptØ   s    z/SelectReactorTests.test_noBufferSpaceFromAcceptc                 C   s
   |   t¡S )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.
        )rd   r   rM   r%   r%   r&   Ú test_connectionAbortedFromAcceptâ   s    z3SelectReactorTests.test_connectionAbortedFromAcceptr/   z(Windows accept(2) cannot generate ENFILEc                 C   s
   |   t¡S )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.
        )rd   r   rM   r%   r%   r&   Útest_noFilesFromAcceptì   s    	z)SelectReactorTests.test_noFilesFromAcceptz(Windows accept(2) cannot generate ENOMEMc                 C   s
   |   t¡S )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).
        )rd   r   rM   r%   r%   r&   Útest_noMemoryFromAccept÷   s    z*SelectReactorTests.test_noMemoryFromAcceptZINFRASTRUCTUREZ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   r0   rR   c                     s   ˆ D ]} |   ¡  qd S rJ   )r)   ©r?   )Úclientsr%   r&   ÚcloseAll  s    z7SelectReactorTests.test_acceptScaling.<locals>.closeAllc                     s(   t   t jt j¡} |  dˆ  ¡ jf¡ | S )Nr0   )r,   ÚAF_INETÚSOCK_STREAMÚconnectZgetHostr>   rj   )r>   r%   r&   ro     s    z6SelectReactorTests.test_acceptScaling.<locals>.connectr   N)r   r   Úprotocolr>   Z
addCleanuprN   r-   ÚnumberAcceptsr`   rc   ÚassertEqual)r$   rT   rl   ro   r%   )rk   r>   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                    s:   ˆ d  d7  < ˆ d ˆkr&ˆ  d¡ ttt t¡ƒ‚d S )Nr   r   z(Maximum number of accept calls exceeded.)r9   r7   r   rU   rV   ©Zoself©ZacceptCallsZmaximumNumberOfAcceptsr$   r%   r&   r=   C  s    
zSSelectReactorTests.test_permissionFailure.<locals>.FakeSocketWithAcceptLimit.acceptNrY   r%   rw   r%   r&   ÚFakeSocketWithAcceptLimit<  s   rx   r0   rR   r,   r   N)r6   r;   r,   r<   r=   ZfailureExceptionr   r>   rq   r_   r`   ZassertEquals)r$   rx   Ú_rT   r>   r%   rw   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 rJ   )Ú
isinstanceÚint)rO   r<   r%   r%   r&   Ú	<genexpr>g  s     
 zBSelectReactorTests.test_unknownSocketErrorRaise.<locals>.<genexpr>r   c                       s   e Zd ZdZ‡ fdd„ZdS )zYSelectReactorTests.test_unknownSocketErrorRaise.<locals>.FakeSocketWithUnknownAcceptErrorru   c                    s   t ˆ dƒ‚d S )Nzunknown socket error message)r7   rv   ©ZunknownAcceptErrorr%   r&   r=   q  s    z`SelectReactorTests.test_unknownSocketErrorRaise.<locals>.FakeSocketWithUnknownAcceptError.acceptNrY   r%   r~   r%   r&   Ú FakeSocketWithUnknownAcceptErrorj  s   r   r   r0   rR   r,   N)Úlistr	   Úextendr
   r   r   Úmaxr   r>   r_   r`   ZflushLoggedErrorsr,   r<   rr   r   Úvaluer8   )r$   ZknownErrorsr   rT   r>   Zfailuresr%   r~   r&   Útest_unknownSocketErrorRaise^  s    ÿ
z/SelectReactorTests.test_unknownSocketErrorRaiseN)rD   rE   rF   rG   r'   r+   r>   rd   re   rf   rg   r   r   rH   rh   ri   rU   Úenvironr[   rs   rz   r„   r%   r%   r%   r&   rI   ˆ   s(   
)




þ
)
+rI   )'rG   ra   rU   r,   r   ÚImportErrorZunittestr   Ztwisted.internetr   r   Ztwisted.internet.deferr   r   Ztwisted.internet.protocolr   r   Ztwisted.internet.tcpr	   r
   r   r   r   r   r   r   r   r   r   Ztwisted.pythonr   Ztwisted.python.runtimer   Ztwisted.trial.unittestr   ZIReactorFDSetZ
providedByr   rI   r%   r%   r%   r&   Ú<module>   s2   
4þ[þ