o
    ¯b‚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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   