U
    
W[=3                     @   s   d Z ddlmZmZ ddlZddlZddlZzddlZW n ek
rP   dZY nX ddl	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mZ ddlmZ dd	lm Z m!Z! dd
l"m#Z#m$Z$ G dd de
Z%G dd de
Z&e$j'(e#sdZ)e)e%_*e)e&_*dS )z
Whitebox tests for TCP APIs.
    )divisionabsolute_importN)TestCase)compatlog)_ACCEPT_ERRORSECONNABORTEDEPERMENOMEMENFILEEAGAINEMFILEENOBUFSEINPROGRESSEWOULDBLOCKPort)ProtocolServerFactory)platform)maybeDeferredgatherResults)reactor
interfacesc                   @   sF   e Zd ZdZdZdd Zdd Zdd Zd	d
 Ze	
 dkrBde_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'   A/usr/lib/python3/dist-packages/twisted/test/test_tcp_internals.pysetUp$   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(   tearDown4   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.   A   s    zPlatformAssumptionsTests.socketc                 C   s   |   }|d | d }|d |   }|d t| jD ]V}z|    W qD t jk
r } z$|jd t	t
fkrW Y  qn 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.r1   )r.   ZbindZgetsocknameZlistenZsetblockingranger%   errorargsr   r   failZassertInZ
connect_exr   assertRaisesaccept)r&   portZserverPortNumberclientieexcr'   r'   r(   test_acceptOutOfFilesK   s&    



z.PlatformAssumptionsTests.test_acceptOutOfFileswin32zhWindows requires an unacceptably large amount of resources to provoke this behavior in the naive manner.N)__name__
__module____qualname____doc__r%   r)   r-   r.   r>   r   getTypeskipr'   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
dd Ze dkr^de_dd Ze dkrxde_dd Zdd Ze dkrde_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removeObserverrI   r/   r   rH   rJ   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startListeningrH   r/   )r&   Z
portNumberfactoryrP   rM   r'   r'   r(   r9      s    zSelectReactorTests.portc                    s   G fdddt }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 rG   )r.   r4   osstrerrorrJ   socketErrorNumberr'   r(   r8      s     z@SelectReactorTests._acceptFailureTest.<locals>.FakeSocket.acceptNr@   rA   rB   rC   r8   r'   rT   r'   r(   
FakeSocket   s   rW   r   r1   rO   r.   z/Could not accept new connection ({acceptError})c                    s(   g | ] }| d ko"| d kqS )Z
log_formatZacceptError)get)rL   msg)expectedErrorCodeexpectedFormatr'   r(   rN      s   z9SelectReactorTests._acceptFailureTest.<locals>.<listcomp>z+Log event for failed accept not found in %rN)
objectr   r9   patchdoReaderrnoZ	errorcoderI   assertGreaterr    )r&   rU   rW   rQ   r9   ZmatchingMessagesr'   )rZ   r[   rU   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.
        )ra   r   rJ   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.
        )ra   r   rJ   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.
        )ra   r   rJ   r'   r'   r(    test_connectionAbortedFromAccept   s    z3SelectReactorTests.test_connectionAbortedFromAcceptc                 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.
        )ra   r   rJ   r'   r'   r(   test_noFilesFromAccept   s    z)SelectReactorTests.test_noFilesFromAcceptr?   z(Windows accept(2) cannot generate ENFILEc                 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).
        )ra   r
   rJ   r'   r'   r(   test_noMemoryFromAccept   s    z*SelectReactorTests.test_noMemoryFromAcceptz(Windows accept(2) cannot generate ENOMEMc                    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   r1   rO   c                     s    D ]} |    qd S rG   )r+   r:   )clientsr'   r(   closeAll  s    z7SelectReactorTests.test_acceptScaling.<locals>.closeAllc                     s(   t  t jt j} | d  jf | S )Nr1   )r.   ZAF_INETZSOCK_STREAMconnectZgetHostr9   rg   )r9   r'   r(   rj     s    z6SelectReactorTests.test_acceptScaling.<locals>.connectr   N)r   r   Zprotocolr9   Z
addCleanuprK   r/   numberAcceptsr^   r`   assertEqual)r&   rQ   ri   rj   r'   )rh   r9   r(   test_acceptScaling   s"    
z%SelectReactorTests.test_acceptScalingc                    s   ddg G  fdddt }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.)r6   r.   r4   r	   rR   rS   ZoselfZacceptCallsZmaximumNumberOfAcceptsr&   r'   r(   r8   2  s    
zSSelectReactorTests.test_permissionFailure.<locals>.FakeSocketWithAcceptLimit.acceptNrV   r'   rq   r'   r(   FakeSocketWithAcceptLimit,  s   rr   r1   rO   r.   r   N)r\   r3   r7   r.   r4   r8   ZfailureExceptionr   r9   rk   r]   r^   ZassertEquals)r&   rr   _rQ   r9   r'   rq   r(   test_permissionFailure#  s"    z)SelectReactorTests.test_permissionFailurez'Windows accept(2) cannot generate EPERMc                    s   t t}|tttg tdd |D d  G  fdddt}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tjfr|V  qd S rG   )
isinstanceintr   Zlong)rL   r4   r'   r'   r(   	<genexpr>\  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>.FakeSocketWithUnknownAcceptErrorro   c                    s   t  dd S )Nzunknown socket error message)r.   r4   rp   ZunknownAcceptErrorr'   r(   r8   g  s    z`SelectReactorTests.test_unknownSocketErrorRaise.<locals>.FakeSocketWithUnknownAcceptError.acceptNrV   r'   rx   r'   r(    FakeSocketWithUnknownAcceptErrora  s   ry   r   r1   rO   r.   N)listr   extendr   r	   r   maxr\   r   r9   r]   r^   ZflushLoggedErrorsr.   r4   rl   r    valuer5   )r&   ZknownErrorsry   rQ   r9   Zfailuresr'   rx   r(   test_unknownSocketErrorRaiseT  s    
z/SelectReactorTests.test_unknownSocketErrorRaiseN)r@   rA   rB   rC   r)   r-   r9   ra   rb   rc   rd   re   r   rD   rE   rf   rm   rt   r~   r'   r'   r'   r(   rF   w   s*   %	*,rF   z?This test only applies to reactors that implement IReactorFDset)+rC   Z
__future__r   r   r_   r.   rR   r   ImportErrorZtwisted.trial.unittestr   Ztwisted.pythonr   r   Ztwisted.internet.tcpr   r   r	   r
   r   r   r   r   r   r   r   Ztwisted.internet.protocolr   r   Ztwisted.python.runtimer   Ztwisted.internet.deferr   r   Ztwisted.internetr   r   r   rF   ZIReactorFDSetZ
providedByZskipMsgrE   r'   r'   r'   r(   <module>   s*   
4Y  