o
    ¯bía  ã                   @   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mZ ddl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)ÚglobalLogPublisher)ÚFailure)ÚLoggingProtocolÚProcessMonitor)ÚMemoryReactor)Úunittestc                   @   s>   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Ú_pathÚ_uidÚ_gidÚ_usePTYÚ	_childFDs)ÚselfÚreactorÚ
executableÚargsÚenvironmentÚpathr   ÚuidÚgidÚusePTYÚchildFDs© r#   úB/usr/lib/python3/dist-packages/twisted/runner/test/test_procmon.pyÚ__init__    s   
zDummyProcess.__init__c                 C   sP   | j dfddœ}| jdu rtƒ ‚||v r&|| \}}| j || j|¡| _dS 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   Ú	callLaterÚprocessEndedÚ_signalHandler)r   ÚsignalIDÚparamsÚdelayÚstatusr#   r#   r$   ÚsignalProcess:   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   r1   Ú	statusMapr#   r#   r$   r,   Q   s
   þzDummyProcess.processEnded)NNr   N)
Ú__name__Ú
__module__Ú__qualname__Ú__doc__r*   r   r)   r%   r2   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%   d   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   ÚmakeConnectionr9   Úappend)r   ÚprocessProtocolr   r   Úenvr   r   r    r!   r"   Úprocr#   r#   r$   ÚspawnProcessj   s   ö
z DummyProcessReactor.spawnProcess)r4   r5   r6   r7   r%   r@   r#   r#   r#   r$   r8   ]   s    
ör8   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)r8   r   r	   ÚpmÚminRestartDelayÚmaxRestartDelayÚ	thresholdr:   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   rC   ©r   r    r>   Ú1Ú2N)rE   Ú
addProcessÚreprÚassertIn©r   Ú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.
        rJ   rK   rL   )r>   ú(ú)N)rE   rP   rQ   ÚassertNotInrS   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.
        rJ   rK   rL   r   rC   rM   Ú	processesN)rE   rP   ÚassertEqualÚ__getstate__r:   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)rX   rE   r\   r:   r#   r#   r$   Útest_getStateExcludesReactorº   ó   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.
        rJ   rK   rL   r   rC   rM   r   N)
rE   rP   r[   Ú	protocolsrZ   ÚstartServicer   ÚadvanceÚlistÚkeysr:   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.
        rJ   rK   rL   r   rC   rM   N)rE   rP   ÚassertRaisesÚKeyErrorr:   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}.
        ÚKEYÚvaluerJ   r   rC   rM   r   N)rE   ra   rP   r   rb   r[   r9   r   )r   Ú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}.
        rJ   z	/mnt/lala)Úcwdr   N)rE   ra   rP   r   rb   r[   r9   r   r:   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.
        rJ   r   r   N)rE   ra   rP   r[   ÚlenrZ   ÚremoveProcessr:   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.
        rJ   N)rE   ra   rf   rg   rp   r:   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.
        rJ   N)	rE   rP   ÚstartProcessÚassertIsInstancer`   r   rR   ÚtimeStartedrd   r:   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.
        rJ   N)rE   rP   rs   ÚassertIsNoner:   r#   r#   r$   Útest_startProcessAlreadyStarted  s   z,ProcmonTests.test_startProcessAlreadyStartedc                 C   ó   |   t| jjd¡ dS )zy
        L{ProcessMonitor.startProcess} raises a C{KeyError} if the given
        process name isn't recognised.
        rJ   N)rf   rg   rE   rs   r:   r#   r#   r$   Ú test_startProcessUnknownKeyError  r_   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 ¡ | j jd ¡ dS )zm
        L{ProcessMonitor.stopProcess} immediately sends a TERM signal to the
        named process.
        rJ   r   N)rE   ra   rP   rR   r`   Ú	transportr)   r   rb   rH   ÚstopProcessr[   Úsecondsru   )r   Ú	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 ¡ | j jd ¡ dS )z•
        L{ProcessMonitor.stopProcess} kills a process which fails to terminate
        naturally within L{ProcessMonitor.killTime} seconds.
        rJ   r   g        N)rE   ra   rP   rR   r`   r   rb   rH   r{   ÚkillTimer)   r|   r[   ru   r}   )r   r?   r#   r#   r$   Útest_stopProcessForcedKill4  s   
z'ProcmonTests.test_stopProcessForcedKillc                 C   ry   )zx
        L{ProcessMonitor.stopProcess} raises a C{KeyError} if the given process
        name isn't recognised.
        rJ   N)rf   rg   rE   r|   r:   r#   r#   r$   Útest_stopProcessUnknownKeyErrorJ  r_   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.
        rJ   N)rE   rP   rw   r|   r:   r#   r#   r$   Útest_stopProcessAlreadyStoppedQ  s   z+ProcmonTests.test_stopProcessAlreadyStoppedc                 C   óì   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.
        rJ   r   ó   hello world!
r   Úlog_namespaceÚstreamÚtagÚlineú%twisted.runner.procmon.ProcessMonitorÚstdoutúhello world!N)Ú
addCleanupr   ÚremoveObserverr<   ÚaddObserverrE   rP   ra   r   rb   rR   r`   rH   ÚoutReceivedÚassertEqualsro   ©r   ÚeventsÚ	namespacer‡   rˆ   r‰   r#   r#   r$   Útest_outputReceivedCompleteLineZ  ó$   
z,ProcmonTests.test_outputReceivedCompleteLinec                 C   r„   )zS
        Getting a complete output line on stderr generates a log message.
        rJ   r   r…   r   r†   r‡   rˆ   r‰   rŠ   ÚstderrrŒ   N)r   r   rŽ   r<   r   rE   rP   ra   r   rb   rR   r`   rH   ÚerrReceivedr‘   ro   r’   r#   r#   r$   Ú!test_ouputReceivedCompleteErrLineu  r–   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
        rJ   r   s   ÿhello world!
r   r†   r‡   rˆ   r‰   rŠ   r‹   s   ÿhello world!N)r   r   rŽ   r<   r   rE   rP   ra   r   rb   rR   r`   rH   r   r‘   ro   rQ   )r   r“   Úmessager”   r‡   rˆ   Ú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
        rJ   r   s   hello world!r   r†   r‡   rˆ   r‰   rŠ   r‹   rŒ   N)r   r   rŽ   r<   r   rE   rP   ra   r   rb   rR   r`   rH   r   r‘   ro   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.
        rJ   r   N)rE   rP   ra   r   rb   rR   r`   rH   r,   r   r   rX   r:   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.
        rJ   r   N)rE   rP   ra   r   rb   r|   rR   ÚmurderÚ
assertTrueÚactiver`   r{   r)   ÚassertFalserX   )r   Ú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.
        rJ   r(   N)rE   ra   rP   rR   r`   r{   r2   r   rb   r)   rX   r:   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
        rC   é   rJ   r   r   N)rE   rF   rG   ra   rP   r[   r0   r   rb   rH   r`   r,   r   r   r:   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.
        rJ   r   r   rC   N)rE   ra   rP   r   rb   rH   rR   r`   r[   r0   rF   r,   r   r   r:   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.
        rJ   r   N)rE   rP   ra   r   rb   rR   r`   r:   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.
        rJ   Úbarr   N)rE   rP   ra   r   rb   rH   rR   r`   ÚstopServicer€   r[   r:   r#   r#   r$   Útest_stopService'  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.
        rJ   r   N)rE   rP   ra   r   rb   Ú
restartAllrc   r9   Úpopr‘   rw   r*   )r   rZ   Ú	myProcessr#   r#   r$   Ú!test_restartAllRestartsOneProcess=  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.
        rJ   r   r   N)rE   rP   ra   r   rb   rH   rR   r`   r,   r   r   r    Úrestartr¡   r«   r¢   r:   r#   r#   r$   Útest_stopServiceCancelRestartsM  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.
        é   rJ   r   é   N)rE   rH   rF   ra   rP   r   rb   r|   r«   r[   r`   r:   r#   r#   r$   Ú(test_stopServiceCleanupScheduledRestartsa  s   

z5ProcmonTests.test_stopServiceCleanupScheduledRestartsN)$r4   r5   r6   r7   rI   rU   rY   r]   r^   re   rh   rl   rn   rq   rr   rv   rx   rz   r   r   r‚   rƒ   r•   r™   rœ   r   rž   r¤   r¥   r§   r¨   r©   r¬   r°   r²   rµ   r#   r#   r#   r$   rA   Œ   sD    

	

		rA   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.
        rB   N)r8   r   r	   rE   r:   r#   r#   r$   rI     s   zDeprecationTests.setUpc                 C   sx   | j  ddg¡ | j j}|  t|ƒd¡ |  ¡ }d}|D ]}|  |d t¡ d|d v r.d}q|  |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.
        rJ   r   FÚcategoryÚtoTuplerš   Tzno tuple deprecation found:N)
rE   rP   rZ   r‘   ro   ÚflushWarningsÚassertIsÚDeprecationWarningr    rQ   )r   ÚmyprocessesÚwarningsÚ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)rE   rZ   r‘   r¹   r®   rº   r»   )r   Ú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ÚdumpsrE   r¹   rº   r»   )r   r½   r¿   r#   r#   r$   Útest_getstate¨  s
   ÿzDeprecationTests.test_getstateN)r4   r5   r6   r7   rI   rÀ   rÃ   rÆ   r#   r#   r#   r$   r¶   y  s    r¶   )r7   rÄ   Útwisted.internet.errorr   r   r   Útwisted.internet.taskr   Útwisted.loggerr   Útwisted.python.failurer   Útwisted.runner.procmonr   r	   Útwisted.test.proto_helpersr
   Útwisted.trialr   r   r8   ÚTestCaserA   ÚSynchronousTestCaser¶   r#   r#   r#   r$   Ú<module>   s    K/   p