U
    ¸~Hj‚H  ã                   @   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	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   ÚINotifyZstartReadingZ
addCleanupÚloseConnection©Úself© r   úF/tmp/pip-unpacked-wheel-ewod1tgb/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)Ú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   Ú
cbNotifiedK   s    
z2INotifyTests._notificationTest.<locals>.cbNotifiedc                     s
   ˆ   | ¡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(   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   r7   ^   s    
z+INotifyTests.test_access.<locals>.operation)r8   r   Ú	IN_ACCESS©r   r7   r   r   r   Útest_accessX   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Úwr9   )ÚopenÚwrite)r<   ZfObjr   r   r   r7   j   s    z+INotifyTests.test_modify.<locals>.operation)r8   r   Z	IN_MODIFYr>   r   r   r   Útest_modifyd   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
   )Útouchr;   r   r   r   r7   v   s    z+INotifyTests.test_attrib.<locals>.operation)r8   r   Z	IN_ATTRIBr>   r   r   r   Útest_attribp   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@   ©rA   Úcloser;   r   r   r   r7   ƒ   s    z/INotifyTests.test_closeWrite.<locals>.operation)r8   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)rD   rA   rH   r;   r   r   r   r7   �   s    z1INotifyTests.test_closeNoWrite.<locals>.operation)r8   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 rF   rG   r;   r   r   r   r7   ›   s    z)INotifyTests.test_open.<locals>.operation)r8   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 rF   )rA   rH   ÚmoveTor   r   r   r;   r   r   r   r7   ¦   s    z.INotifyTests.test_movedFrom.<locals>.operation)r8   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   rD   rO   )r<   Úpr   r   r   r7   ²   s    z,INotifyTests.test_movedTo.<locals>.operation)r8   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 rF   rG   r;   r   r   r   r7   ¿   s    z+INotifyTests.test_create.<locals>.operation)r8   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
   )rD   Úremover;   r   r   r   r7   Ê   s    z+INotifyTests.test_delete.<locals>.operation)r8   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
   )rU   r;   r   r   r   r7   Ö   s    z/INotifyTests.test_deleteSelf.<locals>.operation©r'   )r8   r   ÚIN_DELETE_SELFr   r>   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   rX   r"   r   r   r   r)   ä   s    
z6INotifyTests.test_deleteSelfForced.<locals>.cbNotifiedr   c                     s
   ˆ   | ¡S r
   r*   r,   )Údr   r   r0   ê   r1   z4INotifyTests.test_deleteSelfForced.<locals>.<lambda>r2   )r   r$   r   r   r5   r6   rU   ©r   r)   r   ©rZ   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
   )rO   r   r   r   r;   r   r   r   r7   ù   s    z-INotifyTests.test_moveSelf.<locals>.operationrW   )r8   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   ©rZ   r   Úsubdirr   r   Ú_	  s
    zIINotifyTests.test_simpleSubdirectoryAutoAdd.<locals>._callback.<locals>._r   ©r   Ú	callLater)Úwpr%   r(   rd   rb   r   r   Ú	_callback  s    z>INotifyTests.test_simpleSubdirectoryAutoAdd.<locals>._callbackT©r(   ÚautoAddr3   Útest©	r   ÚIN_ISDIRrS   r$   r   r4   r   r5   r   ©r   rh   Ú	checkMaskr   rb   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   r_   rU   r`   ra   r   rb   r   r   rd   %  s
    zEINotifyTests.test_simpleDeleteDirectory.<locals>._callback.<locals>._c                      sB   z ˆ  ˆj ˆ¡¡ ˆ  d ¡ W n tk
r<   ˆ  ¡  Y nX d S r
   ©ÚassertFalser   r_   r+   r`   ra   r   rb   r   r   Ú_eb,  s
    zGINotifyTests.test_simpleDeleteDirectory.<locals>._callback.<locals>._ebr   )Úappendr   rf   )rg   r%   r(   rd   rs   ©ÚcallsrZ   r   rc   r   r   rh   "  s    
z:INotifyTests.test_simpleDeleteDirectory.<locals>._callbackTri   rk   rl   rn   r   ru   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                      sR   z0ˆ  ˆj ˆj¡¡ ˆ  ˆjj¡ ˆ  d ¡ W n tk
rL   ˆ  ¡  Y nX d S r
   )rr   r   r_   r   Ú	connectedr+   r`   ra   r   r\   r   r   rd   L  s    zIINotifyTests.test_deleteSelfLoseConnection.<locals>.cbNotified.<locals>._r   )r   r    r   r!   r   rX   r   rf   )r#   rd   Úignoredr%   r&   r\   r   r   r)   K  s
    
z>INotifyTests.test_deleteSelfLoseConnection.<locals>.cbNotifiedc                     s
   ˆ   | ¡S r
   r*   r,   r.   r   r   r0   ]  r1   z<INotifyTests.test_deleteSelfLoseConnection.<locals>.<lambda>r2   )	r!   r   r$   r   rX   r   r5   r6   rU   r[   r   )rZ   r/   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)rj   N)r   r$   r   r!   r_   Úignorerr   r   r   r   r   Útest_ignoreDirectoryh  s    z!INotifyTests.test_ignoreDirectoryc                 C   sX   t jD ]\}}|  t  |¡d |¡ qt jt jB t jB }|  tt  |¡ƒdddh¡ dS )zy
        L{inotify.humaReadableMask} translates all the possible event
        masks to a human readable string.
        r   Zclose_writeÚaccessrA   N)r   Z_FLAG_TO_HUMANr   ZhumanReadableMaskrI   r=   rM   Úset)r   r(   Úvaluero   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 |¡¡ qZdS )zŽ
        L{inotify.INotify.watch} with recursive==True will add all the
        subdirectories under the given path to the watchlist.
        rk   Útest2Útest3T)Ú	recursiveN)r   r4   Úmakedirsr   r$   r!   r_   )r   rc   Úsubdir2Úsubdir3ÚdirsrZ   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   rH   Z_fdr   ZflushLoggedErrors)r   r‰   Zin_r   r   r   Útest_connectionLostError�  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
   rq   r   rb   r   r   rd   ¤  s
    zEINotifyTests.test_noAutoAddSubdirectory.<locals>._callback.<locals>._r   re   )rg   Úfpr(   rd   rb   r   r   rh   ¡  s    z:INotifyTests.test_noAutoAddSubdirectory.<locals>._callbackFri   rk   rl   rn   r   rb   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   rX   ©r#   ry   r%   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©r3   r2   )r   r4   rD   r   r5   r!   r   r$   r{   rX   r6   rU   )r   r)   r�   r   )r'   r/   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                    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   r4   rD   r   r5   r!   r   r$   rX   r6   r{   rU   )r   r'   r)   r�   r   )r“   r/   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   r4   rD   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 ¡ ¡¡ 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r´zvˆ ˆ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   r_   r   r`   ra   r+   )rg   r%   r(   Úcreated©rv   rZ   r   Z	someFilesrc   r…   r†   r   r   rh     s    
z?INotifyTests.test_complexSubdirectoryAutoAdd.<locals>._callbackTri   rk   r�   r‚   z	file1.datz	file2.datz	file3.dat)r~   r   rm   rS   r$   r   r4   r   r5   r„   Ú	enumerater:   r<   ÚencodeÚsysÚgetfilesystemencoding)r   rh   ro   Úir%   r   rž   r   Útest_complexSubdirectoryAutoAdd  s*    	   ÿ

ýz,INotifyTests.test_complexSubdirectoryAutoAdd)N)$r   r   r   Ú__doc__r   ÚplatformZsupportsINotifyÚskipr   r   r8   r?   rC   rE   rJ   rL   rN   rP   rR   rT   rV   rY   r]   r^   rp   rw   rz   r|   r€   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   