
    Ϫf1                         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e      Z G d	 d
e      Z G d d      Z G d d      Z G d d      Z G d de      Z G d de      Zy)z.
Tests for L{twisted._threads._threadworker}.
    N)ThreadErrorlocal)SynchronousTestCase   )AlreadyQuit
LockWorkerThreadWorkerc                       e Zd ZdZy)FakeQueueEmptyz8
    L{FakeQueue}'s C{get} has exhausted the queue.
    N__name__
__module____qualname____doc__     I/usr/lib/python3/dist-packages/twisted/_threads/test/test_threadworker.pyr   r      s    r   r   c                       e Zd ZdZy)WouldDeadlockzf
    If this were a real lock, you'd be deadlocked because the lock would be
    double-acquired.
    Nr   r   r   r   r   r      s    r   r   c                       e Zd ZdZd Zd Zy)
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                      || _         d| _        y)z7
        Create a L{FakeThread} with a target.
        FN)targetstarted)selfr   s     r   __init__zFakeThread.__init__)   s     r   c                     d| _         y)z)
        Set the "started" flag.
        TN)r   r   s    r   startzFakeThread.start0   s     r   N)r   r   r   r   r   r   r   r   r   r   r      s    r   r   c                   "    e Zd ZdZd Zd Zd Zy)	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                     g | _         y)z(
        Create a L{FakeQueue}.
        N)itemsr   s    r   r   zFakeQueue.__init__@   s     
r   c                 :    | j                   j                  |       y)zv
        Put an item into the queue for later retrieval by L{FakeQueue.get}.

        @param item: any object
        N)r#   append)r   items     r   putzFakeQueue.putF   s     	

$r   c                 d    | j                   s
t               | j                   j                  d      S )zR
        Get an item.

        @return: an item previously put by C{put}.
        r   )r#   r   popr   s    r   getzFakeQueue.getN   s'     zz ""zz~~a  r   N)r   r   r   r   r   r'   r*   r   r   r   r!   r!   7   s     !r   r!   c                   "    e Zd ZdZd Zd Zd Zy)FakeLockzi
    A stand-in for L{threading.Lock}.

    @ivar acquired: Whether this lock is presently acquired.
    c                     d| _         y)z9
        Create a lock in the un-acquired state.
        FN)acquiredr   s    r   r   zFakeLock.__init__`   s     r   c                 >    | j                   r
t               d| _         y)zX
        Acquire the lock.  Raise an exception if the lock is already acquired.
        TN)r.   r   r   s    r   acquirezFakeLock.acquiref   s     ==/!r   c                 >    | j                   s
t               d| _         y)zf
        Release the lock.  Raise an exception if the lock is not presently
        acquired.
        FN)r.   r   r   s    r   releasezFakeLock.releasen   s    
 }}-r   N)r   r   r   r   r   r0   r2   r   r   r   r,   r,   Y   s    r   r,   c                   "    e Zd ZdZd Zd Zd Zy)ThreadWorkerTestsz$
    Tests for L{ThreadWorker}.
    c                 r     g  _         t                _         fd}t        | j                         _        y)z4
        Create a worker with fake threads.
        c                 v    t        |       }|j                          j                  j                  |       |S )N)r   )r   r   fakeThreadsr%   )r   	newThreadr   s     r   startThreadz,ThreadWorkerTests.setUp.<locals>.startThread   s1    "&1IOO##I.r   N)r7   r!   	fakeQueuer	   worker)r   r9   s   ` r   setUpzThreadWorkerTests.setUp}   s/     "	 #;?r   c                    | j                  t        | j                        d       | j                  | j                  d   j                  d       fdd_        | j
                  j                         | j                  j                  d       | j                  t        | j                  d   j                         | j                  j                  d       y)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                      d _         y NT)done)doIts   r   rB   z@ThreadWorkerTests.test_startsThreadAndPerformsWork.<locals>.doIt   s
    DIr   FN)
assertEquallenr7   r   rA   r;   doassertRaisesr   r   )r   rB   s    @r    test_startsThreadAndPerformsWorkz2ThreadWorkerTests.test_startsThreadAndPerformsWork   s     	T--.2))!,44d;	 	tE*.$*:*:1*=*D*DED)r   c                     | j                   j                          | j                  t        | j                   j                         | j                  t        | j                   j                  t
               y)z
        L{ThreadWorker.quit} causes future calls to L{ThreadWorker.do} and
        L{ThreadWorker.quit} to raise L{AlreadyQuit}.
        N)r;   quitrF   r   rE   listr   s    r   test_quitPreventsFutureCallsz.ThreadWorkerTests.test_quitPreventsFutureCalls   sH    
 	+t{{'7'78+t{{~~t<r   N)r   r   r   r   r<   rG   rK   r   r   r   r4   r4   x   s    @*$=r   r4   c                   :    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
y	)
LockWorkerTestsz"
    Tests for L{LockWorker}.
    c                 x    t               }|j                          | j                  t        |j                         y)ze
        The L{FakeLock} test fixture will alert us if there's a potential
        deadlock.
        N)r,   r0   rF   r   r   locks     r   test_fakeDeadlockz!LockWorkerTests.test_fakeDeadlock   s(    
 z-6r   c                     t               }| j                  t        |j                         |j	                          | j                  d|j                                | j                  t        |j                         y)zk
        The L{FakeLock} test fixture will alert us if there's a potential
        double-release.
        N)r,   rF   r   r2   r0   rC   rO   s     r   test_fakeDoubleReleasez&LockWorkerTests.test_fakeDoubleRelease   sR    
 z+t||4t||~.+t||4r   c                 ,   t               }t               t        |      }fdd_        |j	                         | j                  j                  d       | j                  j                  d       | j                  j                  d       y)zp
        L{LockWorker.do} immediately performs the work it's given, while the
        lock is acquired.
        c                  6    d_          j                  _        y r@   )rA   r.   )rP   works   r   rV   z@LockWorkerTests.test_doExecutesImmediatelyWithLock.<locals>.work   s    DI MMDMr   FTN)r   r,   r   rA   rE   rC   r.   )r   storager;   rP   rV   s      @@r   "test_doExecutesImmediatelyWithLockz2LockWorkerTests.test_doExecutesImmediatelyWithLock   st    
 'zD'*	* 			$D)-.r   c                     t               t        t                     g g fdd_        j	                         | j                  ddg       | j                  ddg       y)z
        If L{LockWorker.do} is called recursively, it postpones the inner call
        until the outer one is complete.
        c                     xj                   dz  c_         j                  j                           j                  j                         t              dk  rj	                         xj                   dz  c_         y )Nr>   r   )levelr%   r.   rD   rE   )r.   levelsrP   rV   r;   s   r   rV   z6LockWorkerTests.test_doUnwindsReentrancy.<locals>.work   sS    JJ!OJMM$**%OODMM*6{Q		$JJ!OJr   r   r>   TN)r,   r   r   r[   rE   rC   )r   r.   r\   rP   rV   r;   s    @@@@@r   test_doUnwindsReentrancyz(LockWorkerTests.test_doUnwindsReentrancy   sj    
 zD%'*	 	 
		$!Q(D$<0r   c                    t               }t        j                  |      }t        |t	                     }d}| j                   |       d       |j                          t        j                          | j                   |       d       | j                  t        |j                         | j                  t        |j                  t               y)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   assertIsNotrI   gccollectassertIsrF   r   rE   rJ   )r   rP   r`   r;   s       r   	test_quitzLockWorkerTests.test_quit   s    
 zkk$D%'*%


ceT"+v{{3+vyy$7r   c                     t               t        j                        }t        t	                      fdd_        fdd_        j                          j                  j
                  d        j                  j
                  d        j                  j                  d       dt        j                           j                   |       d       y)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                      j                         j                          j                  t        j                   t               d _        y r@   )rE   rI   rF   r   rJ   complete)phase1phase2r   r;   s   r   ri   z5LockWorkerTests.test_quitWhileWorking.<locals>.phase1  s5    IIfKKMk699d;"FOr   Fc                  6    d_          j                  _        y r@   )rh   r.   )rP   rj   s   r   rj   z5LockWorkerTests.test_quitWhileWorking.<locals>.phase2  s    "FO"mmFOr   TN)r,   r_   r`   r   r   rh   rE   rC   r.   rb   rc   rd   )r   r`   rP   ri   rj   r;   s   ` @@@@r   test_quitWhileWorkingz%LockWorkerTests.test_quitWhileWorking   s     zkk$D%'*	#  	,  		&$/$/.


ceT"r   c                      G d dt               } |t               t                     }| j                  t        |j
                  t               y)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                   @    e Zd Zed        Zej
                  d        Zy)ALockWorkerTests.test_quitWhileGettingLock.<locals>.RacyLockWorkerc                 @    | j                          | j                  d   S N_lock)rI   __dict__r   s    r   rr   zGLockWorkerTests.test_quitWhileGettingLock.<locals>.RacyLockWorker._lock"  s    		}}W--r   c                 "    || j                   d<   y rq   )rs   )r   values     r   rr   zGLockWorkerTests.test_quitWhileGettingLock.<locals>.RacyLockWorker._lock'  s    ).g&r   N)r   r   r   propertyrr   setterr   r   r   RacyLockWorkerro   !  s,    . . \\/ /r   rx   N)r   r,   r   rF   r   rE   rJ   )r   rx   r;   s      r   test_quitWhileGettingLockz)LockWorkerTests.test_quitWhileGettingLock  s6    	/Z 	/  
EG4+vyy$7r   N)r   r   r   r   rQ   rS   rX   r]   re   rl   ry   r   r   r   rM   rM      s*    7	5/&1.8 #>8r   rM   )r   rb   r_   	threadingr   r   twisted.trial.unittestr    r   r   r	   	Exceptionr   r   r   r!   r,   r4   rM   r   r   r   <module>r~      sr   
 
  ( 6 4 4Y I  2! !D >-=+ -=`D8) D8r   