
    3~hyM                         d Z ddl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  G d d      Z G d	 d
e      Z G d de      Z G d d      Z G d d      Z edd       G d d             Zy)au  
This module contains helpers/fixtures to assist in testing Fabric-driven code.

It is not intended for production use, and pulls in some test-oriented
dependencies as needed. You can install an 'extra' variant of Fabric to get
these dependencies if you aren't already using them for your own testing
purposes: ``pip install fabric[testing]``.

.. note::
    If you're using pytest for your test suite, you may be interested in
    grabbing ``fabric[pytest]`` instead, which encompasses the dependencies of
    both this module and the `fabric.testing.fixtures` module, which contains
    pytest fixtures.

.. versionadded:: 2.1
    N)chainrepeat)BytesIO)MockPropertyMockcallpatchANY)
deprecatedc                   $    e Zd ZdZddZd Zd Zy)Commanda  
    Data record specifying params of a command execution to mock/expect.

    :param str cmd:
        Command string to expect. If not given, no expectations about the
        command executed will be set up. Default: ``None``.

    :param bytes out: Data yielded as remote stdout. Default: ``b""``.

    :param bytes err: Data yielded as remote stderr. Default: ``b""``.

    :param int exit: Remote exit code. Default: ``0``.

    :param int waits:
        Number of calls to the channel's ``exit_status_ready`` that should
        return ``False`` before it then returns ``True``. Default: ``0``
        (``exit_status_ready`` will return ``True`` immediately).

    .. versionadded:: 2.1
    Nc                 X    || _         || _        || _        || _        || _        || _        y N)cmdouterrin_exitwaits)selfr   r   r   r   r   r   s          \/var/www/peopleoo.sandbox-dev.co.uk/venv/lib/python3.12/site-packages/fabric/testing/base.py__init__zCommand.__init__5   s,    	
    c                 b    dj                  | j                  j                  | j                        S )Nz<{} cmd={!r}>)format	__class____name__r   r   s    r   __repr__zCommand.__repr__=   s%     %%dnn&=&=txxHHr   c                 ^    |j                   j                  | j                  xs t               y)zj
        Assert that the ``channel`` was used to run this command.

        .. versionadded:: 2.7
        N)exec_commandassert_called_withr   r
   r   channels     r   expect_executionzCommand.expect_executionB   s      	//C@r   )Nr   r   Nr   r   )r   
__module____qualname____doc__r   r   r%    r   r   r   r      s    *I
Ar   r   c                       e Zd ZdZd Zy)ShellCommandzg
    A pseudo-command that expects an interactive shell to be executed.

    .. versionadded:: 2.7
    c                 8    |j                   j                          y r   )invoke_shellassert_called_once_withr#   s     r   r%   zShellCommand.expect_executionR   s    446r   N)r   r&   r'   r(   r%   r)   r   r   r+   r+   K   s    7r   r+   c                   :     e Zd ZdZ fdZd Zd Zd Zd Z xZ	S )MockChannelz
    Mock subclass that tracks state for its ``recv(_stderr)?`` methods.

    Turns out abusing function closures inside MockRemote to track this state
    only worked for 1 command per session!

    .. versionadded:: 2.1
    c                     t         j                  | d|j                  d             t         j                  | d|j                  d             t         j                  | dt                      t	        |   |i | y )N__stdoutstdout__stderrstderr_stdin)object__setattr__popr   superr   )r   argskwargsr   s      r   r   zMockChannel.__init__`   sa     	4VZZ-AB4VZZ-AB4795$)&)r   c                     t        di |S )Nr)   )r   )r   r<   s     r   _get_child_mockzMockChannel._get_child_mocki   s    ~f~r   c                 L    t         j                  | d      j                  |      S )Nr2   r7   __getattribute__readr   counts     r   recvzMockChannel.recvm        &&tZ8==eDDr   c                 L    t         j                  | d      j                  |      S )Nr4   r@   rC   s     r   recv_stderrzMockChannel.recv_stderrp   rF   r   c                 L    t         j                  | d      j                  |      S )Nr6   )r7   rA   write)r   datas     r   sendallzMockChannel.sendalls   s     &&tX6<<TBBr   )
r   r&   r'   r(   r   r>   rE   rH   rL   __classcell__)r   s   @r   r0   r0   V   s$    *EECr   r0   c                   h    e Zd ZdZ	 	 	 	 	 	 	 	 	 	 	 	 ddZd Zd Z edd      d	        Zd
 Z	d Z
y)Sessionak  
    A mock remote session of a single connection and 1 or more command execs.

    Allows quick configuration of expected remote state, and also helps
    generate the necessary test mocks used by `MockRemote` itself. Only useful
    when handed into `MockRemote`.

    The parameters ``cmd``, ``out``, ``err``, ``exit`` and ``waits`` are all
    shorthand for the same constructor arguments for a single anonymous
    `.Command`; see `.Command` for details.

    To give fully explicit `.Command` objects, use the ``commands`` parameter.

    :param str user:
    :param str host:
    :param int port:
        Sets up expectations that a connection will be generated to the given
        user, host and/or port. If ``None`` (default), no expectations are
        generated / any value is accepted.

    :param commands:
        Iterable of `.Command` objects, used when mocking nontrivial sessions
        involving >1 command execution per host. Default: ``None``.

        .. note::
            Giving ``cmd``, ``out`` etc alongside explicit ``commands`` is not
            allowed and will result in an error.

    :param bool enable_sftp: Whether to enable basic SFTP mocking support.

    :param transfers:
        None if no transfers to expect; otherwise, should be a list of dicts of
        the form ``{"method": "get|put", **kwargs}`` where ``**kwargs`` are the
        kwargs expected in the relevant `~paramiko.sftp_client.SFTPClient`
        method. (eg: ``{"method": "put", "localpath": "/some/path"}``)

    .. versionadded:: 2.1
    .. versionchanged:: 3.2
        Added the ``enable_sftp`` and ``transfers`` parameters.
    Nc                 p   |xs |xs
 |xs |	xs |
}|r|rt        d      |xs |xs | | _        || _        || _        || _        || _        |r=i }|||d<   |||d<   |||d<   |||d<   |	|	|d<   |
|
|d<   t        di |g| _        | j
                  st               g| _        || _        || _        y )	NzAYou can't give both 'commands' and individual Command parameters!r   r   r   r   r   r   r)   )	
ValueError
guard_onlyhostuserportcommandsr   _enable_sftp	transfers)r   rS   rT   rU   rV   r   r   r   r   r   r   enable_sftprX   paramsr<   s                  r   r   zSession.__init__   s      33s3d3e& 
  (;3;)<			  F #u #u #u #u!%v "'w$.v./DM}}$YKDM'"r   c                 ^   t               }|j                  j                  }t        d      }t	        |      t        |      _        g }| j                  D ]  }t        t        |j                        t        |j                              }|j                  |j                  _        t        t        d|j                        t        d            }||j                   _        |j%                  |        ||j&                  _        | j(                  r| j+                  |       || _        || _        y)a  
        Mocks `~paramiko.client.SSHClient` and `~paramiko.channel.Channel`.

        Specifically, the client will expect itself to be connected to
        ``self.host`` (if given), the channels will be associated with the
        client's `~paramiko.transport.Transport`, and the channels will
        expect/provide command-execution behavior as specified on the
        `.Command` objects supplied to this `.Session`.

        The client is then attached as ``self.client`` and the channels as
        ``self.channels``.

        :returns:
            ``None`` - this is mostly a "deferred setup" method and callers
            will just reference the above attributes (and call more methods) as
            needed.

        .. versionadded:: 2.1
        T)side_effect)r3   r5   FN)r   get_transportreturn_valuer   r   typeactiverV   r0   r   r   r   r   recv_exit_statusr   r   exit_status_readyr\   appendopen_sessionrW   _start_sftpclientchannels)r   rf   	transportactivesrg   commandr$   readiess           r   generate_mockszSession.generate_mocks   s    ( ((55	 , ".'!BY}} 	%G "w{{+GGKK4HG 5<LLG$$1 F5'--8&,GG4;G%%1OOG$	%" .6	* V$ r   c                 R   t        d      | _        | j                  j                         }t        d      | _        | j                  j                          |j                  j
                  x| _        }d }||j                  j                  _	        d|j                  _        d}||j                  j
                  _        ||j                  j
                  _        t        j                  |_        dD ]5  }t        t        j                  |      t        |j                  |      _	        7 y )Nfabric.transfer.osfabric.transfer.Pathc                 ^    dj                  t        j                  j                  |             S Nz	/local/{}r   ospathnormpathrt   s    r   fake_abspathz)Session._start_sftp.<locals>.fake_abspath  $     %%bgg&6&6t&<==r   /remote  basenamesplitjoinru   )r	   
os_patcherstartpath_patcher	open_sftpr^   sftprt   abspathr\   getcwdstatst_moders   sepgetattr)r   rf   mock_osr   rw   	fake_modenames          r   re   zSession._start_sftp  s     45//'')!"89!!++888	D	>
 ,8(#,  	)2		&,5!!) ff= 	MD6=bggt6LGGLL$'3	Mr   3.2zGThis method has been renamed to `safety_check` & will be removed in 4.0versionreasonc                 "    | j                         S r   )safety_checkr   s    r   sanity_checkzSession.sanity_check-  s    
   ""r   c                 &   | j                   ry | j                  j                  }|j                          | j                  j                  j                  | j
                  xs t        | j                  xs t        | j                  xs t               g }t        | j                  | j                        D ]f  \  }}|j                  t                      |j                  |       |j                  s>|j                   j#                         |j                  k(  rfJ  |j$                  j&                  j(                  }||k(  sJ | j*                  xs g D ];  }|j-                  d      }t/        | j0                  |      } |j2                  di | = y )N)usernamehostnamerU   )r$   methodr)   )rR   rf   r]   r.   connectrT   r
   rS   rU   ziprg   rV   rc   r   r%   r   r6   getvaluer^   rd   call_args_listrX   r9   r   r   assert_any_call)	r   rh   session_opensr$   rj   callstransfermethod_namer   s	            r   r   zSession.safety_check4  sQ    ?? KK--	))+33YY%#YY%#!c 	4 	
  #DMM4== A 	@GW  ($$W$5{{~~..0GKK???	@ &&33BB%%% ," 	/H",,x0KTYY4F"F"".X.	/r   c                     t        | d      r| j                  j                          t        | d      r| j                  j                          yy)zU
        Stop any internal per-session mocks.

        .. versionadded:: 3.2
        r   r   N)hasattrr   stopr   r   s    r   r   zSession.stop\  s?     4&OO  "4(""$ )r   )NNNNNNNNNNFN)r   r&   r'   r(   r   rl   re   deprecated_no_docstringr   r   r   r)   r   r   rO   rO   w   sj    'V 1#f;!zM8 X#	#&/P	%r   rO   c                   b    e Zd ZdZddZd Zd Zd Zd Z e	dd	      d
        Z
d Zd Zd Zy)
MockRemoteaW  
    Class representing mocked remote SSH/SFTP state.

    It supports stop/start style patching (useful for doctests) but then wraps
    that in a more convenient/common contextmanager pattern (useful in most
    other situations). The latter is also leveraged by the
    `fabric.testing.fixtures` module, recommended if you're using pytest.

    Note that the `expect` and `expect_sessions` methods automatically call
    `start`, so you won't normally need to do so by hand.

    By default, a single anonymous/internal `Session` is created, for
    convenience (eg mocking out SSH functionality as a safety measure). Users
    requiring detailed remote session expectations can call methods like
    `expect` or `expect_sessions`, which wipe that anonymous Session & set up a
    new one instead.

    .. versionadded:: 2.1
    .. versionchanged:: 3.2
        Added the ``enable_sftp`` init kwarg to enable mocking both SSH and
        SFTP at the same time.
    .. versionchanged:: 3.2
        Added contextmanager semantics to the class, so you don't have to
        remember to call `safety`/`stop`.
    c                 H    || _         | j                  t        |             y )N)rY   )rW   expect_sessionsrO   )r   rY   s     r   r   zMockRemote.__init__  s    'W=>r   c                 t    |j                  d| j                         | j                  t        |i |      d   S )z
        Convenience method for creating & 'expect'ing a single `Session`.

        Returns the single `MockChannel` yielded by that Session.

        .. versionadded:: 2.1
        rY   r   )
setdefaultrW   r   rO   )r   r;   r<   s      r   expectzMockRemote.expect  s:     	-):):;##GT$<V$<=a@@r   c                 P    | j                          || _        | j                         S )z
        Sets the mocked remote environment to expect the given ``sessions``.

        Returns a list of `MockChannel` objects, one per input `Session`.

        .. versionadded:: 2.1
        )r   sessionsr   )r   r   s     r   r   zMockRemote.expect_sessions  s      			 zz|r   c                 2   t        d      x| _        }|j                         }g }| j                  D ]-  }|j	                          |j                  |j                         / ||_        t        t        j                  d | j                  D                    }|S )zw
        Start patching SSHClient with the stored sessions, returning channels.

        .. versionadded:: 2.1
        fabric.connection.SSHClientc              3   4   K   | ]  }|j                     y wr   )rg   ).0xs     r   	<genexpr>z#MockRemote.start.<locals>.<genexpr>  s     +N1AJJ+Ns   )r	   patcherr   r   rl   rc   rf   r\   listr   from_iterable)r   r   	SSHClientclientssessionr   s         r   r   zMockRemote.start  s     "''D!EEwMMO	}} 	+G""$NN7>>*	+ !(	+++N+NNO r   c                     t        | d      sy| j                  j                          | j                  D ]  }|j                           y)zI
        Stop patching SSHClient.

        .. versionadded:: 2.1
        r   N)r   r   r   r   r   r   s     r   r   zMockRemote.stop  s=     tY'}} 	GLLN	r   r   zAThis method has been renamed to `safety` & will be removed in 4.0r   c                 "    | j                         S )zq
        Run post-execution sanity checks (usually 'was X called' tests.)

        .. versionadded:: 2.1
        )safetyr   s    r   sanityzMockRemote.sanity  s     {{}r   c                 F    | j                   D ]  }|j                           y)zx
        Run post-execution safety checks (eg ensuring expected calls happened).

        .. versionadded:: 3.2
        N)r   r   r   s     r   r   zMockRemote.safety  s#     }} 	#G  "	#r   c                     | S r   r)   r   s    r   	__enter__zMockRemote.__enter__  s    r   c                 p    	 | j                          | j                          y # | j                          w xY wr   )r   r   )r   excs     r   __exit__zMockRemote.__exit__  s#    	KKMIIKDIIKs   # 5N)F)r   r&   r'   r(   r   r   r   r   r   r   r   r   r   r   r)   r   r   r   r   h  sO    6?	A$0 R	#r   r   r   zhThis class has been merged with `MockRemote` which can now handle SFTP mocking too. Please switch to it!r   c                   $    e Zd ZdZddZd Zd Zy)MockSFTPz
    Class managing mocked SFTP remote state.

    Used in start/stop fashion in eg doctests; wrapped in the SFTP fixtures in
    conftest.py for main use.

    .. versionadded:: 2.1
    c                 *    |r| j                          y y r   )r   )r   	autostarts     r   r   zMockSFTP.__init__  s    JJL r   c                    t        d      | _        t        d      | _        t        d      | _        | j                  j	                         }| j                  j	                         }| j                  j	                          |j
                  j                  j
                  }d }||j                  j                  _	        d|j                  _        d}||j                  j
                  _        ||j                  j
                  _        t        j                  |_        dD ]5  }t        t        j                  |      t        |j                  |      _	        7 ||fS )Nrn   r   ro   c                 ^    dj                  t        j                  j                  |             S rq   rr   rv   s    r   rw   z$MockSFTP.start.<locals>.fake_abspath  rx   r   ry   rz   r{   )r	   r   client_patcherr   r   r^   r   rt   r   r\   r   r   r   rs   r   r   )r   r   Clientr   rw   r   r   s          r   r   zMockSFTP.start  s    45#$AB!"89//'')$$**,!"",,99	>
 ,8(#,  	)2		&,5!!) ff= 	MD6=bggt6LGGLL$'3	M W}r   c                     | j                   j                          | j                  j                          | j                  j                          y r   )r   r   r   r   r   s    r   r   zMockSFTP.stop  s6      " r   N)T)r   r&   r'   r(   r   r   r   r)   r   r   r   r     s    
>!r   r   )r(   rs   	itertoolsr   r   ior   unittest.mockr   r   r   r	   r
   deprecated.sphinxr   deprecated.classicr   r   r+   r0   rO   r   r   r)   r   r   <module>r      s   " 
 #  > > ( D)A )AX77 7C$ CBn% n%b@ @F u0! 0!	0!r   