U
     T‚gd  ã                   @   s´   d Z ddlZddlmZmZmZ ddlmZ ddlm	Z	 ddl
mZ ddlmZ ddlmZmZ dd	lmZ G d
d„ dƒZG dd„ de	eƒZG dd„ dejƒZG dd„ dejƒZdS )z&
Tests for L{twisted.runner.procmon}.
é    N)ÚProcessDoneÚProcessExitedAlreadyÚProcessTerminated)ÚClock)ÚMemoryReactor)ÚglobalLogPublisher)ÚFailure)ÚLoggingProtocolÚProcessMonitor)Úunittestc                   @   s6   e Zd ZdZdZdZdZddd„Zdd„ Zd	d
„ Z	dS )ÚDummyProcessa   
    An incomplete and fake L{IProcessTransport} implementation for testing how
    L{ProcessMonitor} behaves when its monitored processes exit.

    @ivar _terminationDelay: the delay in seconds after which the DummyProcess
        will appear to exit when it receives a TERM signal
    é   Nr   c                 C   s@   || _ || _|| _|| _|| _|| _|| _|| _|	| _|
| _	d S ©N)
ÚprotoÚ_reactorÚ_executableÚ_argsÚ_environmentÚ_pathZ_uidZ_gidZ_usePTYZ	_childFDs)ÚselfÚreactorÚ
executableÚargsÚenvironmentÚpathr   ÚuidÚgidÚusePTYÚchildFDs© r   úD/tmp/pip-unpacked-wheel-1_7di8ic/twisted/runner/test/test_procmon.pyÚ__init__    s    zDummyProcess.__init__c                 C   sL   | j dfddœ}| jdkr tƒ ‚||krH|| \}}| j || j|¡| _dS )añ  
        A partial implementation of signalProcess which can only handle TERM and
        KILL signals.
         - When a TERM signal is given, the dummy process will appear to exit
           after L{DummyProcess._terminationDelay} seconds with exit code 0
         - When a KILL signal is given, the dummy process will appear to exit
           immediately with exit code 1.

        @param signalID: The signal name or number to be issued to the process.
        @type signalID: C{str}
        r   ©r   r   )ÚTERMÚKILLN)Ú_terminationDelayÚpidr   r   Z	callLaterÚprocessEndedZ_signalHandler)r   ZsignalIDÚparamsÚdelayÚstatusr   r   r    ÚsignalProcess9   s    
  ÿzDummyProcess.signalProcessc                 C   s,   d| _ ttdœ}| j t|| |ƒƒ¡ dS )zC
        Deliver the process ended event to C{self.proto}.
        Nr"   )r&   r   r   r   r'   r   )r   r*   Z	statusMapr   r   r    r'   P   s
    þzDummyProcess.processEnded)NNr   N)
Ú__name__Ú
__module__Ú__qualname__Ú__doc__r&   r   r%   r!   r+   r'   r   r   r   r    r      s   
    õ
r   c                   @   s0   e Zd ZdZdd„ Zdi dddddfdd„ZdS )	ÚDummyProcessReactorz�
    @ivar spawnedProcesses: a list that keeps track of the fake process
        instances built by C{spawnProcess}.
    @type spawnedProcesses: C{list}
    c                 C   s   t  | ¡ t | ¡ g | _d S r   )r   r!   r   ÚspawnedProcesses©r   r   r   r    r!   c   s    

zDummyProcessReactor.__init__r   Nr   c
                 C   s4   t | |||||||||	ƒ
}
| |
¡ | j |
¡ |
S )zz
        Fake L{reactor.spawnProcess}, that logs all the process
        arguments and returns a L{DummyProcess}.
        )r   ZmakeConnectionr1   Úappend)r   ZprocessProtocolr   r   Úenvr   r   r   r   r   Úprocr   r   r    ÚspawnProcessi   s    ö
z DummyProcessReactor.spawnProcess)r,   r-   r.   r/   r!   r6   r   r   r   r    r0   \   s   
ör0   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d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d$d%„ Zd&d'„ Zd(d)„ Zd*d+„ Zd,d-„ Zd.d/„ Zd0d1„ Zd2d3„ Zd4d5„ Zd6d7„ Zd8d9„ Zd:d;„ Z d<d=„ Z!d>d?„ Z"d@dA„ Z#dBS )CÚProcmonTestsz&
    Tests for L{ProcessMonitor}.
    c                 C   s2   t ƒ | _t| jd�| _d| j_d| j_d| j_dS )zL
        Create an L{ProcessMonitor} wrapped around a fake reactor.
        ©r   é   é
   N)r0   r   r
   ÚpmÚminRestartDelayÚmaxRestartDelayÚ	thresholdr2   r   r   r    ÚsetUp�   s
    zProcmonTests.setUpc                 C   sL   | j jdddgddi d� t| j ƒ}|  d|¡ |  d|¡ |  d|¡ d	S )
z+
        Repr includes all details
        ÚfooÚarg1Úarg2r   r9   ©r   r   r4   Ú1Ú2N)r;   Ú
addProcessÚreprÚassertIn©r   Zrepresentationr   r   r    Útest_reprLooksGoodš   s
    
zProcmonTests.test_reprLooksGoodc                 C   s<   | j jdddgi d� t| j ƒ}|  d|¡ |  d|¡ dS )z·
        Repr does not include unneeded details.

        Values of attributes that just mean "inherit from launching
        process" do not appear in the repr of a process.
        r@   rA   rB   )r4   ú(ú)N)r;   rF   rG   ÚassertNotInrI   r   r   r    Útest_simpleReprLooksGood¤   s    
z%ProcmonTests.test_simpleReprLooksGoodc                 C   sD   | j jdddgddi d� |  | j  ¡ d dddgddi fi¡ dS )	zW
        The list of monitored processes must be included in the pickle state.
        r@   rA   rB   r   r9   rC   Ú	processesN)r;   rF   ÚassertEqualÚ__getstate__r2   r   r   r    Útest_getStateIncludesProcesses°   s
     ÿz+ProcmonTests.test_getStateIncludesProcessesc                 C   s   |   d| j ¡ ¡ dS )z~
        The private L{ProcessMonitor._reactor} instance variable should not be
        included in the pickle state.
        r   N)rM   r;   rQ   r2   r   r   r    Útest_getStateExcludesReactor¹   s    z)ProcmonTests.test_getStateExcludesReactorc                 C   s~   | j jdddgddi d� |  | j ji ¡ |  | j jdddgddi fi¡ | j  ¡  | j d¡ |  t| j j 	¡ ƒdg¡ dS )	z‡
        L{ProcessMonitor.addProcess} only starts the named program if
        L{ProcessMonitor.startService} has been called.
        r@   rA   rB   r   r9   rC   r   N)
r;   rF   rP   Ú	protocolsrO   ÚstartServicer   ÚadvanceÚlistÚkeysr2   r   r   r    Útest_addProcessÀ   s     
zProcmonTests.test_addProcessc              	   C   s>   | j jdddgddi d� | jt| j jdddgddi d� dS )z|
        L{ProcessMonitor.addProcess} raises a C{KeyError} if a process with the
        given name already exists.
        r@   rA   rB   r   r9   rC   N)r;   rF   ÚassertRaisesÚKeyErrorr2   r   r   r    Ú test_addProcessDuplicateKeyErrorÌ   s          ÿz-ProcmonTests.test_addProcessDuplicateKeyErrorc                 C   sP   ddi}| j  ¡  | j jddgdd|d� | j d¡ |  | jjd j|¡ dS )	zƒ
        L{ProcessMonitor.addProcess} takes an C{env} parameter that is passed to
        L{IReactorProcess.spawnProcess}.
        ZKEYÚvaluer@   r   r9   rC   r   N)r;   rU   rF   r   rV   rP   r1   r   )r   ZfakeEnvr   r   r    Útest_addProcessEnvÖ   s
    
zProcmonTests.test_addProcessEnvc                 C   sD   | j  ¡  | j jddgdd� | j d¡ |  | jjd jd¡ dS )zƒ
        L{ProcessMonitor.addProcess} takes an C{cwd} parameter that is passed
        to L{IReactorProcess.spawnProcess}.
        r@   z	/mnt/lala)Úcwdr   N)r;   rU   rF   r   rV   rP   r1   r   r2   r   r   r    Útest_addProcessCwdá   s    
zProcmonTests.test_addProcessCwdc                 C   sR   | j  ¡  | j  ddg¡ |  t| j jƒd¡ | j  d¡ |  t| j jƒd¡ dS )zm
        L{ProcessMonitor.removeProcess} removes the process from the public
        processes list.
        r@   r   r   N)r;   rU   rF   rP   ÚlenrO   ÚremoveProcessr2   r   r   r    Útest_removeProcessë   s
    
zProcmonTests.test_removeProcessc                 C   s    | j  ¡  |  t| j jd¡ dS )zz
        L{ProcessMonitor.removeProcess} raises a C{KeyError} if the given
        process name isn't recognised.
        r@   N)r;   rU   rZ   r[   rb   r2   r   r   r    Ú!test_removeProcessUnknownKeyErrorö   s    
z.ProcmonTests.test_removeProcessUnknownKeyErrorc                 C   sH   | j  ddg¡ | j  d¡ |  | j jd t¡ |  d| j j ¡ ¡ dS )a  
        When a process has been started, an instance of L{LoggingProtocol} will
        be added to the L{ProcessMonitor.protocols} dict and the start time of
        the process will be recorded in the L{ProcessMonitor.timeStarted}
        dictionary.
        r@   N)	r;   rF   ÚstartProcessZassertIsInstancerT   r	   rH   ÚtimeStartedrX   r2   r   r   r    Útest_startProcessþ   s    zProcmonTests.test_startProcessc                 C   s2   | j  ddg¡ | j  d¡ |  | j  d¡¡ dS )zr
        L{ProcessMonitor.startProcess} silently returns if the named process is
        already started.
        r@   N)r;   rF   re   ÚassertIsNoner2   r   r   r    Útest_startProcessAlreadyStarted
  s    z,ProcmonTests.test_startProcessAlreadyStartedc                 C   s   |   t| jjd¡ dS )zy
        L{ProcessMonitor.startProcess} raises a C{KeyError} if the given
        process name isn't recognised.
        r@   N)rZ   r[   r;   re   r2   r   r   r    Ú test_startProcessUnknownKeyError  s    z-ProcmonTests.test_startProcessUnknownKeyErrorc                 C   s�   | j  ¡  | j  ddg¡ |  d| j j¡ d }| j jd j_| j | j j	¡ | j  
d¡ | j |¡ | j d¡ |  | j ¡ | j jd ¡ dS )zm
        L{ProcessMonitor.stopProcess} immediately sends a TERM signal to the
        named process.
        r@   r   r   N)r;   rU   rF   rH   rT   Ú	transportr%   r   rV   r>   ÚstopProcessrP   Úsecondsrf   )r   Z	timeToDier   r   r    Ú"test_stopProcessNaturalTermination  s    
z/ProcmonTests.test_stopProcessNaturalTerminationc                 C   sÄ   | j  ¡  | j  ddg¡ |  d| j j¡ | j | j j¡ | j jd j}| j j	d |_
| j  d¡ | j | j j	d ¡ |  d| j jd ¡ | j d¡ | j ddg¡ |  | j ¡ | j jd ¡ dS )z•
        L{ProcessMonitor.stopProcess} kills a process which fails to terminate
        naturally within L{ProcessMonitor.killTime} seconds.
        r@   r   g        r   N)r;   rU   rF   rH   rT   r   rV   r>   rk   ÚkillTimer%   rl   rP   rf   Zpumprm   )r   r5   r   r   r    Útest_stopProcessForcedKill8  s    
z'ProcmonTests.test_stopProcessForcedKillc                 C   s   |   t| jjd¡ dS )zx
        L{ProcessMonitor.stopProcess} raises a C{KeyError} if the given process
        name isn't recognised.
        r@   N)rZ   r[   r;   rl   r2   r   r   r    Útest_stopProcessUnknownKeyErrorU  s    z,ProcmonTests.test_stopProcessUnknownKeyErrorc                 C   s&   | j  ddg¡ |  | j  d¡¡ dS )zá
        L{ProcessMonitor.stopProcess} silently returns if the named process
        is already stopped. eg Process has crashed and a restart has been
        rescheduled, but in the meantime, the service is stopped.
        r@   N)r;   rF   rh   rl   r2   r   r   r    Útest_stopProcessAlreadyStopped\  s    z+ProcmonTests.test_stopProcessAlreadyStoppedc                 C   sì   g }|   tj|j¡ t |j¡ | j ddg¡ | j ¡  | j 	d¡ |  
d| jj¡ | j 	| jj¡ | jjd  d¡ |  t|ƒd¡ |d d }|d d }|d d }|d d }|  |d	¡ |  |d
¡ |  |d¡ |  |d¡ dS )zS
        Getting a complete output line on stdout generates a log message.
        r@   r   ó   hello world!
r   Úlog_namespaceÚstreamÚtagÚlineú%twisted.runner.procmon.ProcessMonitorÚstdoutúhello world!N)Ú
addCleanupr   ÚremoveObserverr3   ÚaddObserverr;   rF   rU   r   rV   rH   rT   r>   ÚoutReceivedÚassertEqualsra   ©r   ÚeventsÚ	namespaceru   rv   rw   r   r   r    Útest_outputReceivedCompleteLinee  s$    
z,ProcmonTests.test_outputReceivedCompleteLinec                 C   sì   g }|   tj|j¡ t |j¡ | j ddg¡ | j ¡  | j 	d¡ |  
d| jj¡ | j 	| jj¡ | jjd  d¡ |  t|ƒd¡ |d d }|d d }|d d }|d d }|  |d	¡ |  |d
¡ |  |d¡ |  |d¡ dS )zS
        Getting a complete output line on stderr generates a log message.
        r@   r   rs   r   rt   ru   rv   rw   rx   Ústderrrz   N)r{   r   r|   r3   r}   r;   rF   rU   r   rV   rH   rT   r>   ZerrReceivedr   ra   r€   r   r   r    Ú!test_ouputReceivedCompleteErrLine€  s$    
z.ProcmonTests.test_ouputReceivedCompleteErrLinec                 C   sè   g }|   tj|j¡ t |j¡ | j ddg¡ | j ¡  | j 	d¡ |  
d| jj¡ | j 	| jj¡ | jjd  d¡ |  t|ƒd¡ |d }|d }|d }|d }|d }|  |d	¡ |  |d
¡ |  |d¡ |  |tdƒ¡ dS )zN
        Getting invalid UTF-8 results in the repr of the raw message
        r@   r   s   ÿhello world!
r   rt   ru   rv   rw   rx   ry   s   ÿhello world!N)r{   r   r|   r3   r}   r;   rF   rU   r   rV   rH   rT   r>   r~   r   ra   rG   )r   r�   Úmessager‚   ru   rv   Úoutputr   r   r    Ú*test_outputReceivedCompleteLineInvalidUTF8›  s&    
z7ProcmonTests.test_outputReceivedCompleteLineInvalidUTF8c                 C   s  g }|   tj|j¡ t |j¡ | j ddg¡ | j ¡  | j 	d¡ |  
d| jj¡ | j 	| jj¡ | jjd  d¡ |  t|ƒd¡ | jjd  ttdƒƒ¡ |  t|ƒd¡ |d d }|d d }|d d }|d d }|  |d	¡ |  |d
¡ |  |d¡ |  |d¡ dS )zM
        Getting partial line results in no events until process end
        r@   r   s   hello world!r   rt   ru   rv   rw   rx   ry   rz   N)r{   r   r|   r3   r}   r;   rF   rU   r   rV   rH   rT   r>   r~   r   ra   r'   r   r   r€   r   r   r    Útest_outputReceivedPartialLine·  s(    
z+ProcmonTests.test_outputReceivedPartialLinec                 C   s�   | j  ddg¡ | j  ¡  | j d¡ |  d| j j¡ | j | j j¡ | j jd  t	t
dƒƒ¡ |  d| j j¡ | j d¡ |  d| j j¡ dS )z§
        L{ProcessMonitor.connectionLost} should immediately restart a process
        if it has been running longer than L{ProcessMonitor.threshold} seconds.
        r@   r   N)r;   rF   rU   r   rV   rH   rT   r>   r'   r   r   rM   r2   r   r   r    Ú#test_connectionLostLongLivedProcessÔ  s    
z0ProcmonTests.test_connectionLostLongLivedProcessc                 C   s–   | j  ddg¡ | j  ¡  | j d¡ | j  d¡ |  d| j j¡ | j jd }|  | 	¡ ¡ | j | j j
d jj¡ |  | 	¡ ¡ |  d| j j¡ dS )z¡
        L{ProcessMonitor.connectionLost} cancels a scheduled process killer and
        deletes the DelayedCall from the L{ProcessMonitor.murder} list.
        r@   r   N)r;   rF   rU   r   rV   rl   rH   ZmurderÚ
assertTrueÚactiverT   rk   r%   ÚassertFalserM   )r   ZdelayedCallr   r   r    Útest_connectionLostMurderCancelè  s    
z,ProcmonTests.test_connectionLostMurderCancelc                 C   sj   | j  ¡  | j  ddg¡ |  d| j j¡ | j jd j d¡ | j | j jd jj	¡ |  
d| j j¡ dS )z˜
        L{ProcessMonitor.connectionLost} removes the corresponding
        ProcessProtocol instance from the L{ProcessMonitor.protocols} list.
        r@   r$   N)r;   rU   rF   rH   rT   rk   r+   r   rV   r%   rM   r2   r   r   r    Ú#test_connectionLostProtocolDeletioný  s    
z0ProcmonTests.test_connectionLostProtocolDeletionc                 C   sŒ   d| j _d| j _| j  ¡  | j  ddg¡ |  | j jd | j j¡ | j | j j	d ¡ | j j
d  ttdƒƒ¡ |  | j jd | j j¡ dS )z}
        L{ProcessMonitor.connectionLost} will wait at least minRestartDelay s
        and at most maxRestartDelay s
        r9   é   r@   r   r   N)r;   r<   r=   rU   rF   rP   r)   r   rV   r>   rT   r'   r   r   r2   r   r   r    Ú%test_connectionLostMinMaxRestartDelay	  s    
z2ProcmonTests.test_connectionLostMinMaxRestartDelayc                 C   s�   | j  ¡  | j  ddg¡ | j | j jd ¡ |  d| j j¡ |  | j j	d | j j
¡ | j jd  ttdƒƒ¡ |  | j j	d | j j
d ¡ dS )z|
        L{ProcessMonitor.connectionLost} doubles the restart delay each time
        the process dies too quickly.
        r@   r   r   r9   N)r;   rU   rF   r   rV   r>   rH   rT   rP   r)   r<   r'   r   r   r2   r   r   r    Ú&test_connectionLostBackoffDelayDoubles  s    
z3ProcmonTests.test_connectionLostBackoffDelayDoublesc                 C   s:   | j  ddg¡ | j  ¡  | j d¡ |  d| j j¡ dS )zP
        L{ProcessMonitor.startService} starts all monitored processes.
        r@   r   N)r;   rF   rU   r   rV   rH   rT   r2   r   r   r    Útest_startService'  s    
zProcmonTests.test_startServicec                 C   s˜   | j  ddg¡ | j  ddg¡ | j  ¡  | j | j j¡ |  d| j j¡ |  d| j j¡ | j d¡ | j  ¡  | j | j j	d ¡ |  
i | j j¡ dS )zT
        L{ProcessMonitor.stopService} should stop all monitored processes.
        r@   Úbarr   N)r;   rF   rU   r   rV   r>   rH   rT   ÚstopServicero   rP   r2   r   r   r    Útest_stopService2  s    

zProcmonTests.test_stopServicec                 C   sl   | j  ddg¡ | j  ¡  | j d¡ | j  ¡  | j d¡ t| jjƒ}| ¡ }|  	|g ¡ |  
|j¡ dS )zR
        L{ProcessMonitor.restartAll} succeeds when there is one process.
        r@   r   N)r;   rF   rU   r   rV   Z
restartAllrW   r1   Úpopr   rh   r&   )r   rO   Z	myProcessr   r   r    Ú!test_restartAllRestartsOneProcessH  s    

z.ProcmonTests.test_restartAllRestartsOneProcessc                 C   sš   | j  ddg¡ | j  ¡  | j | j j¡ |  d| j j¡ | j d¡ | j jd  t	t
dƒƒ¡ |  | j jd  ¡ ¡ | j  ¡  |  | j jd  ¡ ¡ dS )ze
        L{ProcessMonitor.stopService} should cancel any scheduled process
        restarts.
        r@   r   r   N)r;   rF   rU   r   rV   r>   rH   rT   r'   r   r   r‹   ZrestartrŒ   r•   r�   r2   r   r   r    Útest_stopServiceCancelRestartsX  s    

z+ProcmonTests.test_stopServiceCancelRestartsc                 C   sx   d| j _d| j _| j  ¡  | j  ddg¡ | j d¡ | j  d¡ | j d¡ | j  ¡  | j d¡ |  	| j j
i ¡ dS )ze
        L{ProcessMonitor.stopService} should cancel all scheduled process
        restarts.
        é   r@   r   é   N)r;   r>   r<   rU   rF   r   rV   rl   r•   rP   rT   r2   r   r   r    Ú(test_stopServiceCleanupScheduledRestartsl  s    

z5ProcmonTests.test_stopServiceCleanupScheduledRestartsN)$r,   r-   r.   r/   r?   rJ   rN   rR   rS   rY   r\   r^   r`   rc   rd   rg   ri   rj   rn   rp   rq   rr   rƒ   r…   rˆ   r‰   rŠ   rŽ   r�   r‘   r’   r“   r–   r˜   r™   rœ   r   r   r   r    r7   ‹   sB   

	

		r7   c                   @   s0   e Zd ZdZdd„ Zdd„ Zdd„ Zdd	„ Zd
S )ÚDeprecationTestszQ
    Tests that check functionality that should be deprecated is deprecated.
    c                 C   s   t ƒ | _t| jd�| _dS )z5
        Create reactor and process monitor.
        r8   N)r0   r   r
   r;   r2   r   r   r    r?   Š  s    zDeprecationTests.setUpc                 C   sx   | j  ddg¡ | j j}|  t|ƒd¡ |  ¡ }d}|D ]$}|  |d t¡ d|d kr8d}q8|  |dt	|ƒ› �¡ d	S )
a   
        _Process.toTuple is deprecated.

        When getting the deprecated processes property, the actual
        data (kept in the class _Process) is converted to a tuple --
        which produces a DeprecationWarning per process so converted.
        r@   r   FÚcategoryZtoTupler†   Tzno tuple deprecation found:N)
r;   rF   rO   r   ra   ÚflushWarningsÚassertIsÚDeprecationWarningr‹   rG   )r   ZmyprocessesÚwarningsZfoundToTupleÚwarningr   r   r    Útest_toTuple‘  s    zDeprecationTests.test_toTuplec                 C   sF   | j j}|  |i ¡ |  ¡ }| d¡}|  |d t¡ |  |g ¡ dS )a  
        Accessing L{ProcessMonitor.processes} results in deprecation warning

        Even when there are no processes, and thus no process is converted
        to a tuple, accessing the L{ProcessMonitor.processes} property
        should generate its own DeprecationWarning.
        r   rž   N)r;   rO   r   rŸ   r—   r    r¡   )r   ZmyProcessesr¢   Úfirstr   r   r    Útest_processes¤  s    
zDeprecationTests.test_processesc                 C   s2   t  | j¡ |  ¡ }|D ]}|  |d t¡ qdS )zO
        Pickling an L{ProcessMonitor} results in deprecation warnings
        rž   N)ÚpickleÚdumpsr;   rŸ   r    r¡   )r   r¢   r£   r   r   r    Útest_getstate³  s    zDeprecationTests.test_getstateN)r,   r-   r.   r/   r?   r¤   r¦   r©   r   r   r   r    r�   „  s
   r�   )r/   r§   Ztwisted.internet.errorr   r   r   Ztwisted.internet.taskr   Ztwisted.internet.testingr   Ztwisted.loggerr   Ztwisted.python.failurer   Ztwisted.runner.procmonr	   r
   Ztwisted.trialr   r   r0   ZTestCaser7   ZSynchronousTestCaser�   r   r   r   r    Ú<module>   s   J/   |