Skip to content

Commit 1349783

Browse files
committed
test for setting log level
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
1 parent 9111bff commit 1349783

2 files changed

Lines changed: 167 additions & 0 deletions

File tree

tests/conftest.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,23 @@
1616
from pylibsshext.logging import ANSIBLE_PYLIBSSH_TRACE
1717
from pylibsshext.session import Session
1818

19+
from pylibsshext import __libssh_version__
20+
1921

2022
_DIR_PRIV_RW_OWNER = 0o700
2123
_FILE_PRIV_RW_OWNER = 0o600
2224

2325

26+
@pytest.fixture
27+
def libssh_version_tuple():
28+
"""
29+
Get the libssh version as a tuple of (major, minor, patch).
30+
31+
This is useful for simple comparison and conditioning tests based on this value.
32+
"""
33+
return tuple(map(int, (__libssh_version__.split('.'))))
34+
35+
2436
@pytest.fixture
2537
def free_port_num():
2638
"""Detect a free port number using a temporary ephemeral port.

tests/integration/logging_test.py

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
"""Tests suite for logging."""
2+
3+
import contextlib as _ctx
4+
import logging
5+
6+
import pytest
7+
8+
from pylibsshext.errors import LibsshSessionException
9+
from pylibsshext.logging import ANSIBLE_PYLIBSSH_NOLOG, ANSIBLE_PYLIBSSH_TRACE
10+
from pylibsshext.session import Session
11+
12+
13+
LOCALHOST = '127.0.0.1'
14+
BAD_LOG_LEVEL = 99
15+
16+
17+
@pytest.fixture(autouse=True)
18+
def _only_capture_project_logs(caplog: pytest.LogCaptureFixture) -> None:
19+
"""Hide unrelated log entries from capture."""
20+
caplog.set_level(ANSIBLE_PYLIBSSH_NOLOG + 1) # root logger
21+
caplog.set_level(
22+
logging.NOTSET,
23+
logger='ansible-pylibssh',
24+
) # don't block things early
25+
caplog.clear()
26+
27+
28+
def test_session_log_level_warning(
29+
caplog: pytest.LogCaptureFixture,
30+
free_port_num: int,
31+
libssh_version_tuple,
32+
) -> None:
33+
"""
34+
Test setting the log level to WARNING.
35+
36+
It should show "Connection refused" on libssh 0.11.0 and newer.
37+
But no debug/ainfo/trace messages.
38+
"""
39+
ssh_session = Session()
40+
# keeping these in sync makes sure the log levels are not "lost"
41+
# in the processing. Technically, setting the log level in libssh
42+
# is not needed as the default is logging everything but filtering
43+
# is done on the python side
44+
ssh_session.set_log_level(logging.WARNING)
45+
caplog.set_level(logging.WARNING)
46+
47+
# the connection will fail but first log lands before that
48+
with _ctx.suppress(LibsshSessionException):
49+
ssh_session.connect(host=LOCALHOST, port=free_port_num)
50+
51+
log_records = caplog.records
52+
53+
# This message is available only in libssh 0.11.0 and newer
54+
expected_substring = 'ssh_client_connection_callback: Connection refused'
55+
if libssh_version_tuple >= (0, 11, 0):
56+
assert any(
57+
record.levelname == 'WARNING' and expected_substring in record.msg
58+
for record in log_records
59+
)
60+
61+
# No INFO and higher log messages should show up at this log level
62+
assert all(record.levelname != 'INFO' for record in log_records)
63+
assert all(record.levelname != 'DEBUG' for record in log_records)
64+
assert all(record.levelname != 'TRACE' for record in log_records)
65+
66+
67+
def test_session_log_level_debug(
68+
caplog: pytest.LogCaptureFixture,
69+
free_port_num: int,
70+
) -> None:
71+
"""
72+
Test setting the log level to DEBUG.
73+
74+
It should reveal copyright information. But no trace messages.
75+
"""
76+
ssh_session = Session()
77+
ssh_session.set_log_level(logging.DEBUG)
78+
caplog.set_level(logging.DEBUG)
79+
80+
# the connection will fail but first log lands before that
81+
with _ctx.suppress(LibsshSessionException):
82+
ssh_session.connect(host=LOCALHOST, port=free_port_num)
83+
84+
log_records = caplog.records
85+
86+
expected_copyright_substring = 'and libssh contributors.'
87+
# This log message is shown at different log levels
88+
# in different libssh versions. Changed at 657d9143d1 (before 0.11.0)
89+
# but backported to some RHEL9 versions so matching on the libssh version
90+
# is not reliable.
91+
assert any(
92+
record.levelname in {'DEBUG', 'INFO'}
93+
and expected_copyright_substring in record.msg
94+
for record in log_records
95+
)
96+
97+
# No TRACE log messages should show up at this log level
98+
assert all(record.levelname != 'TRACE' for record in log_records)
99+
100+
101+
def test_session_log_level_no_log(
102+
caplog: pytest.LogCaptureFixture,
103+
free_port_num: int,
104+
) -> None:
105+
"""Test setting the log level to NOLOG should be quiet."""
106+
ssh_session = Session()
107+
ssh_session.set_log_level(ANSIBLE_PYLIBSSH_NOLOG)
108+
caplog.set_level(ANSIBLE_PYLIBSSH_NOLOG)
109+
110+
# the connection will fail but first log lands before that
111+
with _ctx.suppress(LibsshSessionException):
112+
ssh_session.connect(host=LOCALHOST, port=free_port_num)
113+
114+
assert not caplog.records
115+
116+
117+
def test_session_log_level_trace(
118+
caplog: pytest.LogCaptureFixture,
119+
free_port_num: int,
120+
) -> None:
121+
"""Test setting the log level to TRACE should provide all of the logs."""
122+
ssh_session = Session()
123+
ssh_session.set_log_level(ANSIBLE_PYLIBSSH_TRACE)
124+
caplog.set_level(ANSIBLE_PYLIBSSH_TRACE)
125+
126+
with _ctx.suppress(LibsshSessionException):
127+
ssh_session.connect(host=LOCALHOST, port=free_port_num)
128+
129+
expected_poll_message = 'ssh_socket_pollcallback: Poll callback on socket'
130+
assert expected_poll_message in caplog.text
131+
132+
133+
def test_session_log_level_not_set(
134+
caplog: pytest.LogCaptureFixture,
135+
free_port_num: int,
136+
) -> None:
137+
"""Test setting the log level to NOTSET = all messages should be logged too."""
138+
ssh_session = Session()
139+
ssh_session.set_log_level(logging.NOTSET)
140+
caplog.set_level(logging.NOTSET)
141+
142+
with _ctx.suppress(LibsshSessionException):
143+
ssh_session.connect(host=LOCALHOST, port=free_port_num)
144+
145+
expected_poll_message = 'ssh_socket_pollcallback: Poll callback on socket'
146+
assert expected_poll_message in caplog.text
147+
148+
149+
def test_session_log_level_bad():
150+
"""Test that setting the log level to an unsupported value is rejected."""
151+
ssh_session = Session()
152+
153+
error_msg = r'^Invalid log level \[99\]$'
154+
with pytest.raises(LibsshSessionException, match=error_msg):
155+
ssh_session.set_log_level(BAD_LOG_LEVEL)

0 commit comments

Comments
 (0)