o
    b8                     @   sd  d Z ddlZddlmZ ddlmZ ddlmZ ddl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mZ ddlZddlmZ dd	l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' ddl(m)Z)m*Z* ddl%m+Z+ G dd dej,j-j.Z/eddG dd de+Z0G dd de)Z1G dd dZ2G dd dZ3G dd dZ4G dd  d Z5dS )!z2
Tests for L{twisted.application.runner._runner}.
    N)StringIO)SIGTERM)TracebackType)	AnyIterableListOptionalTextIOTupleTypeUnioncast)Factoryattribattrs)MemoryReactor)FileLogObserverFilteringLogObserverILogObserverLogBeginnerLogLevelLogLevelFilterPredicateLogPublisher)FilePath   )_runner   )
ExitStatus)NonePIDFilePIDFile)Runnerc                   @   s   e Zd ZdZd)dee defddZd*ddZd*d	d
Z	d*ddZ
d*ddZd*ddZd*ddZd*ddZd*ddZd*ddZd*ddZd*ddZd*ddZd*dd Zd*d!d"Zd*d#d$Zd)d%ed&ee ddfd'd(ZdS )+RunnerTestsz
    Tests for L{Runner}.
    Ncontentreturnc                 C   s"   t |  }|d ur|| |S N)r   mktemp
setContent)selfr"   filePath r)   M/usr/lib/python3/dist-packages/twisted/application/runner/test/test_runner.pyr(   '   s   
zRunnerTests.filePathc                 C   s   t  | _t | _| td| j | td| j d| _| j d | _t	 | _
t	 | _t| j
| j| _t | _t | _t| j| jj| j| j| _| td| j | td| j d S )Nexitkilli9  
stderrglobalLogBeginner)	DummyExitr+   	DummyKillr,   patchr   pidencodepidFileContentr   stdoutr.   DummyStandardIOstdioDummyWarningsModulewarningsr   globalLogPublisherr   r/   r'   r)   r)   r*   setUp-   s&   zRunnerTests.setUpc                 C   s*   t t d}|  | |jg d dS )zD
        L{Runner.run} calls the expected methods in order.
        reactor)killIfRequestedstartLoggingstartReactorreactorExitedN)DummyRunnerr   runassertEqualcalledMethodsr'   runnerr)   r)   r*   test_runInOrderO   s   zRunnerTests.test_runInOrderc                 C   sP   t  }tt |d}| |j | |j |  | |j | |j dS )z;
        L{Runner.run} uses the provided PID file.
        r?   pidFileN)DummyPIDFiler    r   assertFalseenteredexitedrE   
assertTruer'   rL   rI   r)   r)   r*   test_runUsesPIDFile`   s   zRunnerTests.test_runUsesPIDFilec                 C   sV   t | | j}dd |_tt |d}|  | | jj	t
j | | jjd dS )z
        L{Runner.run} exits with L{ExitStatus.EX_USAGE} and the expected
        message if a process is already running that corresponds to the given
        PID file.
        c                   S      dS NTr)   r)   r)   r)   r*   <lambda>w       z4RunnerTests.test_runAlreadyRunning.<locals>.<lambda>rK   zAlready running.N)r   r(   r5   	isRunningr    r   rE   rF   r+   statusr   	EX_CONFIGmessagerR   r)   r)   r*   test_runAlreadyRunningp   s   
z"RunnerTests.test_runAlreadyRunningc                 C   s6   t t d}|  | | jjg  | | jj dS )z
        L{Runner.killIfRequested} when C{kill} is false doesn't exit and
        doesn't indiscriminately murder anyone.
        r>   N)	r    r   r@   rF   r,   callsrN   r+   rP   rH   r)   r)   r*   test_killNotRequested   s   z!RunnerTests.test_killNotRequestedc                 C   sL   t t dd}|  | | jjg  | | jjtj	 | | jj
d dS )z
        L{Runner.killIfRequested} when C{kill} is true but C{pidFile} is
        L{nonePIDFile} exits with L{ExitStatus.EX_USAGE} and the expected
        message; and also doesn't indiscriminately murder anyone.
        T)r?   r,   zNo PID file specified.N)r    r   r@   rF   r,   r]   r+   rY   r   EX_USAGEr[   rH   r)   r)   r*    test_killRequestedWithoutPIDFile   s
   z,RunnerTests.test_killRequestedWithoutPIDFilec                 C   sf   t | | j}tt d|d}|  | | jj| j	t
fg | | jjtj | | jjd dS )z
        L{Runner.killIfRequested} when C{kill} is true and given a C{pidFile}
        performs a targeted killing of the appropriate process.
        Tr?   r,   rL   N)r   r(   r5   r    r   r@   rF   r,   r]   r3   r   r+   rY   r   EX_OKassertIdenticalr[   rR   r)   r)   r*   test_killRequestedWithPIDFile   s   z)RunnerTests.test_killRequestedWithPIDFilec                 C   s`   t | d}dtfdd}||_tt d|d}|  | | jj	t
j | | jjd dS )z
        L{Runner.killIfRequested} when C{kill} is true and given a C{pidFile}
        that it can't read exits with L{ExitStatus.EX_IOERR}.
        Nr#   c                   S   s   t tjd)NzPermission denied)OSErrorerrnoEACCESr)   r)   r)   r*   read   s   z?RunnerTests.test_killRequestedWithPIDFileCantRead.<locals>.readTra   zUnable to read PID file.)r   r(   intrh   r    r   r@   rF   r+   rY   r   EX_IOERRr[   )r'   rL   rh   rI   r)   r)   r*   %test_killRequestedWithPIDFileCantRead   s   z1RunnerTests.test_killRequestedWithPIDFileCantReadc                 C   L   t | d}tt d|d}|  | | jjtj	 | | jj
d dS )z
        L{Runner.killIfRequested} when C{kill} is true and given a C{pidFile}
        containing no value exits with L{ExitStatus.EX_DATAERR}.
            Tra   Invalid PID file.Nr   r(   r    r   r@   rF   r+   rY   r   
EX_DATAERRr[   rR   r)   r)   r*   "test_killRequestedWithPIDFileEmpty   
   z.RunnerTests.test_killRequestedWithPIDFileEmptyc                 C   rl   )z
        L{Runner.killIfRequested} when C{kill} is true and given a C{pidFile}
        containing a non-integer value exits with L{ExitStatus.EX_DATAERR}.
        s    ** totally not a number, dude **Tra   rn   Nro   rR   r)   r)   r*   %test_killRequestedWithPIDFileNotAnInt   rr   z1RunnerTests.test_killRequestedWithPIDFileNotAnIntc                    s  t  }G  fddd | td   G fdddt| td G fdddttt tj|d	}|	  | 
t jd
 |  jd t | 
tjd
 | jd t | jd jtj tj}| | | |j| dS )z
        L{Runner.startLogging} sets up a filtering observer with a log level
        predicate set to the given log level that contains a file observer of
        the given type which writes to the given file.
        c                       s8   e Zd ZU g Zee ed< dee ddf fddZdS )z2RunnerTests.test_startLogging.<locals>.LogBeginner	observersr#   Nc                    s   t | _d S r$   )listrt   )r'   rt   r   r)   r*   beginLoggingTo      zARunnerTests.test_startLogging.<locals>.LogBeginner.beginLoggingTo)	__name__
__module____qualname__rt   r   r   __annotations__r   rw   r)   rv   r)   r*   r      s   
 r   r/   c                       sZ   e Zd ZU dZee ed< g Zee	 ed< e
edd fdedee	 def fddZdS )	z?RunnerTests.test_startLogging.<locals>.MockFilteringLogObserverNobserver
predicatesc                 S   s   d S r$   r)   )eventr)   r)   r*   rV      rW   zHRunnerTests.test_startLogging.<locals>.MockFilteringLogObserver.<lambda>negativeObserverc                    s$   | _ t| _t| ||| d S r$   )r}   ru   r~   r   __init__)r'   r}   r~   r   MockFilteringLogObserverr)   r*   r      s
   
zHRunnerTests.test_startLogging.<locals>.MockFilteringLogObserver.__init__)ry   rz   r{   r}   r   r   r|   r~   r   r   r   r   r   r)   r   r)   r*   r      s   
 r   r   c                       s4   e Zd ZU dZee ed< deddf fddZdS )z:RunnerTests.test_startLogging.<locals>.MockFileLogObserverNoutFiler#   c                    s   | _ t| |t d S r$   )r   r   r   str)r'   r   MockFileLogObserverr)   r*   r      s   zCRunnerTests.test_startLogging.<locals>.MockFileLogObserver.__init__)ry   rz   r{   r   r   r	   r|   r   r)   r   r)   r*   r      s   
 r   )r?   defaultLogLevellogFilefileLogObserverFactory   r   N)r   r2   r   r   r   r    r   r   criticalrA   rF   lenrt   assertIsInstancer~   r   rc   r   r   r}   r   )r'   r   rI   r}   r)   )r   r   r   r*   test_startLogging   s2   
zRunnerTests.test_startLoggingc                 C   s(   t  }t|d}|  | |j dS )ze
        L{Runner.startReactor} with the C{reactor} argument runs the given
        reactor.
        r>   N)r   r    rB   rQ   hasRun)r'   r?   rI   r)   r)   r*   test_startReactorWithReactor  s   
z(RunnerTests.test_startReactorWithReactorc                 C   s   |  dd dS )z
        L{Runner.startReactor} ensures that C{whenRunning} is called with
        C{whenRunningArguments} when the reactor is running.
        whenRunningrB   N	_testHookr<   r)   r)   r*   test_startReactorWhenRunning&  s   z(RunnerTests.test_startReactorWhenRunningc                 C      |  d dS )zb
        L{Runner.whenRunning} calls C{whenRunning} with
        C{whenRunningArguments}.
        r   Nr   r<   r)   r)   r*   test_whenRunningWithArguments-     z)RunnerTests.test_whenRunningWithArgumentsc                 C   r   )zf
        L{Runner.whenRunning} calls C{reactorExited} with
        C{reactorExitedArguments}.
        rC   Nr   r<   r)   r)   r*   test_reactorExitedWithArguments4  r   z+RunnerTests.test_reactorExitedWithArguments
methodName
callerNamec                    s   |du r|}t t t t d}g  dtddf fdd}||| d| i}tddt i|}t||}|  | t d	 |  d
 | dS )a  
        Verify that the named hook is run with the expected arguments as
        specified by the arguments used to create the L{Runner}, when the
        specified caller is invoked.

        @param methodName: The name of the hook to verify.

        @param callerName: The name of the method that is expected to cause the
            hook to be called.
            If C{None}, use the L{Runner} method with the same name as the
            hook.
        N)abc	argumentsr#   c                     s     |  d S r$   )append)r   argumentsSeenr)   r*   hookN  rx   z#RunnerTests._testHook.<locals>.hook	Argumentsr?   r   r   r)   )dictobjectcopyr    r   getattrrF   r   )r'   r   r   r   r   runnerArgumentsrI   
hookCallerr)   r   r*   r   ;  s"   
zRunnerTests._testHookr$   r#   N)ry   rz   r{   __doc__r   bytesr   r(   r=   rJ   rS   r\   r^   r`   rd   rk   rq   rs   r   r   r   r   r   r   r   r)   r)   r)   r*   r!   "   s&    

"









M


 r!   T)frozenc                   @   sL   e Zd ZdZeee eedZ	dddZ
dddZdd	d
ZdddZdS )rD   zg
    Stub for L{Runner}.

    Keep track of calls to some methods without actually doing anything.
    )typedefaultr#   Nc                 C      | j d d S )Nr@   rG   r   r<   r)   r)   r*   r@   j     zDummyRunner.killIfRequestedc                 C   r   )NrA   r   r<   r)   r)   r*   rA   m  r   zDummyRunner.startLoggingc                 C   r   )NrB   r   r<   r)   r)   r*   rB   p  r   zDummyRunner.startReactorc                 C   r   )NrC   r   r<   r)   r)   r*   rC   s  r   zDummyRunner.reactorExitedr   )ry   rz   r{   r   r   r   r   r   ru   rG   r@   rA   rB   rC   r)   r)   r)   r*   rD   `  s    


rD   c                   @   sN   e Zd ZdZdddZdddZdeee  d	ee d
ee	 ddfddZ
dS )rM   z]
    Stub for L{PIDFile}.

    Tracks context manager entry/exit without doing anything.
    r#   Nc                 C   s   t |  d| _d| _d S NF)r   r   rO   rP   r<   r)   r)   r*   r   ~  s   

zDummyPIDFile.__init__c                 C   s
   d| _ | S rU   )rO   r<   r)   r)   r*   	__enter__  s   zDummyPIDFile.__enter__excTypeexcValue	tracebackc                 C   
   d| _ d S rU   rP   )r'   r   r   r   r)   r)   r*   __exit__  s   
zDummyPIDFile.__exit__r   )r#   rM   )ry   rz   r{   r   r   r   r   r   BaseExceptionr   r   r)   r)   r)   r*   rM   w  s    


rM   c                   @   s@   e Zd ZdZd
ddZ	ddeeef dee	 ddfdd	Z
dS )r0   zy
    Stub for L{_exit.exit} that remembers whether it's been called and, if it has,
    what arguments it was given.
    r#   Nc                 C   r   r   r   r<   r)   r)   r*   r        
zDummyExit.__init__rY   r[   c                 C   s    | j rJ || _|| _d| _ d S rU   )rP   rY   r[   )r'   rY   r[   r)   r)   r*   __call__  s   

zDummyExit.__call__r   r$   )ry   rz   r{   r   r   r   ri   r   r   r   r   r)   r)   r)   r*   r0     s    

r0   c                   @   s0   e Zd ZdZd
ddZdededdfdd	ZdS )r1   zv
    Stub for L{os.kill} that remembers whether it's been called and, if it has,
    what arguments it was given.
    r#   Nc                 C   s
   g | _ d S r$   )r]   r<   r)   r)   r*   r     r   zDummyKill.__init__r3   sigc                 C   s   | j ||f d S r$   )r]   r   )r'   r3   r   r)   r)   r*   r     s   zDummyKill.__call__r   )ry   rz   r{   r   r   ri   r   r)   r)   r)   r*   r1     s    
r1   c                   @   &   e Zd ZdZdededdfddZdS )r7   zR
    Stub for L{sys} which provides L{StringIO} streams as stdout and stderr.
    r6   r.   r#   Nc                 C   s   || _ || _d S r$   )r6   r.   )r'   r6   r.   r)   r)   r*   r     s   
zDummyStandardIO.__init__)ry   rz   r{   r   r	   r   r)   r)   r)   r*   r7         r7   c                   @   r   )r9   zV
    Stub for L{warnings} which provides a C{showwarning} method that is a no-op.
    argskwargsr#   Nc                  O   rT   )z\
        Do nothing.

        @param args: ignored.
        @param kwargs: ignored.
        Nr)   )r   r   r)   r)   r*   showwarning  rW   zDummyWarningsModule.showwarning)ry   rz   r{   r   r   r   r)   r)   r)   r*   r9     r   r9   )6r   rf   ior   signalr   typesr   typingr   r   r   r   r	   r
   r   r   r   attrr   r   r   twisted.trial.unittesttwistedtwisted.internet.testingr   twisted.loggerr   r   r   r   r   r   r   twisted.python.filepathr   rI   r   _exitr   _pidfiler   r   r    trialunittestTestCaser!   rD   rM   r0   r1   r7   r9   r)   r)   r)   r*   <module>   s2   ,$	  @
