File: test_paramiko.py

package info (click to toggle)
proxmoxer 2.2.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 404 kB
  • sloc: python: 3,107; sh: 12; makefile: 3
file content (156 lines) | stat: -rw-r--r-- 5,195 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
__author__ = "John Hollowell"
__copyright__ = "(c) John Hollowell 2022"
__license__ = "MIT"

import os.path
import tempfile
from unittest import mock

import pytest

from proxmoxer.backends import ssh_paramiko

# pylint: disable=no-self-use


class TestParamikoBackend:
    def test_init(self, mock_connect):
        back = ssh_paramiko.Backend("host", "user")

        assert isinstance(back.session, ssh_paramiko.SshParamikoSession)
        assert back.session.host == "host"
        assert back.session.user == "user"
        assert back.target == "host"


class TestSshParamikoSession:
    def test_init_all_args(self, mock_connect):
        sess = ssh_paramiko.SshParamikoSession(
            "host", "user", password="password", private_key_file="/tmp/key_file", port=1234
        )

        assert sess.host == "host"
        assert sess.user == "user"
        assert sess.password == "password"
        assert sess.private_key_file == "/tmp/key_file"
        assert sess.port == 1234
        assert sess.ssh_client == mock_connect()

    def test_connect_basic(self, mock_ssh_client):
        import paramiko

        sess = ssh_paramiko.SshParamikoSession("host", "user", password="password", port=1234)

        sess.ssh_client.connect.assert_called_once_with(
            "host",
            username="user",
            allow_agent=False,
            look_for_keys=True,
            key_filename=None,
            password="password",
            timeout=5,
            port=1234,
        )
        policy_call_args, _ = sess.ssh_client.set_missing_host_key_policy.call_args_list[0]
        assert isinstance(policy_call_args[0], paramiko.AutoAddPolicy)

    def test_connect_key_file(self, mock_ssh_client):
        import paramiko

        sess = ssh_paramiko.SshParamikoSession(
            "host", "user", password="password", private_key_file="/tmp/key_file", port=1234
        )

        sess.ssh_client.connect.assert_called_once_with(
            "host",
            username="user",
            allow_agent=False,
            look_for_keys=True,
            key_filename="/tmp/key_file",
            password="password",
            timeout=5,
            port=1234,
        )
        policy_call_args, _ = sess.ssh_client.set_missing_host_key_policy.call_args_list[0]
        assert isinstance(policy_call_args[0], paramiko.AutoAddPolicy)

    def test_connect_key_file_user(self, mock_ssh_client):
        import paramiko

        sess = ssh_paramiko.SshParamikoSession(
            "host", "user", password="password", private_key_file="~/key_file", port=1234
        )

        sess.ssh_client.connect.assert_called_once_with(
            "host",
            username="user",
            allow_agent=False,
            look_for_keys=True,
            key_filename=os.path.expanduser("~") + "/key_file",
            password="password",
            timeout=5,
            port=1234,
        )
        policy_call_args, _ = sess.ssh_client.set_missing_host_key_policy.call_args_list[0]
        assert isinstance(policy_call_args[0], paramiko.AutoAddPolicy)

    def test_exec(self, mock_ssh_client):
        mock_client, mock_session, _ = mock_ssh_client

        sess = ssh_paramiko.SshParamikoSession("host", "user")
        sess.ssh_client = mock_client

        stdout, stderr = sess._exec(["echo", "hello", "world"])

        assert stdout == "stdout contents"
        assert stderr == "stderr contents"
        mock_session.exec_command.assert_called_once_with("echo hello world")

    def test_upload_file_obj(self, mock_ssh_client):
        mock_client, _, mock_sftp = mock_ssh_client

        sess = ssh_paramiko.SshParamikoSession("host", "user")
        sess.ssh_client = mock_client

        with tempfile.NamedTemporaryFile("r") as f_obj:
            sess.upload_file_obj(f_obj, "/tmp/file")

            mock_sftp.putfo.assert_called_once_with(f_obj, "/tmp/file")

        mock_sftp.close.assert_called_once_with()


@pytest.fixture
def mock_connect():
    m = mock.Mock(spec=ssh_paramiko.SshParamikoSession._connect)
    with mock.patch(
        "proxmoxer.backends.ssh_paramiko.SshParamikoSession._connect",
        m,
    ):
        yield m


@pytest.fixture
def mock_ssh_client():
    # pylint: disable=import-outside-toplevel
    from paramiko import SFTPClient, SSHClient, Transport, channel

    mock_client = mock.Mock(spec=SSHClient)
    mock_transport = mock.Mock(spec=Transport)
    mock_channel = mock.Mock(spec=channel.Channel)
    mock_sftp = mock.Mock(spec=SFTPClient)

    # mock the return streams from the SSH connection
    mock_stdout = mock.Mock(spec=channel.ChannelFile)
    mock_stderr = mock.Mock(spec=channel.ChannelStderrFile)
    mock_stdout.read.return_value = b"stdout contents"
    mock_stderr.read.return_value = b"stderr contents"
    mock_channel.makefile.return_value = mock_stdout
    mock_channel.makefile_stderr.return_value = mock_stderr

    mock_transport.open_session.return_value = mock_channel
    mock_client.get_transport.return_value = mock_transport
    mock_client.open_sftp.return_value = mock_sftp

    with mock.patch("paramiko.SSHClient", mock_client):
        yield (mock_client, mock_channel, mock_sftp)