U
    
W[’<  ã                   @   s¤   d Z ddlmZmZ ddl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 dZe ¡ r|edƒdkr|ed	ƒdkr|d
ZG dd„ dejƒZG dd„ dejƒZdS )z'
Tests for L{twisted.python.lockfile}.
é    )Úabsolute_importÚdivisionN)Úunittest)Úlockfile)ÚrequireModule)Úplatformzwin32api.OpenProcessZ
pywintypeszZOn windows, lockfile.kill is not implemented in the absence of win32api and/or pywintypes.c                   @   sp   e Zd ZdZdd„ Zdd„ Ze ¡ s*de_dd„ Z	d	d
„ Z
e ¡ sHde
_dd„ Zee_dd„ Zee_dd„ ZdS )Ú	UtilTestszM
    Tests for the helper functions used to implement L{FilesystemLock}.
    c                 C   s:   |   ¡ }t d|¡ |  ttjd|¡}|  |jtj¡ dS )z 
        L{lockfile.symlink} raises L{OSError} with C{errno} set to L{EEXIST}
        when an attempt is made to create a symlink which already exists.
        ÚfooN)Úmktempr   ÚsymlinkÚassertRaisesÚOSErrorÚassertEqualÚerrnoZEEXIST©ÚselfÚnameÚexc© r   ú</usr/lib/python3/dist-packages/twisted/test/test_lockfile.pyÚtest_symlinkEEXIST   s    zUtilTests.test_symlinkEEXISTc                 C   sD   |   ¡ }dd„ }|  td|¡ |  ttj|d¡}|  |jtj¡ dS )a<  
        L{lockfile.symlink} raises L{OSError} with C{errno} set to L{EIO} when
        the underlying L{rename} call fails with L{EIO}.

        Renaming a file on Windows may fail if the target of the rename is in
        the process of being deleted (directory deletion appears not to be
        atomic).
        c                 S   s   t tjd ƒ‚d S ©N)ÚIOErrorr   ÚEIO©ÚsrcZdstr   r   r   Ú
fakeRename4   s    z4UtilTests.test_symlinkEIOWindows.<locals>.fakeRenameÚrenamer	   N)	r
   Úpatchr   r   r   r   r   r   r   )r   r   r   r   r   r   r   Útest_symlinkEIOWindows*   s
    	z UtilTests.test_symlinkEIOWindowsúBspecial rename EIO handling only necessary and correct on Windows.c                 C   s,   |   ¡ }|  ttj|¡}|  |jtj¡ dS )zŸ
        L{lockfile.readlink} raises L{OSError} with C{errno} set to L{ENOENT}
        when an attempt is made to read a symlink which does not exist.
        N)r
   r   r   r   Úreadlinkr   r   ZENOENTr   r   r   r   Útest_readlinkENOENT?   s    zUtilTests.test_readlinkENOENTc                 C   sB   |   ¡ }dd„ }|  td|¡ |  ttj|¡}|  |jtj¡ dS )a\  
        L{lockfile.readlink} raises L{OSError} with C{errno} set to L{EACCES}
        on Windows when the underlying file open attempt fails with C{EACCES}.

        Opening a file on Windows may fail if the path is inside a directory
        which is in the process of being deleted (directory deletion appears
        not to be atomic).
        c                 S   s   t tjd ƒ‚d S r   ©r   r   ÚEACCES)ÚpathÚmoder   r   r   ÚfakeOpenS   s    z6UtilTests.test_readlinkEACCESWindows.<locals>.fakeOpenZ_openN)	r
   r   r   r   r   r!   r   r   r$   )r   r   r'   r   r   r   r   Útest_readlinkEACCESWindowsI   s
    	z$UtilTests.test_readlinkEACCESWindowsúGspecial readlink EACCES handling only necessary and correct on Windows.c                 C   s   t  t ¡ d¡ dS )z}
        L{lockfile.kill} returns without error if passed the PID of a
        process which exists and signal C{0}.
        r   N)r   ÚkillÚosÚgetpid©r   r   r   r   Ú	test_kill^   s    zUtilTests.test_killc                 C   s&   |   ttjdd¡}|  |jtj¡ dS )z
        L{lockfile.kill} raises L{OSError} with errno of L{ESRCH} if
        passed a PID which does not correspond to any process.
        iÿÿÿr   N)r   r   r   r*   r   r   ÚESRCH)r   r   r   r   r   Útest_killESRCHg   s    zUtilTests.test_killESRCHc                 C   s6   |   tdd¡ t |  ¡ ¡}| ¡  |  | ¡ ¡ dS )zµ
        Verify that when L{lockfile.kill} does end up as None (e.g. on Windows
        without pywin32), it doesn't end up being called and raising a
        L{TypeError}.
        r*   N)r   r   ÚFilesystemLockr
   ÚlockÚassertFalse)r   Zflr   r   r   Útest_noKillCallr   s    zUtilTests.test_noKillCallN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r   r   Ú	isWindowsÚskipr"   r(   r.   ÚskipKillr0   r4   r   r   r   r   r      s    ÿ
ÿr   c                   @   sÔ   e Zd Zdd„ Zdd„ Zdd„ Ze ¡ r.de_dd	„ Z	d
d„ Z
dd„ Zdd„ Zdd„ Zdd„ Ze ¡ slde_dd„ Ze ¡ s‚de_dd„ Zdd„ Zdd„ Ze ¡ r¨de_dd„ Zd d!„ Zd"d#„ Zd$d%„ Zd&d'„ Zd(S ))ÚLockingTestsc                    sL   ‡ fdd„}|   td|¡ |  ¡ }t |¡}|  t|j¡}|  |jˆ ¡ d S )Nc                    s   t ˆ d ƒ‚d S r   )r   )ÚsourceÚdest©r   r   r   ÚfakeSymlink   s    z3LockingTests._symlinkErrorTest.<locals>.fakeSymlinkr   )	r   r   r
   r1   r   r   r2   r   r   )r   r   r@   Úlockfr2   r   r   r?   r   Ú_symlinkErrorTest€   s    
zLockingTests._symlinkErrorTestc                 C   s   |   tj¡ dS )z†
        An exception raised by C{symlink} other than C{EEXIST} is passed up to
        the caller of L{FilesystemLock.lock}.
        N)rB   r   ÚENOSYSr-   r   r   r   Útest_symlinkError‹   s    zLockingTests.test_symlinkErrorc                 C   s   |   tj¡ |   tj¡ dS )a   
        An L{OSError} raised by C{symlink} on a POSIX platform with an errno of
        C{EACCES} or C{EIO} is passed to the caller of L{FilesystemLock.lock}.

        On POSIX, unlike on Windows, these are unexpected errors which cannot
        be handled by L{FilesystemLock}.
        N)rB   r   r$   r   r-   r   r   r   Útest_symlinkErrorPOSIX“   s    z#LockingTests.test_symlinkErrorPOSIXz9POSIX-specific error propagation not expected on Windows.c                 C   s<   |   ¡ }t |¡}|  | ¡ ¡ |  |j¡ |  |j¡ dS )z‹
        If the lock has never been held, it can be acquired and the C{clean}
        and C{locked} attributes are set to C{True}.
        N)r
   r   r1   Ú
assertTruer2   ÚcleanÚlocked©r   rA   r2   r   r   r   Útest_cleanlyAcquire¢   s
    
z LockingTests.test_cleanlyAcquirec                 C   sh   |   ¡ }t |¡}|  | ¡ ¡ | ¡  |  |j¡ t |¡}|  | ¡ ¡ |  |j¡ |  |j¡ dS )zŒ
        If a lock is released cleanly, it can be re-acquired and the C{clean}
        and C{locked} attributes are set to C{True}.
        N)	r
   r   r1   rF   r2   Úunlockr3   rH   rG   rI   r   r   r   Útest_cleanlyRelease®   s    

z LockingTests.test_cleanlyReleasec                 C   sH   |   ¡ }t |¡}|  | ¡ ¡ t |¡}|  | ¡ ¡ |  |j¡ dS )zK
        If a lock is currently locked, it cannot be locked again.
        N)r
   r   r1   rF   r2   r3   rH   )r   rA   Z	firstLockZ
secondLockr   r   r   Útest_cannotLockLocked¿   s    

z"LockingTests.test_cannotLockLockedc                    s„   d‰ ‡ fdd„}|   ¡ }|  td|¡ t tˆ ƒ|¡ t |¡}|  | ¡ ¡ |  |j	¡ |  |j
¡ |  t |¡tt ¡ ƒ¡ dS )zÇ
        If a lock was held by a process which no longer exists, it can be
        acquired, the C{clean} attribute is set to C{False}, and the
        C{locked} attribute is set to C{True}.
        i90  c                    s,   |dkrt tjd ƒ‚| ˆ kr(t tjd ƒ‚d S )Nr   ©r   r   ÚEPERMr/   ©ÚpidÚsignal©Úownerr   r   ÚfakeKillÔ   s    z4LockingTests.test_uncleanlyAcquire.<locals>.fakeKillr*   N)r
   r   r   r   Ústrr1   rF   r2   r3   rG   rH   r   r!   r+   r,   )r   rU   rA   r2   r   rS   r   Útest_uncleanlyAcquireÌ   s    
z"LockingTests.test_uncleanlyAcquirec                    s~   ‡ ‡fdd„}|   td|¡‰dd„ }|   td|¡ |  ¡ ‰ t ˆ ¡}t tdƒˆ ¡ |  | ¡ ¡ |  |j¡ |  |j	¡ dS )	zð
        If the lock is initially held but then released before it can be
        examined to determine if the process which held it still exists, it is
        acquired and the C{clean} and C{locked} attributes are set to C{True}.
        c                    s   t  ˆ ¡ ˆ ¡  t  | ¡S r   )r   ÚrmlinkÚrestorer!   ©r   ©rA   ZreadlinkPatchr   r   ÚfakeReadlinkì   s    
z?LockingTests.test_lockReleasedBeforeCheck.<locals>.fakeReadlinkr!   c                 S   s,   |dkrt tjd ƒ‚| dkr(t tjd ƒ‚d S ©Nr   éu¨  rN   rP   r   r   r   rU   ô   s    z;LockingTests.test_lockReleasedBeforeCheck.<locals>.fakeKillr*   r^   N©
r   r   r
   r1   r   rV   rF   r2   rG   rH   )r   r\   rU   r2   r   r[   r   Útest_lockReleasedBeforeCheckæ   s    
z)LockingTests.test_lockReleasedBeforeCheckc                 C   sF   dd„ }|   td|¡ |  ¡ }t |¡}|  | ¡ ¡ |  |j¡ dS )a“  
        If the lock is released while an attempt is made to acquire
        it, the lock attempt fails and C{FilesystemLock.lock} returns
        C{False}.  This can happen on Windows when L{lockfile.symlink}
        fails with L{IOError} of C{EIO} because another process is in
        the middle of a call to L{os.rmdir} (implemented in terms of
        RemoveDirectory) which is not atomic.
        c                 S   s   t tjd ƒ‚d S r   )r   r   r   r   r   r   r   r@     s    zGLockingTests.test_lockReleasedDuringAcquireSymlink.<locals>.fakeSymlinkr   N)r   r   r
   r1   r3   r2   rH   )r   r@   rA   r2   r   r   r   Ú%test_lockReleasedDuringAcquireSymlink  s    	
z2LockingTests.test_lockReleasedDuringAcquireSymlinkr    c                 C   sV   dd„ }|   td|¡ |  ¡ }t |¡}t tdƒ|¡ |  | ¡ ¡ |  |j¡ dS )z»
        If the lock is initially held but is released while an attempt
        is made to acquire it, the lock attempt fails and
        L{FilesystemLock.lock} returns C{False}.
        c                 S   s   t tjd ƒ‚d S r   r#   rZ   r   r   r   r\   #  s    zILockingTests.test_lockReleasedDuringAcquireReadlink.<locals>.fakeReadlinkr!   r^   N)	r   r   r
   r1   r   rV   r3   r2   rH   )r   r\   rA   r2   r   r   r   Ú&test_lockReleasedDuringAcquireReadlink  s    
z3LockingTests.test_lockReleasedDuringAcquireReadlinkr)   c                    sj   ‡ ‡fdd„}|   td|¡ |  ¡ }t tdƒ|¡ t |¡}|  ˆ|j¡}|  |j	ˆ ¡ |  
|j¡ d S )Nc                    s   ˆˆ d ƒ‚d S r   r   rZ   ©r   ÚexceptionTyper   r   r\   6  s    z5LockingTests._readlinkErrorTest.<locals>.fakeReadlinkr!   r^   )r   r   r
   r   rV   r1   r   r2   r   r   r3   rH   )r   rd   r   r\   rA   r2   r   r   rc   r   Ú_readlinkErrorTest5  s    
zLockingTests._readlinkErrorTestc                 C   s    |   ttj¡ |   ttj¡ dS )z‡
        An exception raised by C{readlink} other than C{ENOENT} is passed up to
        the caller of L{FilesystemLock.lock}.
        N)re   r   r   rC   r   r-   r   r   r   Útest_readlinkErrorE  s    zLockingTests.test_readlinkErrorc                 C   s    |   ttj¡ |   ttj¡ dS )zú
        Any L{IOError} raised by C{readlink} on a POSIX platform passed to the
        caller of L{FilesystemLock.lock}.

        On POSIX, unlike on Windows, these are unexpected errors which cannot
        be handled by L{FilesystemLock}.
        N)re   r   r   rC   r$   r-   r   r   r   Útest_readlinkErrorPOSIXN  s    z$LockingTests.test_readlinkErrorPOSIXc                    s~   ‡ ‡fdd„}|   td|¡‰dd„ }|   td|¡ |  ¡ ‰ t ˆ ¡}t tdƒˆ ¡ |  | ¡ ¡ |  |j¡ |  |j	¡ dS )	z×
        If a second process cleans up the lock after a first one checks the
        lock and finds that no process is holding it, the first process does
        not fail when it tries to clean up the lock.
        c                    s   ˆ  ¡  t ˆ ¡ t | ¡S r   )rY   r   rX   rZ   ©rA   ZrmlinkPatchr   r   Ú
fakeRmlinkc  s    
z?LockingTests.test_lockCleanedUpConcurrently.<locals>.fakeRmlinkrX   c                 S   s,   |dkrt tjd ƒ‚| dkr(t tjd ƒ‚d S r]   rN   rP   r   r   r   rU   k  s    z=LockingTests.test_lockCleanedUpConcurrently.<locals>.fakeKillr*   r^   Nr_   )r   ri   rU   r2   r   rh   r   Útest_lockCleanedUpConcurrently]  s    
z+LockingTests.test_lockCleanedUpConcurrentlyc                 C   s|   dd„ }|   td|¡ dd„ }|   td|¡ |  ¡ }t tdƒ|¡ t |¡}|  t|j¡}|  	|j
t
j¡ |  |j¡ dS )	z…
        An exception raised by L{rmlink} other than C{ENOENT} is passed up
        to the caller of L{FilesystemLock.lock}.
        c                 S   s   t tjd ƒ‚d S r   )r   r   rC   rZ   r   r   r   ri     s    z1LockingTests.test_rmlinkError.<locals>.fakeRmlinkrX   c                 S   s,   |dkrt tjd ƒ‚| dkr(t tjd ƒ‚d S r]   rN   rP   r   r   r   rU   ƒ  s    z/LockingTests.test_rmlinkError.<locals>.fakeKillr*   r^   N)r   r   r
   r   rV   r1   r   r   r2   r   r   rC   r3   rH   )r   ri   rU   rA   r2   r   r   r   r   Útest_rmlinkErrorz  s    
zLockingTests.test_rmlinkErrorc                 C   sf   dd„ }|   td|¡ |  ¡ }t tdƒ|¡ t |¡}|  t|j¡}|  	|j
t
j¡ |  |j¡ dS )z¶
        If L{kill} raises an exception other than L{OSError} with errno set to
        C{ESRCH}, the exception is passed up to the caller of
        L{FilesystemLock.lock}.
        c                 S   s   t tjd ƒ‚d S r   )r   r   rO   rP   r   r   r   rU   ›  s    z-LockingTests.test_killError.<locals>.fakeKillr*   r^   N)r   r   r
   r   rV   r1   r   r   r2   r   r   rO   r3   rH   )r   rU   rA   r2   r   r   r   r   Útest_killError•  s    
zLockingTests.test_killErrorc                 C   s<   |   ¡ }t tt ¡ d ƒ|¡ t |¡}|  t|j	¡ dS )z‚
        L{FilesystemLock.unlock} raises L{ValueError} if called for a lock
        which is held by a different process.
        é   N)
r
   r   r   rV   r+   r,   r1   r   Ú
ValueErrorrK   rI   r   r   r   Útest_unlockOtherª  s    
zLockingTests.test_unlockOtherc                 C   s\   |   ¡ }|  t |¡¡ t |¡}|  | ¡ ¡ |  t |¡¡ | ¡  |  t |¡¡ dS )zp
        L{isLocked} returns C{True} if the named lock is currently locked,
        C{False} otherwise.
        N)r
   r3   r   ZisLockedr1   rF   r2   rK   rI   r   r   r   Útest_isLockedµ  s    
zLockingTests.test_isLockedN)r5   r6   r7   rB   rD   rE   r   r9   r:   rJ   rL   rM   rW   r`   ra   rb   re   rf   rg   rj   rk   rl   ro   rp   r   r   r   r   r<      s<   
ÿÿÿ	
ÿr<   )r8   Z
__future__r   r   r   r+   Ztwisted.trialr   Ztwisted.pythonr   Ztwisted.python.reflectr   Ztwisted.python.runtimer   r;   r9   ZTestCaser   r<   r   r   r   r   Ú<module>   s   
ÿd