Skip to content

Commit 63166d1

Browse files
authored
Optimize tests timeouts and polling
* pytest-xdist cannot help due to pypy3 compatibility * modify tests, which can receive race-conditions * remove never documented internal code * add 1 test for coverage bump * 100 ms timeout & 100 ms cycle can cause false negative -> use 200
1 parent 57cd273 commit 63166d1

File tree

6 files changed

+79
-40
lines changed

6 files changed

+79
-40
lines changed

exec_helpers/_ssh_client_base.py

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -191,24 +191,11 @@ def clear_cache(mcs): # type: () -> None
191191
mcs.__cache = {}
192192

193193
@classmethod
194-
def close_connections(
195-
mcs,
196-
hostname=None # type: typing.Optional[str]
197-
): # type: (...) -> None
198-
"""Close connections for selected or all cached records.
199-
200-
:type hostname: str
201-
"""
202-
if hostname is None:
203-
keys = [key for key, ssh in mcs.__cache.items() if ssh.is_alive]
204-
else:
205-
keys = [
206-
(host, port)
207-
for (host, port), ssh
208-
in mcs.__cache.items() if host == hostname and ssh.is_alive]
209-
# raise ValueError(keys)
210-
for key in keys:
211-
mcs.__cache[key].close()
194+
def close_connections(mcs): # type: (...) -> None
195+
"""Close connections for selected or all cached records."""
196+
for ssh in mcs.__cache.values():
197+
if ssh.is_alive:
198+
ssh.close()
212199

213200

214201
class SSHClientBase(six.with_metaclass(_MemorizedSSH, _api.ExecHelper)):
@@ -742,7 +729,6 @@ def poll_pipes(stop, ): # type: (threading.Event) -> None
742729

743730
# Process closed?
744731
if stop_event.is_set():
745-
stop_event.clear()
746732
interface.close()
747733
return result
748734

exec_helpers/proc_enums.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
from __future__ import unicode_literals
2525

2626
import enum
27-
import typing
27+
import typing # noqa # pylint: disable=unused-import
2828

2929
import six
3030

@@ -72,7 +72,7 @@ class SigNum(enum.IntEnum):
7272
SIGPWR = 30 # Power failure restart (System V).
7373
SIGSYS = 31 # Bad system call.
7474

75-
def __str__(self):
75+
def __str__(self): # pragma: no cover
7676
"""Representation for logs."""
7777
return "{name}<{value:d}(0x{value:02X})>".format(
7878
name=self.name,
@@ -158,19 +158,16 @@ def __str__(self):
158158
)
159159

160160

161-
_type_exit_codes = typing.Union[int, ExitCodes]
162-
163-
164-
def exit_code_to_enum(code): # type: (_type_exit_codes) -> _type_exit_codes
161+
def exit_code_to_enum(code): # type: (typing.Union[int, ExitCodes]) -> typing.Union[int, ExitCodes]
165162
"""Convert exit code to enum if possible."""
166163
if isinstance(code, int) and code in ExitCodes.__members__.values():
167164
return ExitCodes(code)
168165
return code
169166

170167

171168
def exit_codes_to_enums(
172-
codes=None # type: typing.Optional[typing.Iterable[_type_exit_codes]]
173-
): # type: (...) -> typing.List[_type_exit_codes]
169+
codes=None # type: typing.Optional[typing.Iterable[typing.Union[int, ExitCodes]]]
170+
): # type: (...) -> typing.List[typing.Union[int, ExitCodes]]
174171
"""Convert integer exit codes to enums."""
175172
if codes is None:
176173
return [ExitCodes.EX_OK]

exec_helpers/subprocess_runner.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,6 @@ def poll_pipes(stop, ): # type: (threading.Event) -> None
249249

250250
# Process closed?
251251
if stop_event.is_set():
252-
stop_event.clear()
253252
return result
254253
# Kill not ended process and wait for close
255254
try:

test/test_ssh_client.py

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -994,7 +994,7 @@ def test_024_execute_timeout(
994994
logger.reset_mock()
995995

996996
# noinspection PyTypeChecker
997-
result = ssh.execute(command=command, verbose=False, timeout=0.1)
997+
result = ssh.execute(command=command, verbose=False, timeout=0.2)
998998

999999
self.assertEqual(
10001000
result,
@@ -1030,7 +1030,7 @@ def test_025_execute_timeout_fail(
10301030

10311031
with self.assertRaises(exec_helpers.ExecHelperTimeoutError):
10321032
# noinspection PyTypeChecker
1033-
ssh.execute(command=command, verbose=False, timeout=0.1)
1033+
ssh.execute(command=command, verbose=False, timeout=0.2)
10341034

10351035
execute_async.assert_called_once_with(command, verbose=False)
10361036
chan.assert_has_calls((mock.call.status_event.is_set(), ))
@@ -1468,6 +1468,65 @@ def test_02_execute_through_host_auth(self, transp, client, policy, logger):
14681468
mock.call.close()
14691469
))
14701470

1471+
def test_03_execute_through_host_get_pty(
1472+
self, transp, client, policy, logger):
1473+
target = '127.0.0.2'
1474+
exit_code = 0
1475+
1476+
# noinspection PyTypeChecker
1477+
return_value = exec_result.ExecResult(
1478+
cmd=command,
1479+
stderr=stderr_list,
1480+
stdout=stdout_list,
1481+
exit_code=exit_code
1482+
)
1483+
1484+
(
1485+
open_session,
1486+
transport,
1487+
channel,
1488+
get_transport,
1489+
open_channel,
1490+
intermediate_channel
1491+
) = self.prepare_execute_through_host(
1492+
transp=transp,
1493+
client=client,
1494+
exit_code=exit_code)
1495+
1496+
# noinspection PyTypeChecker
1497+
ssh = exec_helpers.SSHClient(
1498+
host=host,
1499+
port=port,
1500+
auth=exec_helpers.SSHAuth(
1501+
username=username,
1502+
password=password
1503+
))
1504+
1505+
# noinspection PyTypeChecker
1506+
result = ssh.execute_through_host(target, command, get_pty=True)
1507+
self.assertEqual(result, return_value)
1508+
get_transport.assert_called_once()
1509+
open_channel.assert_called_once()
1510+
transp.assert_called_once_with(intermediate_channel)
1511+
open_session.assert_called_once()
1512+
transport.assert_has_calls((
1513+
mock.call.connect(
1514+
username=username, password=password, pkey=None,
1515+
),
1516+
mock.call.open_session()
1517+
))
1518+
1519+
channel.assert_has_calls((
1520+
mock.call.get_pty(term='vt100', width=80, height=24, width_pixels=0, height_pixels=0),
1521+
mock.call.makefile('rb'),
1522+
mock.call.makefile_stderr('rb'),
1523+
mock.call.exec_command(command),
1524+
mock.call.recv_ready(),
1525+
mock.call.recv_stderr_ready(),
1526+
mock.call.status_event.is_set(),
1527+
mock.call.close()
1528+
))
1529+
14711530

14721531
@mock.patch('exec_helpers._ssh_client_base.logger', autospec=True)
14731532
@mock.patch('paramiko.AutoAddPolicy', autospec=True, return_value='AutoAddPolicy')

test/test_ssh_client_init.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -708,13 +708,10 @@ def test_023_init_memorize(
708708
no_call.assert_not_called()
709709
# Mock returns false-connected state, so we just count close calls
710710

711-
client.assert_has_calls((
712-
mock.call().get_transport(),
713-
mock.call().get_transport(),
714-
mock.call().get_transport(),
715-
mock.call().close(),
716-
mock.call().close(),
717-
mock.call().close(),
711+
client().close.assert_has_calls((
712+
mock.call(),
713+
mock.call(),
714+
mock.call(),
718715
))
719716

720717
# change creds

test/test_subprocess_runner.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ def test_003_context_manager(
206206

207207
with mock.patch('threading.RLock', autospec=True):
208208
with exec_helpers.Subprocess() as runner:
209+
runner.lock.acquire.assert_called()
209210
self.assertEqual(
210211
mock.call.acquire(), runner.lock.mock_calls[0]
211212
)
@@ -215,7 +216,7 @@ def test_003_context_manager(
215216

216217
)
217218

218-
self.assertEqual(mock.call.release(), runner.lock.mock_calls[-1])
219+
runner.lock.release.assert_called()
219220

220221
subprocess_runner.SingletonMeta._instances.clear()
221222

@@ -235,7 +236,7 @@ def test_004_execute_timeout_fail(
235236

236237
with self.assertRaises(exec_helpers.ExecHelperTimeoutError):
237238
# noinspection PyTypeChecker
238-
runner.execute(command, timeout=1)
239+
runner.execute(command, timeout=0.2)
239240

240241
popen.assert_has_calls((
241242
mock.call(
@@ -830,7 +831,7 @@ def test_013_execute_timeout_done(
830831

831832
# noinspection PyTypeChecker
832833

833-
res = runner.execute(command, timeout=0.1)
834+
res = runner.execute(command, timeout=0.2)
834835

835836
self.assertEqual(res, exp_result)
836837

0 commit comments

Comments
 (0)