U
    
W[.A                     @   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k	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	d8d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!dS )9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   INotifyZstartReadingZ
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  d S 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   Z_inotifyN)Zpatchr   r   assertRaisesr   )r   r   r   r   r   test_initializationErrors%   s    z&INotifyTests.test_initializationErrorsNc                    s`    dk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   
cbNotifiedJ   s    
z2INotifyTests._notificationTest.<locals>.cbNotifiedc                     s
     | S r
   callbackargsnotifiedr   r   <lambda>R       z0INotifyTests._notificationTest.<locals>.<lambda>r&   	callbacks)r   childr   DeferredaddCallbackr   r"   )r   r&   	operationr%   r'   r   )r%   r&   r-   r   r   _notificationTest4   s    
 zINotifyTests._notificationTestc                 C   s   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)
setContentZ
getContentpathr   r   r   r5   \   s    
z+INotifyTests.test_access.<locals>.operation)r6   r   	IN_ACCESSr   r5   r   r   r   test_accessW   s    zINotifyTests.test_accessc                 C   s   dd }|  tj|S )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 5 Q R X d S )Nwr7   )openwrite)r:   ZfObjr   r   r   r5   h   s    z+INotifyTests.test_modify.<locals>.operation)r6   r   Z	IN_MODIFYr<   r   r   r   test_modifyc   s    zINotifyTests.test_modifyc                 C   s   dd }|  tj|S )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
   )touchr9   r   r   r   r5   t   s    z+INotifyTests.test_attrib.<locals>.operation)r6   r   Z	IN_ATTRIBr<   r   r   r   test_attribo   s    zINotifyTests.test_attribc                 C   s   dd }|  tj|S )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   s   |  d  d S Nr>   r?   closer9   r   r   r   r5      s    z/INotifyTests.test_closeWrite.<locals>.operation)r6   r   IN_CLOSE_WRITEr<   r   r   r   test_closeWrite{   s    zINotifyTests.test_closeWritec                 C   s   dd }|  tj|S )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)rB   r?   rF   r9   r   r   r   r5      s    z1INotifyTests.test_closeNoWrite.<locals>.operation)r6   r   ZIN_CLOSE_NOWRITEr<   r   r   r   test_closeNoWrite   s    zINotifyTests.test_closeNoWritec                 C   s   dd }|  tj|S )zt
        Opening a file in a monitored directory sends an
        C{inotify.IN_OPEN} event to the callback.
        c                 S   s   |  d  d S rD   rE   r9   r   r   r   r5      s    z)INotifyTests.test_open.<locals>.operation)r6   r   IN_OPENr<   r   r   r   	test_open   s    zINotifyTests.test_openc                    s    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 rD   )r?   rF   moveTor   r   r   r9   r   r   r   r5      s    z.INotifyTests.test_movedFrom.<locals>.operation)r6   r   ZIN_MOVED_FROMr<   r   r   r   test_movedFrom   s    zINotifyTests.test_movedFromc                    s    fdd}  tj|S )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   rB   rM   )r:   pr   r   r   r5      s    z,INotifyTests.test_movedTo.<locals>.operation)r6   r   ZIN_MOVED_TOr<   r   r   r   test_movedTo   s    zINotifyTests.test_movedToc                 C   s   dd }|  tj|S )zw
        Creating a file in a monitored directory sends an
        C{inotify.IN_CREATE} event to the callback.
        c                 S   s   |  d  d S rD   rE   r9   r   r   r   r5      s    z+INotifyTests.test_create.<locals>.operation)r6   r   	IN_CREATEr<   r   r   r   test_create   s    zINotifyTests.test_createc                 C   s   dd }|  tj|S )zw
        Deleting a file in a monitored directory sends an
        C{inotify.IN_DELETE} event to the callback.
        c                 S   s   |    |   d S r
   )rB   remover9   r   r   r   r5      s    z+INotifyTests.test_delete.<locals>.operation)r6   r   Z	IN_DELETEr<   r   r   r   test_delete   s    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
   )rS   r9   r   r   r   r5      s    z/INotifyTests.test_deleteSelf.<locals>.operationr%   )r6   r   IN_DELETE_SELFr   r<   r   r   r   test_deleteSelf   s      zINotifyTests.test_deleteSelfc                    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
   )rM   r   r   r   r9   r   r   r   r5      s    z-INotifyTests.test_moveSelf.<locals>.operationrU   )r6   r   ZIN_MOVE_SELFr   r<   r   r   r   test_moveSelf   s      zINotifyTests.test_moveSelfc                    sT    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                    s     fdd}t d| d S )Nc                      sB   z  j  d  W n tk
r<      Y nX d S r
   )r    r   
_isWatchedr)   	Exceptionerrbackr   dr   subdirr   r   _   s
    zIINotifyTests.test_simpleSubdirectoryAutoAdd.<locals>._callback.<locals>._r   r   	callLater)wpr#   r&   r_   r\   r   r   	_callback   s    z>INotifyTests.test_simpleSubdirectoryAutoAdd.<locals>._callbackTr&   autoAddr1   test	r   IN_ISDIRrQ   r"   r   r2   r   r3   r   r   rc   	checkMaskr   r\   r   test_simpleSubdirectoryAutoAdd   s      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                    sL   fdd}fdd} s<  | td| ntd| d S )Nc                      s@   z j   W n tk
r:      Y nX d S r
   )r    r   rY   rS   rZ   r[   r   r\   r   r   r_   
  s
    zEINotifyTests.test_simpleDeleteDirectory.<locals>._callback.<locals>._c                      sB   z  j  d  W n tk
r<      Y nX d S r
   assertFalser   rY   r)   rZ   r[   r   r\   r   r   _eb  s
    zGINotifyTests.test_simpleDeleteDirectory.<locals>._callback.<locals>._ebr   )appendr   ra   )rb   r#   r&   r_   rn   callsr]   r   r^   r   r   rc     s    
z:INotifyTests.test_simpleDeleteDirectory.<locals>._callbackTrd   rf   rg   ri   r   rp   r   test_simpleDeleteDirectory  s      z'INotifyTests.test_simpleDeleteDirectoryc                 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)re   N)r   r"   r   r    rY   ignorerm   r   r   r   r   test_ignoreDirectory*  s    z!INotifyTests.test_ignoreDirectoryc                 C   s\   t jD ]\}}| t |d | qt jt jB t jB }| tt |tdddg dS )zy
        L{inotify.humaReadableMask} translates all the possible event
        masks to a human readable string.
        r   Zclose_writeaccessr?   N)r   Z_FLAG_TO_HUMANr   ZhumanReadableMaskrG   r;   rK   set)r   r&   valuerj   r   r   r   test_humanReadableMask4  s    z#INotifyTests.test_humanReadableMaskc                 C   sv   | j d}|d}|d}|  |||g}| jj| j dd | jj| j dd |D ]}| | j| qZdS )z
        L{inotify.INotify.watch} with recursive==True will add all the
        subdirectories under the given path to the watchlist.
        rf   test2test3T)	recursiveN)r   r2   makedirsr   r"   r    rY   )r   r^   subdir2subdir3dirsr]   r   r   r   test_recursiveWatchC  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   rF   Z_fdr   ZflushLoggedErrors)r   r   Zin_r   r   r   test_connectionLostErrorT  s
    z%INotifyTests.test_connectionLostErrorc                    sT    fdd}t jt jB }j jj|d|gd jdt     S )z
        L{inotify.INotify.watch} with autoAdd==False will stop inotify
        from watching subdirectories created under the watched one.
        c                    s     fdd}t d| d S )Nc                      sB   z  j  d  W n tk
r<      Y nX d S r
   rl   r   r\   r   r   r_   g  s
    zEINotifyTests.test_noAutoAddSubdirectory.<locals>._callback.<locals>._r   r`   )rb   fpr&   r_   r\   r   r   rc   d  s    z:INotifyTests.test_noAutoAddSubdirectory.<locals>._callbackFrd   rf   rg   ri   r   r\   r   test_noAutoAddSubdirectory_  s      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                    s2   | \}}} |    |tj@  d S r
   r   r   r    r   rV   r!   Zignoredr#   r$   )r%   r   r   r   r'     s    
z<INotifyTests.test_seriesOfWatchAndIgnore.<locals>.cbNotifiedc                     s     |  d S r
   r(   r*   r,   r   r   callIt  s    z8INotifyTests.test_seriesOfWatchAndIgnore.<locals>.callItr1   r0   )r   r2   rB   r   r3   r    r   r"   rs   rV   r4   rS   )r   r'   r   r   )r%   r-   r   r   test_seriesOfWatchAndIgnorey  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                    s2   | \}}} |    |tj@  d S r
   r   r   )expectedPath2r   r   r   r'     s    
z4INotifyTests.test_ignoreFilePath.<locals>.cbNotifiedc                     s     |  d S r
   r(   r*   r,   r   r   r     s    z0INotifyTests.test_ignoreFilePath.<locals>.callItr   )r   r2   rB   r   r3   r    r   r"   rV   r4   rs   rS   )r   r%   r'   r   r   )r   r-   r   r   test_ignoreFilePath  s4      
  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   r2   rB   r   KeyErrorr   rs   )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  q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rzvj j j g }dd |D }t t|  | W n tk
r     Y nX d  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   rY   r   rZ   r[   r)   )rb   r#   r&   Zcreatedrq   r]   r   Z	someFilesr^   r}   r~   r   r   rc     s    
z?INotifyTests.test_complexSubdirectoryAutoAdd.<locals>._callbackTrd   rf   ry   rz   z	file1.datz	file2.datz	file3.dat)rv   r   rh   rQ   r"   r   r2   r   r3   r|   	enumerater8   r:   encodesysgetfilesystemencoding)r   rc   rj   ir#   r   r   r   test_complexSubdirectoryAutoAdd  s.    	  

z,INotifyTests.test_complexSubdirectoryAutoAdd)N)"r   r   r   __doc__r   platformZsupportsINotifyskipr   r   r6   r=   rA   rC   rH   rJ   rL   rN   rP   rR   rT   rW   rX   rk   rr   rt   rx   r   r   r   r   r   r   r   r   r   r   r   r	      s:   

#)
#$r	   )r   r   Ztwisted.internetr   r   Ztwisted.pythonr   r   Ztwisted.python.reflectr   Ztwisted.trialr   r   ZTestCaser	   r   r   r   r   <module>   s   