o
    bH                     @   sx   d Z ddlZddlmZmZ ddlmZmZ ddlm	Z	 ddl
mZ e	ddur/ddlmZ ndZG d	d
 d
ejZdS )z?
Tests for the inotify wrapper in L{twisted.internet.inotify}.
    N)deferreactor)filepathruntime)requireModule)unittestztwisted.python._inotify)inotifyc                   @   s   e Zd ZdZej sdZdd Zdd Z	d<dd	Z
d
d Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zd d! Zd"d# Zd$d% Zd&d' Zd(d) Zd*d+ Zd,d- Zd.d/ Zd0d1 Zd2d3 Zd4d5 Z d6d7 Z!d8d9 Z"d:d; Z#dS )=INotifyTestsz]
    Define all the tests for the basic functionality exposed by
    L{inotify.INotify}.
    z&This platform doesn't support INotify.c                 C   s@   t |  | _| j  t | _| j  | | jj	 d S N)
r   FilePathmktempdirnamecreateDirectoryr   INotifystartReading
addCleanuploseConnectionself r   D/usr/lib/python3/dist-packages/twisted/internet/test/test_inotify.pysetUp   s
   


zINotifyTests.setUpc                 C   s4   G dd d}|  tjd|  | tjtj dS )a  
        L{inotify.INotify} emits a C{RuntimeError} when initialized
        in an environment that doesn't support inotify as we expect it.

        We just try to raise an exception for every possible case in
        the for loop in L{inotify.INotify._inotify__init__}.
        c                   @   s   e Zd Zdd ZdS )z;INotifyTests.test_initializationErrors.<locals>.FakeINotifyc                 S   s   t  r
   )r   INotifyErrorr   r   r   r   init.   s   z@INotifyTests.test_initializationErrors.<locals>.FakeINotify.initN)__name__
__module____qualname__r   r   r   r   r   FakeINotify-   s    r   _inotifyN)patchr   r   assertRaisesr   )r   r   r   r   r   test_initializationErrors$   s   	z&INotifyTests.test_initializationErrorsNc                    s`    du r
j d t  fdd}| jjj fddgd |  S )a  
        Test notification from some filesystem operation.

        @param mask: The event mask to use when setting up the watch.

        @param operation: A function which will be called with the
            name of a file in the watched directory and which should
            trigger the event.

        @param expectedPath: Optionally, the name of the path which is
            expected to come back in the notification event; this will
            also be passed to C{operation} (primarily useful when the
            operation is being done to the directory itself, not a
            file in it).

        @return: A L{Deferred} which fires successfully when the
            expected event has been received or fails otherwise.
        Nzfoo.barc                    s0   | \}}} |    |@  d S r
   )assertEqualasBytesMode
assertTrueresultwatchfilenameevents)expectedPathmaskr   r   r   
cbNotifiedK   s   
z2INotifyTests._notificationTest.<locals>.cbNotifiedc                     
     | S r
   callbackargsnotifiedr   r   <lambda>S      
 z0INotifyTests._notificationTest.<locals>.<lambda>r+   	callbacks)r   childr   DeferredaddCallbackr   r'   )r   r+   	operationr*   r,   r   )r*   r+   r3   r   r   _notificationTest4   s   
zINotifyTests._notificationTestc                 C      dd }|  tj|S )z{
        Reading from a file in a monitored directory sends an
        C{inotify.IN_ACCESS} event to the callback.
        c                 S   s   |  d |   d S )N   foo)
setContent
getContentpathr   r   r   r;   ^   s   
z+INotifyTests.test_access.<locals>.operation)r<   r   	IN_ACCESSr   r;   r   r   r   test_accessX      zINotifyTests.test_accessc                 C   r=   )zy
        Writing to a file in a monitored directory sends an
        C{inotify.IN_MODIFY} event to the callback.
        c                 S   s:   |  d}|d W d    d S 1 sw   Y  d S )Nwr>   )openwrite)rB   fObjr   r   r   r;   j   s   "z+INotifyTests.test_modify.<locals>.operation)r<   r   	IN_MODIFYrD   r   r   r   test_modifyd   rF   zINotifyTests.test_modifyc                 C   r=   )z
        Changing the metadata of a file in a monitored directory
        sends an C{inotify.IN_ATTRIB} event to the callback.
        c                 S   s   |    |    d S r
   )touchrA   r   r   r   r;   v      z+INotifyTests.test_attrib.<locals>.operation)r<   r   	IN_ATTRIBrD   r   r   r   test_attribp   rF   zINotifyTests.test_attribc                 C   r=   )z
        Closing a file which was open for writing in a monitored
        directory sends an C{inotify.IN_CLOSE_WRITE} event to the
        callback.
        c                 S      |  d  d S NrG   rH   closerA   r   r   r   r;         z/INotifyTests.test_closeWrite.<locals>.operation)r<   r   IN_CLOSE_WRITErD   r   r   r   test_closeWrite|   s   zINotifyTests.test_closeWritec                 C   r=   )z
        Closing a file which was open for reading but not writing in a
        monitored directory sends an C{inotify.IN_CLOSE_NOWRITE} event
        to the callback.
        c                 S   s   |    | d  d S )Nr)rM   rH   rT   rA   r   r   r   r;      s   z1INotifyTests.test_closeNoWrite.<locals>.operation)r<   r   IN_CLOSE_NOWRITErD   r   r   r   test_closeNoWrite   s   zINotifyTests.test_closeNoWritec                 C   r=   )zt
        Opening a file in a monitored directory sends an
        C{inotify.IN_OPEN} event to the callback.
        c                 S   rQ   rR   rS   rA   r   r   r   r;      rU   z)INotifyTests.test_open.<locals>.operation)r<   r   IN_OPENrD   r   r   r   	test_open      zINotifyTests.test_openc                        fdd}  tj|S )z}
        Moving a file out of a monitored directory sends an
        C{inotify.IN_MOVED_FROM} event to the callback.
        c                    s&   |  d  | t   d S rR   )rH   rT   moveTor   r   r   rA   r   r   r   r;      s   z.INotifyTests.test_movedFrom.<locals>.operation)r<   r   IN_MOVED_FROMrD   r   r   r   test_movedFrom   s   zINotifyTests.test_movedFromc                    r^   )zy
        Moving a file into a monitored directory sends an
        C{inotify.IN_MOVED_TO} event to the callback.
        c                    s$   t   }|  ||  d S r
   )r   r   r   rM   r_   )rB   pr   r   r   r;      s   z,INotifyTests.test_movedTo.<locals>.operation)r<   r   IN_MOVED_TOrD   r   r   r   test_movedTo   s   zINotifyTests.test_movedToc                 C   r=   )zw
        Creating a file in a monitored directory sends an
        C{inotify.IN_CREATE} event to the callback.
        c                 S   rQ   rR   rS   rA   r   r   r   r;      rU   z+INotifyTests.test_create.<locals>.operation)r<   r   	IN_CREATErD   r   r   r   test_create   r]   zINotifyTests.test_createc                 C   r=   )zw
        Deleting a file in a monitored directory sends an
        C{inotify.IN_DELETE} event to the callback.
        c                 S   s   |    |   d S r
   )rM   removerA   r   r   r   r;      rN   z+INotifyTests.test_delete.<locals>.operation)r<   r   	IN_DELETErD   r   r   r   test_delete   rF   zINotifyTests.test_deletec                 C   s   dd }| j tj|| jdS )z{
        Deleting the monitored directory itself sends an
        C{inotify.IN_DELETE_SELF} event to the callback.
        c                 S   s   |    d S r
   )rg   rA   r   r   r   r;      s   z/INotifyTests.test_deleteSelf.<locals>.operationr*   )r<   r   IN_DELETE_SELFr   rD   r   r   r   test_deleteSelf   s   
zINotifyTests.test_deleteSelfc                    sJ   fdd}j jjd fddgd t   | j   S )z
        Deleting the monitored directory itself sends an
        C{inotify.IN_DELETE_SELF} event to the callback
        even if the mask isn't specified by the call to watch().
        c                    s4   | \}}}  |  j   |tj@  d S r
   )r"   r#   r   r$   r   rk   r%   r   r   r   r,      s   
z6INotifyTests.test_deleteSelfForced.<locals>.cbNotifiedr   c                     r-   r
   r.   r0   )dr   r   r4      r5   z4INotifyTests.test_deleteSelfForced.<locals>.<lambda>r6   )r   r'   r   r   r9   r:   rg   r   r,   r   rm   r   r   test_deleteSelfForced   s   

z"INotifyTests.test_deleteSelfForcedc                    s     fdd} j tj| jdS )zy
        Renaming the monitored directory itself sends an
        C{inotify.IN_MOVE_SELF} event to the callback.
        c                    s   |  t   d S r
   )r_   r   r   r   rA   r   r   r   r;      s   z-INotifyTests.test_moveSelf.<locals>.operationrj   )r<   r   IN_MOVE_SELFr   rD   r   r   r   test_moveSelf   s   
zINotifyTests.test_moveSelfc                    T    fdd}t jt jB }j jj|d|gd jdt     S )z
        L{inotify.INotify} when initialized with autoAdd==True adds
        also adds the created subdirectories to the watchlist.
        c                         fdd}t d| d S )Nc                      @   z j  d  W d S  ty      Y d S w r
   )r$   r   
_isWatchedr/   	Exceptionerrbackr   rm   r   subdirr   r   _	     zIINotifyTests.test_simpleSubdirectoryAutoAdd.<locals>._callback.<locals>._r   r   	callLater)wpr(   r+   r{   ry   r   r   	_callback     z>INotifyTests.test_simpleSubdirectoryAutoAdd.<locals>._callbackTr+   autoAddr7   test	r   IN_ISDIRre   r'   r   r8   r   r9   r   r   r   	checkMaskr   ry   r   test_simpleSubdirectoryAutoAdd      z+INotifyTests.test_simpleSubdirectoryAutoAddc                    sZ   g   fdd}t jt jB }j jj|d|gd jdt   S )zz
        L{inotify.INotify} removes a directory from the watchlist when
        it's removed from the filesystem.
        c                    sN   fdd}fdd} s  | td| d S td| d S )Nc                      s>   z j   W d S  ty      Y d S w r
   )r$   r   rv   rg   rw   rx   r   ry   r   r   r{   %  s   zEINotifyTests.test_simpleDeleteDirectory.<locals>._callback.<locals>._c                      ru   r
   assertFalser   rv   r/   rw   rx   r   ry   r   r   _eb,  s   zGINotifyTests.test_simpleDeleteDirectory.<locals>._callback.<locals>._ebr   )appendr   r~   )r   r(   r+   r{   r   callsrm   r   rz   r   r   r   "  s   
z:INotifyTests.test_simpleDeleteDirectory.<locals>._callbackTr   r   r   r   r   r   r   test_simpleDeleteDirectory  s   z'INotifyTests.test_simpleDeleteDirectoryc                    s\    fdd} jjjtjfddgd t | j  t   S )z
        L{inotify.INotify} closes the file descriptor after removing a
        directory from the filesystem (and therefore from the watchlist).
        c                    sN    fdd}| \}}} | j  |tj@  td| d S )Nc                      sP   z jj  jj  d  W d S  ty'      Y d S w r
   )r   r   rv   r   	connectedr/   rw   rx   r   ro   r   r   r{   L  s   zIINotifyTests.test_deleteSelfLoseConnection.<locals>.cbNotified.<locals>._r   )r"   r#   r   r$   r   rk   r   r~   )r&   r{   ignoredr(   r)   ro   r   r   r,   K  s
   
z>INotifyTests.test_deleteSelfLoseConnection.<locals>.cbNotifiedc                     r-   r
   r.   r0   r2   r   r   r4   ]  r5   z<INotifyTests.test_deleteSelfLoseConnection.<locals>.<lambda>r6   )	r$   r   r'   r   rk   r   r9   r:   rg   rn   r   )rm   r3   r   r   test_deleteSelfLoseConnectionE  s   

z*INotifyTests.test_deleteSelfLoseConnectionc                 C   sL   | j j| jdd | | j | j | j | j | | j | j dS )zR
        L{inotify.INotify.ignore} removes a directory from the watchlist
        T)r   N)r   r'   r   r$   rv   ignorer   r   r   r   r   test_ignoreDirectoryh  s   z!INotifyTests.test_ignoreDirectoryc                 C   sV   t jD ]\}}| t |d | qt jt jB t jB }| tt |h d dS )zy
        L{inotify.humaReadableMask} translates all the possible event
        masks to a human readable string.
        r   >   rH   accessclose_writeN)r   _FLAG_TO_HUMANr"   humanReadableMaskrV   rC   r[   set)r   r+   valuer   r   r   r   test_humanReadableMaskq  s   z#INotifyTests.test_humanReadableMaskc                 C   sv   | j d}|d}|d}|  |||g}| jj| j dd | jj| j dd |D ]}| | j| q-dS )z
        L{inotify.INotify.watch} with recursive==True will add all the
        subdirectories under the given path to the watchlist.
        r   test2test3T)	recursiveN)r   r8   makedirsr   r'   r$   rv   )r   rz   subdir2subdir3dirsrm   r   r   r   test_recursiveWatch  s   


z INotifyTests.test_recursiveWatchc                 C   s0   ddl }t }||j |  |   dS )z
        L{inotify.INotify.connectionLost} if there's a problem while closing
        the fd shouldn't raise the exception but should log the error
        r   N)osr   r   rT   _fdr   flushLoggedErrors)r   r   in_r   r   r   test_connectionLostError  s
   z%INotifyTests.test_connectionLostErrorc                    rs   )z
        L{inotify.INotify.watch} with autoAdd==False will stop inotify
        from watching subdirectories created under the watched one.
        c                    rt   )Nc                      ru   r
   r   r   ry   r   r   r{     r|   zEINotifyTests.test_noAutoAddSubdirectory.<locals>._callback.<locals>._r   r}   )r   fpr+   r{   ry   r   r   r     r   z:INotifyTests.test_noAutoAddSubdirectory.<locals>._callbackFr   r   r   r   r   ry   r   test_noAutoAddSubdirectory  r   z'INotifyTests.test_noAutoAddSubdirectoryc                    s   j d    t  fdd}fdd}jj |gd j  jj tj	|gd 
|    S )z
        L{inotify.INotify} will watch a filepath for events even if the same
        path is repeatedly added/removed/re-added to the watchpoints.
        foo.bar2c                    2   | \}}} |    |tj@  d S r
   r"   r#   r$   r   rk   r&   r   r(   r)   )r*   r   r   r   r,        
z<INotifyTests.test_seriesOfWatchAndIgnore.<locals>.cbNotifiedc                          |  d S r
   r.   r0   r2   r   r   callIt     z8INotifyTests.test_seriesOfWatchAndIgnore.<locals>.callItr7   r6   )r   r8   rM   r   r9   r$   r   r'   r   rk   r:   rg   )r   r,   r   r   )r*   r3   r   r   test_seriesOfWatchAndIgnore  s   

z(INotifyTests.test_seriesOfWatchAndIgnorec                    s   j d}|  j d    t  fdd}fdd}jj|tj|gd 	| jj tj|gd j
| |     S )zr
        L{inotify.INotify} will ignore a filepath after it has been removed from
        the watch list.
        r   zfoo.bar3c                    r   r
   r   r   )expectedPath2r   r   r   r,     r   z4INotifyTests.test_ignoreFilePath.<locals>.cbNotifiedc                     r   r
   r.   r0   r2   r   r   r     r   z0INotifyTests.test_ignoreFilePath.<locals>.callItr   )r   r8   rM   r   r9   r$   r   r'   rk   r:   r   rg   )r   r*   r,   r   r   )r   r3   r   r   test_ignoreFilePath  s(   

z INotifyTests.test_ignoreFilePathc                 C   s*   | j d}|  | t| jj| dS )zf
        L{inotify.INotify} will raise KeyError if a non-watched filepath is
        ignored.
        zfoo.ignoredN)r   r8   rM   r    KeyErrorr   r   )r   r*   r   r   r   test_ignoreNonWatchedFile  s   z&INotifyTests.test_ignoreNonWatchedFilec                    s   t    fdd}tjtjB }jjj|d|gd jdddt 	  dd	d
gt
D ]\}}||jt  qKS )aB  
        L{inotify.INotify} with autoAdd==True for a watched path
        generates events for every file or directory already present
        in a newly created subdirectory under the watched one.

        This tests that we solve a race condition in inotify even though
        we may generate duplicate events.
        c                    s     | t dkr\z;j j j g }dd |D }t t|  | W n tyT     Y d S w d  d S d S )N   c                 S   s   h | ]}|  qS r   )r#   ).0fr   r   r   	<setcomp>  s    zRINotifyTests.test_complexSubdirectoryAutoAdd.<locals>._callback.<locals>.<setcomp>)	addlenr$   r   rv   r"   rw   rx   r/   )r   r(   r+   createdr   rm   r   	someFilesrz   r   r   r   r   r     s   
z?INotifyTests.test_complexSubdirectoryAutoAdd.<locals>._callbackTr   r   r   r   z	file1.datz	file2.datz	file3.dat)r   r   r   re   r'   r   r8   r   r9   r   	enumerater?   rB   encodesysgetfilesystemencoding)r   r   r   ir(   r   r   r   test_complexSubdirectoryAutoAdd  s$   	

z,INotifyTests.test_complexSubdirectoryAutoAddr
   )$r   r   r   __doc__r   platformsupportsINotifyskipr   r!   r<   rE   rL   rP   rW   rZ   r\   ra   rd   rf   ri   rl   rp   rr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r	      s@    

$*#	%&
r	   )r   r   twisted.internetr   r   twisted.pythonr   r   twisted.python.reflectr   twisted.trialr   r   TestCaser	   r   r   r   r   <module>   s   