o
    ¯b1  ã                   @   s²   d Z ddlZddlZddlmZmZ ddlmZ ddlm	Z	m
Z
mZ G dd„ deƒZG d	d
„ d
eƒZG dd„ dƒZG dd„ dƒZG dd„ dƒZG dd„ deƒZG dd„ deƒZdS )z.
Tests for L{twisted._threads._threadworker}.
é    N)ÚThreadErrorÚlocal)ÚSynchronousTestCaseé   )ÚAlreadyQuitÚ
LockWorkerÚThreadWorkerc                   @   ó   e Zd ZdZdS )ÚFakeQueueEmptyz8
    L{FakeQueue}'s C{get} has exhausted the queue.
    N©Ú__name__Ú
__module__Ú__qualname__Ú__doc__© r   r   úI/usr/lib/python3/dist-packages/twisted/_threads/test/test_threadworker.pyr
      ó    r
   c                   @   r	   )ÚWouldDeadlockzf
    If this were a real lock, you'd be deadlocked because the lock would be
    double-acquired.
    Nr   r   r   r   r   r      r   r   c                   @   s    e Zd ZdZdd„ Zdd„ ZdS )Ú
FakeThreadz½
    A fake L{threading.Thread}.

    @ivar target: A target function to run.
    @type target: L{callable}

    @ivar started: Has this thread been started?
    @type started: L{bool}
    c                 C   s   || _ d| _dS )z7
        Create a L{FakeThread} with a target.
        FN)ÚtargetÚstarted)Úselfr   r   r   r   Ú__init__)   s   
zFakeThread.__init__c                 C   ó
   d| _ dS )z)
        Set the "started" flag.
        TN)r   ©r   r   r   r   Ústart0   ó   
zFakeThread.startN)r   r   r   r   r   r   r   r   r   r   r      s    
r   c                   @   ó(   e Zd ZdZdd„ Zdd„ Zdd„ ZdS )	Ú	FakeQueuez­
    A fake L{Queue} implementing C{put} and C{get}.

    @ivar items: A lit of items placed by C{put} but not yet retrieved by
        C{get}.
    @type items: L{list}
    c                 C   s
   g | _ dS )z(
        Create a L{FakeQueue}.
        N)Úitemsr   r   r   r   r   @   r   zFakeQueue.__init__c                 C   s   | j  |¡ dS )zv
        Put an item into the queue for later retrieval by L{FakeQueue.get}.

        @param item: any object
        N)r   Úappend)r   Úitemr   r   r   ÚputF   s   zFakeQueue.putc                 C   s   | j stƒ ‚| j  d¡S )zR
        Get an item.

        @return: an item previously put by C{put}.
        r   )r   r
   Úpopr   r   r   r   ÚgetN   s   zFakeQueue.getN)r   r   r   r   r   r"   r$   r   r   r   r   r   7   s
    r   c                   @   r   )	ÚFakeLockzi
    A stand-in for L{threading.Lock}.

    @ivar acquired: Whether this lock is presently acquired.
    c                 C   r   )z9
        Create a lock in the un-acquired state.
        FN)Úacquiredr   r   r   r   r   `   r   zFakeLock.__init__c                 C   s   | j rtƒ ‚d| _ dS )zX
        Acquire the lock.  Raise an exception if the lock is already acquired.
        TN)r&   r   r   r   r   r   Úacquiref   s   
zFakeLock.acquirec                 C   s   | j stƒ ‚d| _ dS )zf
        Release the lock.  Raise an exception if the lock is not presently
        acquired.
        FN)r&   r   r   r   r   r   Úreleasen   s   
zFakeLock.releaseN)r   r   r   r   r   r'   r(   r   r   r   r   r%   Y   s
    r%   c                   @   r   )	ÚThreadWorkerTestsz$
    Tests for L{ThreadWorker}.
    c                    s,   g ˆ _ tƒ ˆ _‡ fdd„}t|ˆ jƒˆ _dS )z4
        Create a worker with fake threads.
        c                    s"   t | d�}| ¡  ˆ j |¡ |S )N)r   )r   r   ÚfakeThreadsr    )r   Ú	newThreadr   r   r   ÚstartThread„   s   
z,ThreadWorkerTests.setUp.<locals>.startThreadN)r*   r   Ú	fakeQueuer   Úworker)r   r,   r   r   r   ÚsetUp}   s   zThreadWorkerTests.setUpc                    sx   |   t| jƒd¡ |   | jd jd¡ ‡ fdd„‰ dˆ _| j ˆ ¡ |   ˆ jd¡ |  t| jd j	¡ |   ˆ jd¡ dS )zÐ
        L{ThreadWorker} calls its C{createThread} callable to create a thread,
        its C{createQueue} callable to create a queue, and then the thread's
        target pulls work from that queue.
        é   r   Tc                      s
   dˆ _ d S ©NT)Údoner   ©ÚdoItr   r   r4   •   s   
z@ThreadWorkerTests.test_startsThreadAndPerformsWork.<locals>.doItFN)
ÚassertEqualÚlenr*   r   r2   r.   ÚdoÚassertRaisesr
   r   r   r   r3   r   Ú test_startsThreadAndPerformsWorkŒ   s   z2ThreadWorkerTests.test_startsThreadAndPerformsWorkc                 C   s0   | j  ¡  |  t| j j¡ |  t| j jt¡ dS )zŠ
        L{ThreadWorker.quit} causes future calls to L{ThreadWorker.do} and
        L{ThreadWorker.quit} to raise L{AlreadyQuit}.
        N)r.   Úquitr8   r   r7   Úlistr   r   r   r   Útest_quitPreventsFutureCallsž   s   
z.ThreadWorkerTests.test_quitPreventsFutureCallsN)r   r   r   r   r/   r9   r<   r   r   r   r   r)   x   s
    r)   c                   @   sH   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S )ÚLockWorkerTestsz"
    Tests for L{LockWorker}.
    c                 C   s    t ƒ }| ¡  |  t|j¡ dS )ze
        The L{FakeLock} test fixture will alert us if there's a potential
        deadlock.
        N)r%   r'   r8   r   ©r   Úlockr   r   r   Útest_fakeDeadlock­   s   z!LockWorkerTests.test_fakeDeadlockc                 C   s>   t ƒ }|  t|j¡ | ¡  |  d| ¡ ¡ |  t|j¡ dS )zk
        The L{FakeLock} test fixture will alert us if there's a potential
        double-release.
        N)r%   r8   r   r(   r'   r5   r>   r   r   r   Útest_fakeDoubleRelease¶   s
   z&LockWorkerTests.test_fakeDoubleReleasec                    sb   t ƒ }tƒ ‰ tˆ |ƒ}‡ ‡fdd„‰dˆ_| ˆ¡ |  ˆjd¡ |  ˆjd¡ |  ˆ jd¡ dS )zp
        L{LockWorker.do} immediately performs the work it's given, while the
        lock is acquired.
        c                      ó   dˆ_ ˆ jˆ_d S r1   )r2   r&   r   ©r?   Úworkr   r   rD   Ê   ó   z@LockWorkerTests.test_doExecutesImmediatelyWithLock.<locals>.workFTN)r   r%   r   r2   r7   r5   r&   )r   Ústorager.   r   rC   r   Ú"test_doExecutesImmediatelyWithLockÁ   s   

z2LockWorkerTests.test_doExecutesImmediatelyWithLockc                    sb   t ƒ ‰tˆtƒ ƒ‰g ‰g ‰ ‡ ‡‡‡‡fdd„‰dˆ_ˆ ˆ¡ |  ˆddg¡ |  ˆ ddg¡ dS )z�
        If L{LockWorker.do} is called recursively, it postpones the inner call
        until the outer one is complete.
        c                      sN   ˆ j d7  _ ˆ ˆj ¡ ˆ  ˆj¡ tˆƒdk rˆ ˆ¡ ˆ j d8  _ d S )Nr0   r   )Úlevelr    r&   r6   r7   r   ©r&   Úlevelsr?   rD   r.   r   r   rD   Þ   s   
z6LockWorkerTests.test_doUnwindsReentrancy.<locals>.workr   r0   TN)r%   r   r   rH   r7   r5   r   r   rI   r   Útest_doUnwindsReentrancyÔ   s   
z(LockWorkerTests.test_doUnwindsReentrancyc                 C   sn   t ƒ }t |¡}t|tƒ ƒ}d}|  |ƒ d¡ | ¡  t ¡  |  	|ƒ d¡ |  
t|j¡ |  
t|jt¡ dS )z�
        L{LockWorker.quit} frees the resources associated with its lock and
        causes further calls to C{do} and C{quit} to fail.
        N)r%   ÚweakrefÚrefr   r   ÚassertIsNotr:   ÚgcÚcollectÚassertIsr8   r   r7   r;   )r   r?   rM   r.   r   r   r   Ú	test_quitë   s   
zLockWorkerTests.test_quitc                    sš   t ƒ ‰ t ˆ ¡}tˆ tƒ ƒ‰‡‡‡‡fdd„‰dˆ_‡ ‡fdd„‰dˆ_ˆ ˆ¡ ˆ ˆjd¡ ˆ ˆjd¡ ˆ ˆ jd¡ d‰ t	 
¡  ˆ |ƒ d¡ dS )zÉ
        If L{LockWorker.quit} is invoked during a call to L{LockWorker.do}, all
        recursive work scheduled with L{LockWorker.do} will be completed and
        the lock will be released.
        c                      s,   ˆ  ˆ¡ ˆ ¡  ˆ tˆj t¡ dˆ _d S r1   )r7   r:   r8   r   r;   Úcompleter   )Úphase1Úphase2r   r.   r   r   rT     s   

z5LockWorkerTests.test_quitWhileWorking.<locals>.phase1Fc                      rB   r1   )rS   r&   r   )r?   rU   r   r   rU     rE   z5LockWorkerTests.test_quitWhileWorking.<locals>.phase2TN)r%   rL   rM   r   r   rS   r7   r5   r&   rO   rP   rQ   )r   rM   r   )r?   rT   rU   r   r.   r   Útest_quitWhileWorkingû   s   

z%LockWorkerTests.test_quitWhileWorkingc                 C   s2   G dd„ dt ƒ}|tƒ tƒ ƒ}|  t|jt¡ dS )zÉ
        If L{LockWorker.do} is called concurrently with L{LockWorker.quit}, and
        C{quit} wins the race before C{do} gets the lock attribute, then
        L{AlreadyQuit} will be raised.
        c                   @   s&   e Zd Zedd„ ƒZejdd„ ƒZdS )zALockWorkerTests.test_quitWhileGettingLock.<locals>.RacyLockWorkerc                 S   s   |   ¡  | jd S ©NÚ_lock)r:   Ú__dict__r   r   r   r   rX   "  s   
zGLockWorkerTests.test_quitWhileGettingLock.<locals>.RacyLockWorker._lockc                 S   s   || j d< d S rW   )rY   )r   Úvaluer   r   r   rX   '  s   N)r   r   r   ÚpropertyrX   Úsetterr   r   r   r   ÚRacyLockWorker!  s
    
r]   N)r   r%   r   r8   r   r7   r;   )r   r]   r.   r   r   r   Útest_quitWhileGettingLock  s   
z)LockWorkerTests.test_quitWhileGettingLockN)r   r   r   r   r@   rA   rG   rK   rR   rV   r^   r   r   r   r   r=   ¨   s    	r=   )r   rO   rL   Ú	threadingr   r   Útwisted.trial.unittestr   Ú r   r   r   Ú	Exceptionr
   r   r   r   r%   r)   r=   r   r   r   r   Ú<module>   s   "0