a
    )(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                   @   s   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   Flib/python3.9/site-packages/twisted/_threads/test/test_threadworker.pyr	      s   r	   c                   @   s   e Zd ZdZdS )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   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   s
   d| _ dS )z)
        Set the "started" flag.
        TN)r   r   r   r   r   start0   s    zFakeThread.startN)r   r   r   r   r   r   r   r   r   r   r      s   
r   c                   @   s(   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   @   s    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                   @   s(   e Zd ZdZdd Zdd Zdd ZdS )	FakeLockzi
    A stand-in for L{threading.Lock}.

    @ivar acquired: Whether this lock is presently acquired.
    c                 C   s
   d| _ dS )z9
        Create a lock in the un-acquired state.
        FN)acquiredr   r   r   r   r   `   s    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                   @   s(   e Zd ZdZdd Zdd Zdd ZdS )	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   Z	newThreadr   r   r   startThread   s    
z,ThreadWorkerTests.setUp.<locals>.startThreadN)r%   r   Z	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   r-      s    z@ThreadWorkerTests.test_startsThreadAndPerformsWork.<locals>.doItFN)
assertEquallenr%   r   r+   r'   doassertRaisesr	   r   r   r   r,   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'   quitr1   r   r0   listr   r   r   r   test_quitPreventsFutureCalls   s    
z.ThreadWorkerTests.test_quitPreventsFutureCallsN)r   r   r   r   r(   r2   r5   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"   r1   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    r1   r   r#   r"   r.   r7   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                      s   d_  j_d S r*   )r+   r!   r   r8   workr   r   r<      s    z@LockWorkerTests.test_doExecutesImmediatelyWithLock.<locals>.workFTN)r   r    r   r+   r0   r.   r!   )r   Zstorager'   r   r;   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 )Nr)   r   )levelr   r!   r/   r0   r   r!   Zlevelsr8   r<   r'   r   r   r<      s    
z6LockWorkerTests.test_doUnwindsReentrancy.<locals>.workr   r)   TN)r    r   r   r>   r0   r.   r   r   r?   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   ZassertIsNotr3   gccollectassertIsr1   r   r0   r4   )r   r8   rB   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 r*   )r0   r3   r1   r   r4   completer   )phase1phase2r   r'   r   r   rH     s    
z5LockWorkerTests.test_quitWhileWorking.<locals>.phase1Fc                      s   d_  j_d S r*   )rG   r!   r   )r8   rI   r   r   rI     s    z5LockWorkerTests.test_quitWhileWorking.<locals>.phase2TN)r    rA   rB   r   r   rG   r0   r.   r!   rC   rD   rE   )r   rB   r   )r8   rH   rI   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)r3   __dict__r   r   r   r   rL   "  s    zGLockWorkerTests.test_quitWhileGettingLock.<locals>.RacyLockWorker._lockc                 S   s   || j d< d S rK   )rM   )r   valuer   r   r   rL   '  s    N)r   r   r   propertyrL   setterr   r   r   r   RacyLockWorker!  s   
rQ   N)r   r    r   r1   r   r0   r4   )r   rQ   r'   r   r   r   test_quitWhileGettingLock  s    
z)LockWorkerTests.test_quitWhileGettingLockN)r   r   r   r   r9   r:   r=   r@   rF   rJ   rR   r   r   r   r   r6      s   	r6   )r   rC   rA   Z	threadingr   r   Ztwisted.trial.unittestr    r   r   r   	Exceptionr	   r   r   r   r    r$   r6   r   r   r   r   <module>   s   "0