Ϫf&>dZddlmZddlZddlZddlmZmZddlm Z ddl m Z ddl m Z ddlmZdd lmZd Zd Zej(re d  e d dZdZGddeZGddeZy)z' Tests for L{twisted.python.lockfile}. ) annotationsN)skipIf skipUnless)NoReturn)lockfile) requireModule)platform)TestCaseFzwin32api.OpenProcess pywintypesTzZOn windows, lockfile.kill is not implemented in the absence of win32api and/or pywintypes.ceZdZdZd dZeejdd dZd dZ eejdd dZ e e e d dZe e e d d Zd d Zy ) UtilTestszM Tests for the helper functions used to implement L{FilesystemLock}. c|j}tjd||jttjd|}|j |j t jy)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)mktemprsymlink assertRaisesOSError assertEqualerrnoEEXISTselfnameexcs .fakeRenameAs%))T* *rrenamerNr&strr'r+returnr) rpatchrrIOErrorrrrr$)rrr(rs rtest_symlinkEIOWindowsz UtilTests.test_symlinkEIOWindows2sZ{{} + 8Xz2)9)94G EII.rc|j}|jttj|}|j |j t jy)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)rrrrreadlinkrrENOENTrs rtest_readlinkENOENTzUtilTests.test_readlinkENOENTHsA {{}):):DA ELL1rGspecial readlink EACCES handling only necessary and correct on Windows.c|j}dd}|jtd||jttj |}|j |jtjy)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). c6ttjdr"rrEACCES)pathmodes rfakeOpenz6UtilTests.test_readlinkEACCESWindows..fakeOpen`%,,- -r_openN)r9r+r:r+r,r) rr-rrr.r1rrr8)rrr;rs rtest_readlinkEACCESWindowsz$UtilTests.test_readlinkEACCESWindowsQsX{{} . 8Wh/):):DA ELL1rcTtjtjdy)z} L{lockfile.kill} returns without error if passed the PID of a process which exists and signal C{0}. rN)rkillosgetpidrs r test_killzUtilTests.test_killgs  biik1%rc|jttjdd}|j |j t j y)z L{lockfile.kill} raises L{OSError} with errno of L{ESRCH} if passed a PID which does not correspond to any process. irN)rrrr@rrESRCH)rrs rtest_killESRCHzUtilTests.test_killESRCHos6 1E EKK0rc|jtddtj|j}|j |j |j y)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-rFilesystemLockrlock assertFalse)rfls rtest_noKillCallzUtilTests.test_noKillCallysG 8VT*  $ $T[[] 3   #rNr,None)__name__ __module__ __qualname____doc__rrr isWindowsr/r3r>rskipKillskipKillReasonrDrGrMrrrr#s2O/ /$2T2 2$ Hn%&&& Hn%1&1 $rrceZdZddZddZeejdddZddZ ddZ ddZ ddZ dd Z eejd dd Zeejd dd Z ddZddZeejdddZddZddZddZddZddZy) LockingTestscdfd }|jtd||j}tj|}|j t |j }|j|jy)Nctdr")r)sourcedestrs r fakeSymlinkz3LockingTests._symlinkErrorTest..fakeSymlinks%& &rr)r\r+r]r+r,r) r-rrrIrrrJrr)rrr^lockfrJrs ` r_symlinkErrorTestzLockingTests._symlinkErrorTests_ ' 8Y 4 &&u-3 E*rcB|jtjy)z An exception raised by C{symlink} other than C{EEXIST} is passed up to the caller of L{FilesystemLock.lock}. N)r`rENOSYSrCs rtest_symlinkErrorzLockingTests.test_symlinkErrors u||,rz9POSIX-specific error propagation not expected on Windows.c|jtj|jtjy)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)r`rr8r$rCs rtest_symlinkErrorPOSIXz#LockingTests.test_symlinkErrorPOSIXs( u||, uyy)rc|j}tj|}|j|j |j|j |j|j y)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)rrrI assertTruerJcleanlockedrr_rJs rtest_cleanlyAcquirez LockingTests.test_cleanlyAcquiresQ  &&u-  $  #  $rc|j}tj|}|j|j |j |j |jtj|}|j|j |j|j|j|jy)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) rrrIrgrJunlockrKrirhrjs rtest_cleanlyReleasez LockingTests.test_cleanlyReleases  &&u-  $  %&&u-  $  #  $rc*|j}tj|}|j|j tj|}|j |j |j |j y)zK If a lock is currently locked, it cannot be locked again. N)rrrIrgrJrKri)rr_ firstLock secondLocks rtest_cannotLockLockedz"LockingTests.test_cannotLockLockedsk ++E2   (),,U3  *+ **+rcddfd }|j}|jtd|tjt |tj |}|j |j|j|j|j |j|jtj|t tjy)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}. i90c|dk7rttjd|k(rttjdy)NrrrEPERMrF)pidsignalowners rfakeKillz4LockingTests.test_uncleanlyAcquire..fakeKills8{ekk400e|ekk400rr@Nrwintrxr|r,rO)rr-rrr+rIrgrJrKrhrirr1rArB)rrzr_rJrys @rtest_uncleanlyAcquirez"LockingTests.test_uncleanlyAcquires  1   8VX.UU+&&u-  $ $  $ **513ryy{3CDrcdfd }|jtd|dd}|jtd||jtj}tjt d|j |j|j |j|j |jy) 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}. cxtjjtj|Sr")rrmlinkrestorer1)rr_ readlinkPatchs r fakeReadlinkz?LockingTests.test_lockReleasedBeforeCheck..fakeReadlinks, OOE "  ! ! #$$T* *rr1c|dk7rttjd|dk(rttjdyNrururwrxs rrzz;LockingTests.test_lockReleasedBeforeCheck..fakeKill7{ekk400e|ekk400rr@rN)rr+r,r+r{ r-rrrIrr+rgrJrhri)rrrzrJr_rs @@rtest_lockReleasedBeforeCheckz)LockingTests.test_lockReleasedBeforeChecks + 8ZF  1 8VX. &&u-UU+  $  #  $rrcdd}|jtd||j}tj|}|j |j |j |j y)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. c6ttjdr"r#r%s rr^zGLockingTests.test_lockReleasedDuringAcquireSymlink..fakeSymlinks%))T* *rrNr*)r-rrrIrKrJri)rr^r_rJs r%test_lockReleasedDuringAcquireSymlinkz2LockingTests.test_lockReleasedDuringAcquireSymlinksZ + 8Y 4 &&u- % %rr4c6dd}|jtd||j}tj|}tjt d||j |j|j |jy)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}. c6ttjdr"r7rs rrzILockingTests.test_lockReleasedDuringAcquireReadlink..fakeReadlink+s%,,- -rr1rNrr+r,r) r-rrrIrr+rKrJri)rrr_rJs r&test_lockReleasedDuringAcquireReadlinkz3LockingTests.test_lockReleasedDuringAcquireReadlink sn . 8Z6 &&u-UU+ % %rcrdfd }|jtd||j}tjt d|tj |}|j |j}|j|j|j|jy)Ncdr"rW)rr exceptionTypes rrz5LockingTests._readlinkErrorTest..fakeReadlink<st, ,rr1rr) r-rrrr+rIrrJrrrKri)rrrrr_rJrs `` r_readlinkErrorTestzLockingTests._readlinkErrorTest9s - 8Z6  UU+&&u- tyy9 E* %rc|jttj|jttjy)z An exception raised by C{readlink} other than C{ENOENT} is passed up to the caller of L{FilesystemLock.lock}. N)rrrrbr.rCs rtest_readlinkErrorzLockingTests.test_readlinkErrorKs, 6 6rc|jttj|jttjy)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)rr.rrbr8rCs rtest_readlinkErrorPOSIXz$LockingTests.test_readlinkErrorPOSIXSs, 6 6rcdfd }|jtd|dd}|jtd||jtj}tjt d|j |j|j |j|j |jy) 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. cxjtjtj|Sr")rrr)rr_ rmlinkPatchs r fakeRmlinkz?LockingTests.test_lockCleanedUpConcurrently..fakeRmlinkis*    ! OOE "??4( (rrc|dk7rttjd|dk(rttjdyrrurs rrzz=LockingTests.test_lockCleanedUpConcurrently..fakeKillrrrr@rN)rr+r,rOr{r)rrrzrJr_rs @@rtest_lockCleanedUpConcurrentlyz+LockingTests.test_lockCleanedUpConcurrentlybs )jj8Z@  1 8VX. &&u-UU+  $  #  $rcdd}|jtd|dd}|jtd||j}tjt d|tj |}|j t|j}|j|jtj|j|jy) z An exception raised by L{rmlink} other than C{ENOENT} is passed up to the caller of L{FilesystemLock.lock}. c6ttjdr")rrrbrs rrz1LockingTests.test_rmlinkError..fakeRmlinkr<rrc|dk7rttjd|dk(rttjdyrrurs rrzz/LockingTests.test_rmlinkError..fakeKillrrr@rNrr{)r-rrrr+rIrrrJrrrbrKri)rrrzr_rJrs rtest_rmlinkErrorzLockingTests.test_rmlinkErrors  . 8Xz2 1 8VX.  UU+&&u-3 ELL1 %rcdd}|jtd||j}tjt d|tj |}|j t|j}|j|jtj|j|jy)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}. c6ttjdr")rrrvrs rrzz-LockingTests.test_killError..fakeKills%++t, ,rr@rN)rwr|rxr|r,r)r-rrrr+rIrrrJrrrvrKri)rrzr_rJrs rtest_killErrorzLockingTests.test_killErrors - 8VX.  UU+&&u-3 EKK0 %rc|j}tjtt j dz|tj |}|jt|jy)z L{FilesystemLock.unlock} raises L{ValueError} if called for a lock which is held by a different process. N) rrrr+rArBrIr ValueErrorrmrjs rtest_unlockOtherzLockingTests.test_unlockOthersR  RYY[1_-u5&&u- *dkk2rc|j}|jtj|tj|}|j |j |j tj||j|jtj|y)zp L{isLocked} returns C{True} if the named lock is currently locked, C{False} otherwise. N)rrKrisLockedrIrgrJrmrjs r test_isLockedzLockingTests.test_isLockeds   **512&&u-  $ ))%01  **512rN)rr|r,rOrN)rztype[OSError] | type[IOError]rr|r,rO)rPrQrRr`rcrr rTrerkrnrrr}rrrrrrrrrrrrrWrrrYrYs  +- C *  * %% ,E2%>O& &,T& &*&:&CF& &$7 C 7  7%>&:&,3 3rrY)rS __future__rrrAunittestrrtypingrtwisted.pythonrtwisted.python.reflectrtwisted.python.runtimer twisted.trial.unittestr rUrVrTrrYrWrrrs # '#0++ 8,-5 , ' / <  _$_$DD38D3r