o
    fG                     @   s  d Z ddlZddlZddlZddlZddlZddlZddlZddlm	Z	 ddl
mZ ddlmZ ddlmZ ddlmZ ddlmZmZ dd	lmZ dd
lmZmZmZmZmZ ddlmZ ddlm Z m!Z! ddl"m#Z# ddl$m%Z% ddl&m'Z' ddl(m)Z) ddl*m+Z+ ddl,m-Z- ddl.m/Z/ e+dZ0e+dZ1e+dZ2e1re0rz(ddl3m4Z4 ddl5m6Z6 ddl7m8Z8 ddl9m:Z:m;Z; ddl<m=Z= ddlm>Z> W n	 e?y   Y nw dZ@de2e1e0eAedfv rdZ@ee@dG d d! d!e/ZBG d"d# d#e/ZCG d$d% d%e-ZDG d&d' d'ZEG d(d) d)ZFeeG d*d+ d+e	ZGee@dG d,d- d-e/ZHG d.d/ d/ZIG d0d1 d1ejJZKG d2d3 d3eZLee@dG d4d5 d5eLZMee@dG d6d7 d7eLZNee@dee)d8 d9G d:d; d;eLZOdS )<z*
Tests for L{twisted.conch.scripts.cftp}.
    N)BytesIO)skipIf)implementer)ls)	ISFTPFile)FileTransferTestAvatarSFTPTestBase)portal)defererror
interfacesprotocolreactor)Clock)getProcessOutputAndValuegetProcessValue)log)UserDatabase)FilePath)which)requireModule)StringTransport)TestCasepyasn1cryptographyztwisted.conch.unix)cftp)
SSHSession)filetransfer)
test_conchtest_ssh)	FakeStdio)FileTransferForTestAvatarFTz4don't run w/o spawnProcess or cryptography or pyasn1c                   @   s   e Zd ZdZdd ZdS )SSHSessionTestsz=
    Tests for L{twisted.conch.scripts.cftp.SSHSession}.
    c                 C   s*   t  }t }||_|  | |j dS )z|
        L{twisted.conch.scripts.cftp.SSHSession.eofReceived} loses the write
        half of its stdio connection.
        N)r    r   stdioeofReceived
assertTruewriteConnLost)selfr#   channel r)   >/usr/lib/python3/dist-packages/twisted/conch/test/test_cftp.pytest_eofReceived>   s
   z SSHSessionTests.test_eofReceivedN)__name__
__module____qualname____doc__r+   r)   r)   r)   r*   r"   8   s    r"   c                   @   s   e Zd ZdZeedddu rdZdd Zdd Zd	d
 Z	dd Z
dd Ze Zzz	eejd W n ejy>   dZY nw eeje W n   Y eeddd Zdd ZdS )ListingTestsz
    Tests for L{lsLine}, the function which generates an entry for a file or
    directory in an SFTP I{ls} command's output.
    tzsetNz8Cannot test timestamp formatting code without time.tzsetc                    sj   d _  fdd} td| dtjv r* tjtjdtjd   tj	 dS dd } | dS )	zo
        Patch the L{ls} module's time function so the results of L{lsLine} are
        deterministic.
        i[c                      s    j S N)nowr)   r'   r)   r*   fakeTimeZ   s   z$ListingTests.setUp.<locals>.fakeTimetimeTZc                   S   s,   zt jd= W n	 ty   Y nw t  d S )Nr7   )osenvironKeyErrorr6   r1   r)   r)   r)   r*   cleanupf   s   z#ListingTests.setUp.<locals>.cleanupN)
r3   patchr   r8   r9   
addCleanupoperatorsetitemr6   r1   )r'   r5   r;   r)   r4   r*   setUpS   s   
zListingTests.setUpc                 C   s   |t jd< t  td|S )zl
        Call L{ls.lsLine} after setting the timezone to C{timezone} and return
        the result.
        r7   foo)r8   r9   r6   r1   r   lsLine)r'   timezonestatr)   r)   r*   _lsInTimezonep   s   
zListingTests._lsInTimezonec                 C   T   | j d }tdddddddd|df
}| | d|d | | d|d dS )z
        A file with an mtime six months (approximately) or more in the past has
        a listing including a low-resolution timestamp.
        r   America/New_Yorkz;!---------    0 0        0               0 Apr 26  1973 fooPacific/Aucklandz;!---------    0 0        0               0 Apr 27  1973 fooNr3   r8   stat_resultassertEqualrE   r'   thenrD   r)   r)   r*   test_oldFile{      


zListingTests.test_oldFilec                 C   X   | j d d }tdddddddd|df
}| | d|d | | d|d dS )	
        A file with a high-resolution timestamp which falls on a day of the
        month which can be represented by one decimal digit is formatted with
        one padding 0 to preserve the columns which come after it.
        rG   i r   rH   z;!---------    0 0        0               0 May 01  1973 foorI   z;!---------    0 0        0               0 May 02  1973 fooNrJ   rM   r)   r)   r*   test_oldSingleDigitDayOfMonth      

z*ListingTests.test_oldSingleDigitDayOfMonthc                 C   rF   )z
        A file with an mtime fewer than six months (approximately) in the past
        has a listing including a high-resolution timestamp excluding the year.
        逛z r   rH   ;!---------    0 0        0               0 Aug 28 17:33 foorI   ;!---------    0 0        0               0 Aug 29 09:33 fooNrJ   rM   r)   r)   r*   test_newFile   rP   zListingTests.test_newFile
es_AR.UTF8Tz'The es_AR.UTF8 locale is not installed.c                 C   s|   | j d }tdddddddd|df
}t }ttjd | tjtj| | | 	d|d | | 	d|d dS )	zC
        The month name in the date is locale independent.
        rU   r   rY   rH   rV   rI   rW   N)
r3   r8   rK   locale	getlocale	setlocaleLC_ALLr=   rL   rE   )r'   rN   rD   currentLocaler)   r)   r*   test_localeIndependent   s   


z#ListingTests.test_localeIndependentc                 C   rQ   )	rR   rU   i F r   rH   z;!---------    0 0        0               0 Sep 01 17:33 foorI   z;!---------    0 0        0               0 Sep 02 09:33 fooNrJ   rM   r)   r)   r*   test_newSingleDigitDayOfMonth   rT   z*ListingTests.test_newSingleDigitDayOfMonth)r,   r-   r.   r/   getattrr6   skipr@   rE   rO   rS   rX   rZ   r[   r^   r\   r]   Error
localeSkipr   r_   r`   r)   r)   r)   r*   r0   J   s.    
r0   c                       s    e Zd ZdZ fddZ  ZS )InMemorySSHChannelzp
    Minimal implementation of a L{SSHChannel} like class which only reads and
    writes data from memory.
    c                    s   || _ d| _t   dS )zt
        @param conn: The SSH connection associated with this channel.
        @type conn: L{SSHConnection}
        r   N)connlocalClosedsuper__init__)r'   rf   	__class__r)   r*   ri      s   zInMemorySSHChannel.__init__)r,   r-   r.   r/   ri   __classcell__r)   r)   rj   r*   re      s    re   c                   @   (   e Zd ZdZdd Zdd Zdd ZdS )	FilesystemAccessExpectationszC
    A test helper used to support expected filesystem access.
    c                 C   s
   i | _ d S r2   _cacher4   r)   r)   r*   ri        
z%FilesystemAccessExpectations.__init__c                 C   s   || j ||f< dS )z

        @param path: Path at which the stream is requested.
        @type path: L{str}

        @param path: Flags with which the stream is requested.
        @type path: L{str}

        @param stream: A stream.
        @type stream: C{File}
        Nro   )r'   pathflagsstreamr)   r)   r*   put  s   z FilesystemAccessExpectations.putc                 C   s   | j ||fS )a  
        Remove a stream from the memory.

        @param path: Path at which the stream is requested.
        @type path: L{str}

        @param path: Flags with which the stream is requested.
        @type path: L{str}

        @return: A stream.
        @rtype: C{File}
        )rp   pop)r'   rr   rs   r)   r)   r*   rv     s   z FilesystemAccessExpectations.popN)r,   r-   r.   r/   ri   ru   rv   r)   r)   r)   r*   rn      s
    rn   c                   @   s    e Zd ZdZdd Zdd ZdS )InMemorySFTPClienta'  
    A L{filetransfer.FileTransferClient} which does filesystem operations in
    memory, without touching the local disc or the network interface.

    @ivar _availableFiles: File like objects which are available to the SFTP
        client.
    @type _availableFiles: L{FilesystemRegister}
    c                 C   s    t | | _ddd| _|| _d S )N   
   )requests
buffersize)re   	transportoptions_availableFiles)r'   availableFilesr)   r)   r*   ri   ,  s
   

zInMemorySFTPClient.__init__c                 C   s   | j ||S )z}
        @see: L{filetransfer.FileTransferClient.openFile}.

        Retrieve and remove cached file based on flags.
        )r~   rv   )r'   filenamers   attrsr)   r)   r*   openFile4  s   zInMemorySFTPClient.openFileN)r,   r-   r.   r/   ri   r   r)   r)   r)   r*   rw   "  s    	rw   c                   @   sH   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dS )InMemoryRemoteFilez;
    An L{ISFTPFile} which handles all data in memory.
    c                 C   s   || _ t|  dS )zL
        @param name: Name of this file.
        @type name: L{str}
        N)namer   ri   )r'   r   r)   r)   r*   ri   C  s   zInMemoryRemoteFile.__init__c                 C   s   |  | | | t| S )z/
        @see: L{ISFTPFile.writeChunk}
        )seekwriter
   succeed)r'   startdatar)   r)   r*   
writeChunkK  s   


zInMemoryRemoteFile.writeChunkc                 C   s
   d| _ dS )zo
        @see: L{ISFTPFile.writeChunk}

        Keeps data after file was closed to help with testing.
        TN)_closedr4   r)   r)   r*   closeS     
zInMemoryRemoteFile.closec                 C      d S r2   r)   r4   r)   r)   r*   getAttrs[     zInMemoryRemoteFile.getAttrsc                 C   r   r2   r)   )r'   offsetlengthr)   r)   r*   	readChunk_  r   zInMemoryRemoteFile.readChunkc                 C   r   r2   r)   )r'   r   r)   r)   r*   setAttrsc  r   zInMemoryRemoteFile.setAttrsc                 C   s
   t | S )zb
        Get current data of file.

        Allow reading data event when file is closed.
        )r   getvaluer4   r)   r)   r*   r   g  r   zInMemoryRemoteFile.getvalueN)r,   r-   r.   r/   ri   r   r   r   r   r   r   r)   r)   r)   r*   r   =  s    r   c                   @   s   e Zd Z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dZd*dd Zd!d" Zd#d$ Zd%d& Zd'd( ZdS )+StdioClientTestsz(
    Tests for L{cftp.StdioClient}.
    c                 C   sT   t  | _t| j}t|| _d| j_t  | _| j_	| 
dd | jjj| j_dS )zm
        Create a L{cftp.StdioClient} hooked up to dummy transport and a fake
        user database.
        /i     N)rn   fakeFilesystemrw   r   StdioClientclientcurrentDirectoryr   database_pwdsetKnownConsoleSizer|   )r'   
sftpClientr)   r)   r*   r@   v  s   
zStdioClientTests.setUpc              	   C   s@   | j t dt dddtj | j	d}|
| jd |S )zs
        The I{exec} command runs its arguments locally in a child process
        using the user's shell.
        secret  rA   barzexec print(1 + 2)s   3
)r   addUsergetpassgetuserr8   getuidsys
executabler   _dispatchCommandaddCallbackrL   r'   dr)   r)   r*   	test_exec  s   zStdioClientTests.test_execc              	   C   >   | j t dt dddd | jd}|| j	d |S )zr
        If the local user has no shell, the I{exec} command runs its arguments
        using I{/bin/sh}.
        r   r   rA   r    zexec echo hello   hello

r   r   r   r   r8   r   r   r   r   rL   r   r)   r)   r*   test_execWithoutShell  s   z&StdioClientTests.test_execWithoutShellc              	   C   r   )zO
        The I{exec} command is run for lines which start with C{"!"}.
        r   r   rA   r   z/bin/shz!echo hellor   r   r   r)   r)   r*   	test_bang  s   zStdioClientTests.test_bangc                    s2   ddl G  fddd}| td|  dS )a  
        For the duration of this test, patch C{cftp}'s C{fcntl} module to return
        a fixed width and height.

        @param width: the width in characters
        @type width: L{int}
        @param height: the height in characters
        @type height: L{int}
        r   Nc                       s   e Zd Z fddZdS )z7StdioClientTests.setKnownConsoleSize.<locals>.FakeFcntlc                    s&   |j kr
| d td ddS )Nz#Only window-size queries supported.4Hr   )
TIOCGWINSZfailstructpack)r'   fdoptmutateheightttywidthr)   r*   ioctl  s   

z=StdioClientTests.setKnownConsoleSize.<locals>.FakeFcntl.ioctlN)r,   r-   r.   r   r)   r   r)   r*   	FakeFcntl  s    r   fcntl)r   r<   r   )r'   r   r   r   r)   r   r*   r     s   z$StdioClientTests.setKnownConsoleSizec                 C   s   |  dd t  }| j_td}d|_t|}d|_|	 }|
d | jd7  _| j|| d}| | jj | d	S )
a(  
        L{StdioClient._printProgressBar} prints a progress description,
        including percent done, amount transferred, transfer rate, and time
        remaining, all based the given start time, the given L{FileWrapper}'s
        progress information and the reactor's current time.
        ry   "      x   samplei (  g       @i   s#   b'sample' 40% 4.0kB 2.0kBps 00:03 N)r   r   r   r   r   r   r   FileWrappersizesecondsadvancetotal_printProgressBarrL   r|   valuer'   clockwrappedwrapper	startTimeresultr)   r)   r*   test_printProgressBarReporting  s   	

z/StdioClientTests.test_printProgressBarReportingc                 C   sd   |  dd t  }| j_td}d|_t|}| }| j	|| d}| 
| jj | dS )z
        L{StdioClient._printProgressBar} prints a progress description that
        indicates 0 bytes transferred if no bytes have been transferred and no
        time has passed.
        ry   r   r   r   s!   b'sample'  0% 0.0B 0.0Bps 00:00 N)r   r   r   r   r   r   r   r   r   r   rL   r|   r   r   r)   r)   r*   test_printProgressBarNoProgress  s   
z0StdioClientTests.test_printProgressBarNoProgressc                 C   sL   |  dd t }d|_t|}| j|d d}| || jj	  dS )z5
        Print the progress for empty files.
        ry   r   s
   empty-filer   s%   b'empty-file'100% 0.0B 0.0Bps 00:00 N)
r   r   r   r   r   r   r   rL   r|   r   )r'   r   r   r   r)   r)   r*   test_printProgressBarEmptyFile  s   
z/StdioClientTests.test_printProgressBarEmptyFilec                 C      | j d}| d| dS )zK
        Returns empty value for both filename and remaining data.
        z  )r   r   Nr   _getFilenamerL   r'   r   r)   r)   r*   test_getFilenameEmpty  s   z&StdioClientTests.test_getFilenameEmptyc                 C   r   )zd
        Returns empty value for remaining data when line contains
        only a filename.
        
only-local)r   r   Nr   r   r)   r)   r*   test_getFilenameOnlyLocal     z*StdioClientTests.test_getFilenameOnlyLocalc                 C   r   )ze
        Returns filename and remaining data striped of leading and trailing
        spaces.
        z local  remote file  )localzremote fileNr   r   r)   r)   r*   test_getFilenameNotQuoted  r   z*StdioClientTests.test_getFilenameNotQuotedc                 C   r   )z
        Returns filename and remaining data not striped of leading and trailing
        spaces when quoted paths are requested.
        z" " local file "  " remote  file " )z local file z" remote  file "Nr   r   r)   r)   r*   test_getFilenameQuoted  r   z'StdioClientTests.test_getFilenameQuotedN    c                 C   sJ   |du r|   }t|d}|| W d   |S 1 sw   Y  |S )ab  
        Create a local file and return its path.

        When `path` is L{None}, it will create a new temporary file.

        @param path: Optional path for the new file.
        @type path: L{str}

        @param content: Content to be written in the new file.
        @type content: L{bytes}

        @return: Path to the newly create file.
        Nwb)mktempopenr   )r'   rr   contentfiler)   r)   r*   makeFile  s   
zStdioClientTests.makeFileFc                 C   sh  | j j }|d}|d}g }g }|D ]\}}}g }	|D ]}
|	| d|
  q|	d| d|  ||	 |ddd}|dd	 }|d	 d
d
}|| g }|dd	 D ]$}
|
 	ddd }
|
 dd}
||
d  d|
d    qd||d	  || q|r| 
t|t| n| 
|| | 
dt|d dS )a  
        Check output of cftp client for a put request.


        @param transfers: List with tuple of (local, remote, progress).
        @param randomOrder: When set to C{True}, it will ignore the order
            in which put reposes are received

        utf-8z
 zTransferred z to r   N
   rx   z5There are still put responses which were not checked.)r   r|   r   decodesplitappendrv   stripextendrsplitrL   sortedlen)r'   	transfersrandomOrderoutputexpectedOutputactualOutputr   remoteexpectedexpectedTransferlineprogressPartsactuallastactualTransferr)   r)   r*   checkPutMessage3  s<   




"z StdioClientTests.checkPutMessagec                 C   s   d}| j |d}tjtjB tjB }tjdtj|}t	|}| j
||t| d| jjjd< | j|}| | | ||  | |j | ||g dfg dS )z
        A name based on local path is used when remote path is not
        provided.

        The progress is updated while chunks are transferred.
        s   Test
Content)r   r   ry   r{   )z	76% 10.0B
100% 13.0Br  N)r   r   	FXF_WRITE	FXF_CREAT	FXF_TRUNCr8   rr   joinbasenamer   r   ru   r
   r   r   r}   cmd_PUTsuccessResultOfrL   r   r%   r   r  )r'   r   	localPathrs   
remoteName
remoteFiledeferredr)   r)   r*   test_cmd_PUTSingleNoRemotePathp  s   
z/StdioClientTests.test_cmd_PUTSingleNoRemotePathc                 C   s   |   }tjtjB tjB }d}t|}| j||t	| | j
| d| d}| | | ||dgfg | |j | d|  dS )z
        Remote path is extracted from first filename after local file.

        Any other data in the line is ignored.
        z/remote-pathr   z ignored	100% 0.0Br   N)r   r   r  r  r  r   r   ru   r
   r   r   r  r  r  r%   r   rL   r   )r'   r  rs   r  r  r  r)   r)   r*   test_cmd_PUTSingleRemotePath  s   
z-StdioClientTests.test_cmd_PUTSingleRemotePathc                 C   s  |   }tj|}d}tj|}| j tj||d}tjtjB tj	B }d| }d| }t
|}	t
|}
| j||t|	 | j||t|
 | jtj|d}| | | |	j | d|	  | |
j | d|
  | j||dgf||dgfgdd d	S )
z
        When a gobbing expression is used local files are transferred with
        remote file names based on local names.
        second-namerr   r   *r   r  Tr   N)r   r8   rr   r
  dirnamer	  r   r  r  r  r   r   ru   r
   r   r   r  r  r%   r   rL   r   r  )r'   first	firstName
secondNameparentsecondrs   firstRemotePathsecondRemotePathfirstRemoteFilesecondRemoteFiler  r)   r)   r*    test_cmd_PUTMultipleNoRemotePath  s4   





z1StdioClientTests.test_cmd_PUTMultipleNoRemotePathc                 C   s   |   }tj|}d}tj|}| j tj||d}tjtjB tj	B }t
|}t
|}d| }	d| }
| j|	|t| | j|
|t| | jdtj|d}| | | |j | d|  | |j | d|  | j||dgf||dgfgdd	 d
S )z
        When a gobbing expression is used local files are transferred with
        remote file names based on local names.
        when a remote folder is requested remote paths are composed from
        remote path and local filename.
        r  r  z/remote/z	{} remoter  r   r  Tr  N)r   r8   rr   r
  r  r	  r   r  r  r  r   r   ru   r
   r   r   r  formatr  r%   r   rL   r   r  )r'   r  r  r  r  r  rs   r   r!  r  r  r  r)   r)   r*   "test_cmd_PUTMultipleWithRemotePath  s4   





z3StdioClientTests.test_cmd_PUTMultipleWithRemotePath)Nr   )F)r,   r-   r.   r/   r@   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r"  r$  r)   r)   r)   r*   r   p  s(    		
	
=#r   c                   @   s   e Zd Zdd Zdd ZdS )FileTransferTestRealmc                 C   s
   || _ d S r2   )testDir)r'   r&  r)   r)   r*   ri     rq   zFileTransferTestRealm.__init__c                 G   s   t | j}|d |dd fS )Nr   c                   S   r   r2   r)   r)   r)   r)   r*   <lambda>  s    z5FileTransferTestRealm.requestAvatar.<locals>.<lambda>)r   r&  )r'   avatarIDmindr   ar)   r)   r*   requestAvatar  s   
z#FileTransferTestRealm.requestAvatarN)r,   r-   r.   ri   r+  r)   r)   r)   r*   r%    s    r%  c                   @   s`   e Zd Z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S )SFTPTestProcessz
    Protocol for testing cftp. Provides an interface between Python (where all
    the tests are) and the cftp client process (which does the work that is
    being tested).
    c                 C   s$   |    || _d| _d| _d| _dS )zr
        @param onOutReceived: A L{Deferred} to be fired as soon as data is
        received from stdout.
        NF)clearBufferonOutReceivedonProcessEnd_expectingCommand_processEnded)r'   r.  r)   r)   r*   ri     s
   
zSFTPTestProcess.__init__c                 C   s   d| _ g | _d| _dS )zR
        Clear any buffered data received from stdout. Should be private.
        r   N)buffer_linesReceived_lineBufferr4   r)   r)   r*   r-    s   
zSFTPTestProcess.clearBufferc                 C   sr   t d|  | j| d}|d| _| j| | jdur,| jd}| _|| |  j	|7  _	| 
  dS )zO
        Called by Twisted when the cftp client prints data to stdout.
        zgot %r   
r   N)r   msgr4  r   rv   r3  r   r.  callbackr2  _checkForCommand)r'   r   linesr   r)   r)   r*   outReceived  s   

zSFTPTestProcess.outReceivedc                 C   sf   d}| j r/| j|kr1d| j}||r|t|d  }|   | j d }| _ || d S d S d S )Ns   cftp> r5  )r0  r4  r	  r3  
startswithr   r-  r7  )r'   promptbufr   r)   r)   r*   r8    s   
z SFTPTestProcess._checkForCommandc                 C   s   t d|  dS )zO
        Called by Twisted when the cftp client prints data to stderr.
        zerr: %sN)r   r6  )r'   r   r)   r)   r*   errReceived"  s   zSFTPTestProcess.errReceivedc                 C   s   | j S )zQ
        Return the contents of the buffer of data received from stdout.
        )r2  r4   r)   r)   r*   	getBuffer(  s   zSFTPTestProcess.getBufferc                 C   s<   t  | _|   t|tr|d}| j|d  | jS )a  
        Issue the given command via the cftp client. Return a C{Deferred} that
        fires when the server returns a result. Note that the C{Deferred} will
        callback even if the server returns some kind of error.

        @param command: A string containing an sftp command.

        @return: A C{Deferred} that fires when the sftp server returns a
        result. The payload is the server's response string.
        r   r5  )	r
   Deferredr0  r-  
isinstancestrencoder|   r   r'   commandr)   r)   r*   
runCommand.  s   


zSFTPTestProcess.runCommandc                    s(   t d fdd|D }t |S )ax  
        Run each command in sequence and return a Deferred that fires when all
        commands are completed.

        @param commands: A list of strings containing sftp commands.

        @return: A C{Deferred} that fires when all commands are completed. The
        payload is a list of response strings from the server, in the same
        order as the commands.
        rx   c                    s   g | ]	}  j|qS r)   )runrF  ).0rE  r'   semr)   r*   
<listcomp>L  s    z-SFTPTestProcess.runScript.<locals>.<listcomp>)r
   DeferredSemaphoregatherResults)r'   commandsdlr)   rI  r*   	runScript@  s   

zSFTPTestProcess.runScriptc                 C   s,   | j rtdS t | _| jd | jS )z
        Kill the process if it is still running.

        If the process is still running, sends a KILL signal to the transport
        and returns a C{Deferred} which fires when L{processEnded} is called.

        @return: a C{Deferred}.
        NKILL)r1  r
   r   r@  r/  r|   signalProcessr4   r)   r)   r*   killProcessO  s
   	

zSFTPTestProcess.killProcessc                 C   s,   d| _ | jr| jd}| _|d dS dS )zF
        Called by Twisted when the cftp client process ends.
        TN)r1  r/  r7  )r'   reasonr   r)   r)   r*   processEnded^  s
   zSFTPTestProcess.processEndedN)r,   r-   r.   r/   ri   r-  r:  r8  r>  r?  rF  rP  rS  rU  r)   r)   r)   r*   r,    s    
r,  c                   @   s4   e Zd Zdd Zdd Zdd Zdd Zd	d
 ZdS )CFTPClientTestBasec                 C   s   t dd}|tj W d    n1 sw   Y  t dd}|tj W d    n1 s1w   Y  tdd t dd}|dtj  W d    n1 sTw   Y  t	| S )Ndsa_test.pubr   dsa_testi  kh_tests
   127.0.0.1 )
r   r   r   publicDSA_opensshprivateDSA_opensshr8   chmodpublicRSA_opensshr   r@   r'   fr)   r)   r*   r@   i  s   
zCFTPClientTestBase.setUpc                 C   sF   t | j}t|}|t  t }||_tj	d|dd| _
d S )Nr   z	127.0.0.1)	interface)r%  r&  r	   PortalregisterCheckerr   conchTestPublicKeyCheckerConchTestServerFactoryr   	listenTCPserver)r'   realmpfacr)   r)   r*   startServers  s   

zCFTPClientTestBase.startServerc                 C   sH   t | jjds| d S d| jjj_t| jjjjj	}|
| j |S )Nprotorx   )hasattrrf  factory_cbStopServerrk  expectedLoseConnectionr
   maybeDeferredr|   loseConnectionr   r   r)   r)   r*   
stopServer{  s   
zCFTPClientTestBase.stopServerc                 C   s   t | jjS r2   )r
   rp  rf  stopListeningr'   ignoredr)   r)   r*   rn    s   z CFTPClientTestBase._cbStopServerc              	   C   s4   dD ]}zt | W q ty   Y qw t| S )N)rW  rX  rY  )r8   removeBaseExceptionr   tearDownr^  r)   r)   r*   rx    s   
zCFTPClientTestBase.tearDownN)r,   r-   r.   r@   rj  rr  rn  rx  r)   r)   r)   r*   rV  h  s    
rV  c                   @   s   e Zd Z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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S ).OurServerCmdLineClientTestsz
    Functional tests which launch a SFTP server over TCP on localhost and check
    cftp command line interface using a spawned process.

    Due to the spawned process you can not add a debugger breakpoint for the
    client code.
    c           
         s0  t      d} j j}tj||  dd}t	
dtj d|  t }t| _| fdd tj }tjtj|d< g }i }|D ]}t|trZ|d	}|| qN|D ]}|| }	t|trr|d	}t|	tr||	d	}	|	||< qbt	
| t	
| tj jtj||d
 |S )Nz-p %i -l testuser --known-hosts kh_test --user-authentications publickey --host-key-algorithms ssh-rsa -i dsa_test -a -v 127.0.0.1r   modrunning r   c                    
    j  S r2   )processProtocolr-  _r4   r)   r*   r'       
 z3OurServerCmdLineClientTests.setUp.<locals>.<lambda>
PYTHONPATHr   env)rV  r@   rj  rf  getHostportr   	_makeArgsr   r   r6  r   r   r
   r@  r,  r~  r   r8   r9   copypathsepr	  rr   rA  rB  rC  r   r   spawnProcess)
r'   cmdsr  r   r  encodedCmds
encodedEnvcmdvarvalr)   r4   r*   r@     s>   












z!OurServerCmdLineClientTests.setUpc                    s      }| fdd |S )Nc                    r}  r2   )r~  rS  r  r4   r)   r*   r'    r  z6OurServerCmdLineClientTests.tearDown.<locals>.<lambda>)rr  r   r   r)   r4   r*   rx    s   z$OurServerCmdLineClientTests.tearDownc                 C   s,   z
| j jd W d S  tjy   Y d S w )NrQ  )r~  r|   rR  r   ProcessExitedAlreadyrt  r)   r)   r*   _killProcess  s
   z(OurServerCmdLineClientTests._killProcessc                 C      | j |S )z
        Run the given command with the cftp client. Return a C{Deferred} that
        fires when the command is complete. Payload is the server's output for
        that command.
        )r~  rF  rD  r)   r)   r*   rF       z&OurServerCmdLineClientTests.runCommandc                 G   r  )z
        Run the given commands with the cftp client. Returns a C{Deferred}
        that fires when the commands are all complete. The C{Deferred}'s
        payload is a list of output for each command.
        )r~  rP  )r'   rN  r)   r)   r*   rP    r  z%OurServerCmdLineClientTests.runScriptc                 C   sL   | j }| ddddd}dd }|| || j|jt d|jg |S )z
        Test that 'pwd' reports the current remote directory, that 'lpwd'
        reports the current local directory, and that changing to a
        subdirectory then changing to its parent leaves you in the original
        remote directory.
        pwdlpwdzcd testDirectorycd ..c                 S   sD   g }| D ]}t |tr|d}|| q|dd |dd  S )zH
            Callback function for handling command output.
            r   N      )rA  bytesr   r   )r   r  r  r)   r)   r*   	cmdOutput  s   

z8OurServerCmdLineClientTests.testCdPwd.<locals>.cmdOutputr   )r&  rP  r   rL   rr   r8   getcwd)r'   homeDirr   r  r)   r)   r*   	testCdPwd  s   
z%OurServerCmdLineClientTests.testCdPwdc                    s&    fdd}  dddd}||S )z
        Check that 'ls -l' output includes the access permissions and that
        this output changes appropriately with 'chmod'.
        c                    sZ        | d d  | d d  | d d| d   | d d d S )Nr   s
   -rw-r--r--rx   r   r   s
   ----------r  )flushLoggedErrorsr%   r;  rL   resultsr4   r)   r*   _check  s
   z7OurServerCmdLineClientTests.testChAttrs.<locals>._checkzls -l testfile1zchmod 0 testfile1zchmod 644 testfile1rP  r   r'   r  r   r)   r4   r*   testChAttrs  s   
z'OurServerCmdLineClientTests.testChAttrsc                    s@    fdd}  dd j  ddd}|dd	  ||S )
z
        Check 'ls' works as expected. Checks for wildcards, hidden files,
        listing directories and listing empty directories.
        c                    sf     | d g d   | d g d   | d ddg   | d g d   | d	 d
g d S )Nr   s   testDirectory   testRemoveFile   testRenameFiles	   testfile1rx   r   r  r  r  )s   .testHiddenFiler  r  r  r   rL   r  r4   r)   r*   r    s   z4OurServerCmdLineClientTests.testList.<locals>._checkr   zls ../zls *Filezls -a *Filezls -l testDirectoryc                 S   s   dd | D S )Nc                 S   s   g | ]}| d qS )r5  )r   )rH  xr)   r)   r*   rK  *      zJOurServerCmdLineClientTests.testList.<locals>.<lambda>.<locals>.<listcomp>r)   )xsr)   r)   r*   r'  *  s    z6OurServerCmdLineClientTests.testList.<locals>.<lambda>)rP  r&  r
  r   r  r)   r4   r*   testList  s   
z$OurServerCmdLineClientTests.testListc                 C   sD   |  d}tdd }t|tr|d}|| j	| |S )zB
        Check that running the '?' command returns help.
        ?Nr   r   )
rF  r   r   cmd_HELPr   rA  rB  rC  r   rL   )r'   r   helpTextr)   r)   r*   testHelp-  s   


z$OurServerCmdLineClientTests.testHelpNc                 C   s   |  | | | dS )zg
        Assert that the files at C{name1} and C{name2} contain exactly the
        same data.
        N)rL   
getContent)r'   name1name2r6  r)   r)   r*   assertFilesEqual9  s   z,OurServerCmdLineClientTests.assertFilesEqualc                    sl   d jjjj t tr d  fdd}djj d}|| |fdd |S )	z
        Test that 'get' saves the remote file to the correct local location,
        that the output of 'get' is correct and that 'rm' actually removes
        the file.
        z)Transferred {}/testfile1 to {}/test file2r   c                    s8    |   jdjdd dS )N	testfile1
test file2z
get failedzrm "test file2")r%   endswithr  r&  childrF  r   r   r'   r)   r*   	_checkGetN  s   


z6OurServerCmdLineClientTests.testGet.<locals>._checkGetzget testfile1 "z/test file2"c                          jd S )Nr  assertFalser&  r  existsr  r4   r)   r*   r'  Z  r  z5OurServerCmdLineClientTests.testGet.<locals>.<lambda>)r#  r&  rr   rA  rB  rC  rF  r   )r'   r  r   r)   r  r*   testGet@  s   

	

z#OurServerCmdLineClientTests.testGetc                    s     fdd}  d}||S )zQ
        Test that 'get' works correctly when given wildcard parameters.
        c                    s8      jdtdd    jdtdd d S )NtestRemoveFiletestRemoveFile get failedtestRenameFiletestRenameFile get failed)r  r&  r  r   )ru  r4   r)   r*   r  c  s   

z;OurServerCmdLineClientTests.testWildcardGet.<locals>._checkz
get testR*)rF  r   r  r)   r4   r*   testWildcardGet^  s   

z+OurServerCmdLineClientTests.testWildcardGetc                    sh   dj  j d j  j d   fdd}dj j d}|| |fdd	 |S )
z
        Check that 'put' uploads files correctly and that they can be
        successfully removed. Also check the output of the put command.
        s   Transferred s   /testfile1 to s   /test"file2c                    s6    jdjd |   dS )Nr  
test"file2zrm "test\"file2")r  r&  r  r%   r  rF  r  r  r)   r*   	_checkPut  s
   
z6OurServerCmdLineClientTests.testPut.<locals>._checkPutput z/testfile1 "test\"file2"c                    r  )Nr  r  r  r4   r)   r*   r'    r  z5OurServerCmdLineClientTests.testPut.<locals>.<lambda>)r&  asBytesModerr   rF  r   )r'   r  r   r)   r  r*   testPutr  s"   



z#OurServerCmdLineClientTests.testPutc                    s    j djdd}|d W d   n1 sw   Y   j djdd}|d W d   n1 s9w   Y   fdd	} d
 j j d}|| |S )zb
        Check that 'put' uploads files correctly when overwriting a longer
        file.
        shorterFilewmode   aN
longerFile   bbc                    s       jd jd d S )Nr  r  )r  r&  r  r  r4   r)   r*   r    s   zEOurServerCmdLineClientTests.test_putOverLongerFile.<locals>._checkPutr  z/shorterFile longerFile)r&  r  r   r   rF  rr   r   r'   r_  r  r   r)   r4   r*   test_putOverLongerFile  s   
z2OurServerCmdLineClientTests.test_putOverLongerFilec                    s    j d  djdd}|d W d   n1 s#w   Y   j djdd}|d W d   n1 sBw   Y   fdd	} d
 j j d}|| |S )z
        Check that 'put' uploads files correctly when overwriting a longer
        file and you use a wildcard to specify the files to upload.
        dirr   r  r  r  Nr  c                    s     d jd d S )Nr   )r  r  r&  r  r'   someDirr)   r*   r    s   zMOurServerCmdLineClientTests.test_putMultipleOverLongerFile.<locals>._checkPutr  z/dir/*)r&  r  createDirectoryr   r   rF  rr   r   r  r)   r  r*   test_putMultipleOverLongerFile  s   
z:OurServerCmdLineClientTests.test_putMultipleOverLongerFilec                    s>    fdd}  dd jj dd j  }|| |S )z
        What happens if you issue a 'put' command and include a wildcard (i.e.
        '*') in parameter? Check that all files matching the wildcard are
        uploaded to the correct directory.
        c                    sh     | d d   | d d   jd j dd   jd j dd d S )Nr   r   r   r  r  r  r  )rL   r  r&  r  r  r  r4   r)   r*   check  s   

z:OurServerCmdLineClientTests.testWildcardPut.<locals>.checkr  r  z/testR*zcd %s)rP  r&  rr   r
  r   )r'   r  r   r)   r4   r*   testWildcardPut  s   
z+OurServerCmdLineClientTests.testWildcardPutc                    4    fdd}  dd}|| | jd |S )z
        Test that 'ln' creates a file which appears as a link in the output of
        'ls'. Check that removing the new file succeeds without output.
        c                    s8        | d d  | d dd  dS )Nr   r   rx      lzlink failedzrm testLink)r  rL   r%   r;  rF  r  r4   r)   r*   r    s   
z4OurServerCmdLineClientTests.testLink.<locals>._checkzln testLink testfile1zls -l testLinkr   rP  r   rL   r  r)   r4   r*   testLink  s
   
z$OurServerCmdLineClientTests.testLinkc                    r  )zV
        Test that we can create and remove directories with the cftp client.
        c                    s.     | d d  | d d  dS )Nr   r   rx      dzrmdir testMakeDirectory)rL   r%   r;  rF  r  r4   r)   r*   r    s   
z?OurServerCmdLineClientTests.testRemoteDirectory.<locals>._checkmkdir testMakeDirectoryzls -l testMakeDirector?r   r  r  r)   r4   r*   testRemoteDirectory  
   
z/OurServerCmdLineClientTests.testRemoteDirectoryc                    s&    fdd}  dd}|| |S )z
        Test that a C{mkdir} on an existing directory fails with the
        appropriate error, and doesn't log an useless error server side.
        c                    s$     | d d   | d d d S )Nr   r   rx   s   remote error 11: mkdir failedr  r  r4   r)   r*   r    s   zHOurServerCmdLineClientTests.test_existingRemoteDirectory.<locals>._checkr  r  r  r)   r4   r*   test_existingRemoteDirectory  s   
z8OurServerCmdLineClientTests.test_existingRemoteDirectoryc                    sH     d jj d}| jd | fdd | jd |S )z
        Test that we can create a directory locally and remove it with the
        cftp client. This test works because the 'remote' server is running
        out of a local directory.
        zlmkdir z/testLocalDirectoryr   c                    s
     dS )Nzrmdir testLocalDirectory)rF  r  r4   r)   r*   r'  
  r  z@OurServerCmdLineClientTests.testLocalDirectory.<locals>.<lambda>)rF  r&  rr   r   rL   r   r)   r4   r*   testLocalDirectory  s
   z.OurServerCmdLineClientTests.testLocalDirectoryc                    r  )z1
        Test that we can rename a file.
        c                    s*     | d d   | d d  dS )Nr   r   rx   s	   testfile2zrename testfile2 testfile1)rL   rF  r  r4   r)   r*   r    s   
z6OurServerCmdLineClientTests.testRename.<locals>._checkzrename testfile1 testfile2zls testfile?r   r  r  r)   r4   r*   
testRename  r  z&OurServerCmdLineClientTests.testRenamer2   )r,   r-   r.   r/   r@   rx  r  rF  rP  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r)   r)   r)   r*   ry    s.    *
ry  c                   @   s@   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dS )OurServerBatchFileTestszm
    Functional tests which launch a SFTP server over localhost and checks csftp
    in batch interface.
    c                 C   s   t |  |   d S r2   rV  r@   rj  r4   r)   r)   r*   r@   %  s   
zOurServerBatchFileTests.setUpc                 C      t |  |  S r2   )rV  rx  rr  r4   r)   r)   r*   rx  )     
z OurServerBatchFileTests.tearDownc                    s   |    t d}|| W d    n1 sw   Y  | j j}d| f }tj| dddd  }t	
dtj d|  tj }tjtj|d< d| jj_ttj||d	} fd
d}|dd  || |S )Nr  z-p %i -l testuser --known-hosts kh_test --user-authentications publickey --host-key-algorithms ssh-rsa -i dsa_test -a -v -b %s 127.0.0.1r   rz  rx   r|  r   r  r  c                    s   t   | S r2   )r8   rv  resfnr)   r*   _cleanupD  s   
z9OurServerBatchFileTests._getBatchOutput.<locals>._cleanupc                 S   s   | d S )Nr   r)   r  r)   r)   r*   r'  H  s    z9OurServerBatchFileTests._getBatchOutput.<locals>.<lambda>)r   r   r   rf  r  r  r   r  r   r   r6  r   r   r8   r9   r  r  r	  rr   rm  ro  r   r   addBoth)r'   r_  fpr  r  r  r   r  r)   r  r*   _getBatchOutput-  s$   	


z'OurServerBatchFileTests._getBatchOutputc                    (   d} fdd}  |}|| |S )z
        Test whether batch file function of cftp ('cftp -b batchfile').
        This works by treating the file as a list of commands to be run.
        zpwd
ls
exit
c                    sP   |  d} tdt|     j j| d   | dd g d d S )Nr5  zRES %srx   r  r  )	r   r   r6  reprassertInr&  r  rr   rL   r  r4   r)   r*   _cbCheckResultW  s   

z=OurServerBatchFileTests.testBatchFile.<locals>._cbCheckResultr  r   r'   r  r  r   r)   r4   r*   testBatchFileM  s
   
	
z%OurServerBatchFileTests.testBatchFilec                    r  )zO
        Test that an error in the batch file stops running the batch.
        zchown 0 missingFile
pwd
exit
c                          j j|  d S r2   )assertNotInr&  r  rr   r  r4   r)   r*   r  m     z9OurServerBatchFileTests.testError.<locals>._cbCheckResultr  r  r)   r4   r*   	testErrord  s
   

z!OurServerBatchFileTests.testErrorc                    r  )z_
        Test that a minus sign '-' at the front of a line ignores
        any errors.
        z-chown 0 missingFile
pwd
exit
c                    r  r2   )r  r&  r  rr   r  r4   r)   r*   r  ~  r  z@OurServerBatchFileTests.testIgnoredError.<locals>._cbCheckResultr  r  r)   r4   r*   testIgnoredErrort  s
   

z(OurServerBatchFileTests.testIgnoredErrorN)
r,   r-   r.   r/   r@   rx  r  r  r  r  r)   r)   r)   r*   r    s     r  sftpz%no sftp command-line client availablec                   @   rm   )	OurServerSftpClientTestsz@
    Test the sftp server against sftp command line client.
    c                 C   r  r2   r  r4   r)   r)   r*   r@     r  zOurServerSftpClientTests.setUpc                 C   s   |   S r2   )rr  r4   r)   r)   r*   rx    s   z!OurServerSftpClientTests.tearDownc                    s      t d}|d W d   n1 sw   Y  j jtjfdd}td| djj	_
tdd	} fd
d}fdd}|| |dd  ||S )a  
        Test the return of extended attributes by the server: the sftp client
        should ignore them, but still be able to parse the response correctly.

        This test is mainly here to check that
        L{filetransfer.FILEXFER_ATTR_EXTENDED} has the correct value.
        r  z	ls .
exitNc                    s    | |}d|d< |S )Nr   ext_foor)   )r'   sr   )
oldGetAttrr)   r*   	_getAttrs  s   
zCOurServerSftpClientTests.test_extendedAttributes.<locals>._getAttrsr  Tssh)-oPubkeyAcceptedKeyTypes=ssh-dssz-Vc                    s>   | dkrd}nd}|dddddddd	dd
f d df7 }|S )Nr   )r  r  r)   z-Fz	/dev/nullr  zIdentityFile=dsa_testzUserKnownHostsFile=kh_testzHostKeyAlgorithms=ssh-rsazPort=%iz-bztestuser@127.0.0.1r)   )statusargs)r  r  r)   r*   hasPAKT  s&   zAOurServerSftpClientTests.test_extendedAttributes.<locals>.hasPAKTc                    s.     | d d dD ]
} || d  q
d S )Nr   r   r  )rL   r  )r   ir4   r)   r*   r    s   z?OurServerSftpClientTests.test_extendedAttributes.<locals>.checkc                 S   s
   t d| S )Nr   )r   )r
  r)   r)   r*   r'    r  zBOurServerSftpClientTests.test_extendedAttributes.<locals>.<lambda>)r   r   r   rf  r  r  r!   r  r<   rm  ro  r   r   )r'   r_  r  r   r  r  r)   )r  r  r  r'   r*   test_extendedAttributes  s   




z0OurServerSftpClientTests.test_extendedAttributesN)r,   r-   r.   r/   r@   rx  r  r)   r)   r)   r*   r    s
    r  )Pr/   r   rZ   r>   r8   r   r   r6   ior   unittestr   zope.interfacer   twisted.conchr   twisted.conch.interfacesr   $twisted.conch.test.test_filetransferr   r   twisted.credr	   twisted.internetr
   r   r   r   r   twisted.internet.taskr   twisted.internet.utilsr   r   twisted.pythonr   twisted.python.fakepwdr   twisted.python.filepathr   twisted.python.procutilsr   twisted.python.reflectr   twisted.test.proto_helpersr   twisted.trial.unittestr   r   r   unixtwisted.conch.scriptsr   twisted.conch.scripts.cftpr   twisted.conch.sshr   twisted.conch.testr   r   twisted.conch.test.test_conchr    r!   ImportError	skipTestsIReactorProcessr"   r0   re   rn   rw   r   r   r%  ProcessProtocolr,  rV  ry  r  r  r)   r)   r)   r*   <module>   s    #&2  u	{'   g