Add more insight into failures

This commit is contained in:
Pedro Algarvio 2020-08-20 08:42:16 +01:00
parent 7721f5ca57
commit 86a86e6b58
No known key found for this signature in database
GPG key ID: BB36BF6584A298FF
2 changed files with 80 additions and 77 deletions

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
:copyright: Copyright 2013-2017 by the SaltStack Team, see AUTHORS for more details.
:license: Apache 2.0, see LICENSE for more details.
@ -9,7 +8,6 @@
Test support helpers
"""
from __future__ import absolute_import, print_function, unicode_literals
import base64
import errno
@ -40,7 +38,8 @@ import salt.utils.pycrypto
import salt.utils.stringutils
import salt.utils.versions
from salt.ext import six
from salt.ext.six.moves import builtins, range
from salt.ext.six.moves import builtins
from saltfactories.exceptions import ProcessFailed
from saltfactories.utils.ports import get_unused_localhost_port
from saltfactories.utils.processes.bases import ProcessResult
from tests.support.mock import patch
@ -306,7 +305,7 @@ def requires_sshd_server(caller):
return wrap
class RedirectStdStreams(object):
class RedirectStdStreams:
"""
Temporarily redirect system output to file like objects.
Default is to redirect to `os.devnull`, which just mutes output, `stdout`
@ -375,7 +374,7 @@ class RedirectStdStreams(object):
pass
class TstSuiteLoggingHandler(object):
class TstSuiteLoggingHandler:
"""
Simple logging handler which can be used to test if certain logging
messages get emitted or not:
@ -459,7 +458,7 @@ class TstSuiteLoggingHandler(object):
return self.handler.release()
class ForceImportErrorOn(object):
class ForceImportErrorOn:
"""
This class is meant to be used in mock'ed test cases which require an
``ImportError`` to be raised.
@ -530,22 +529,19 @@ class ForceImportErrorOn(object):
locals_ = {}
if level is None:
if six.PY2:
level = -1
else:
level = 0
level = 0
if fromlist is None:
fromlist = []
if name in self.__module_names:
importerror_fromlist = self.__module_names.get(name)
if importerror_fromlist is None:
raise ImportError("Forced ImportError raised for {0!r}".format(name))
raise ImportError("Forced ImportError raised for {!r}".format(name))
if importerror_fromlist.intersection(set(fromlist)):
raise ImportError(
"Forced ImportError raised for {0!r}".format(
"from {0} import {1}".format(name, ", ".join(fromlist))
"Forced ImportError raised for {!r}".format(
"from {} import {}".format(name, ", ".join(fromlist))
)
)
return self.__original_import(name, globals_, locals_, fromlist, level)
@ -558,7 +554,7 @@ class ForceImportErrorOn(object):
self.restore_import_funtion()
class MockWraps(object):
class MockWraps:
"""
Helper class to be used with the mock library.
To be used in the ``wraps`` keyword of ``Mock`` or ``MagicMock`` where you
@ -623,7 +619,7 @@ def requires_network(only_local_network=False):
retsock.bind(("", 18001))
retsock.close()
has_local_network = True
except socket.error:
except OSError:
# I wonder if we just have IPV6 support?
try:
pubsock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
@ -635,7 +631,7 @@ def requires_network(only_local_network=False):
retsock.bind(("", 18001))
retsock.close()
has_local_network = True
except socket.error:
except OSError:
# Let's continue
pass
@ -670,7 +666,7 @@ def requires_network(only_local_network=False):
sock.connect((addr, 80))
# We connected? Stop the loop
break
except socket.error:
except OSError:
# Let's check the next IP
continue
else:
@ -715,7 +711,7 @@ def with_system_user(
def wrap(cls):
# Let's add the user to the system.
log.debug("Creating system user {0!r}".format(username))
log.debug("Creating system user {!r}".format(username))
kwargs = {"timeout": 60, "groups": groups}
if salt.utils.platform.is_windows():
kwargs.update({"password": password})
@ -724,25 +720,25 @@ def with_system_user(
log.debug("Failed to create system user")
# The user was not created
if on_existing == "skip":
cls.skipTest("Failed to create system user {0!r}".format(username))
cls.skipTest("Failed to create system user {!r}".format(username))
if on_existing == "delete":
log.debug("Deleting the system user {0!r}".format(username))
log.debug("Deleting the system user {!r}".format(username))
delete_user = cls.run_function(
"user.delete", [username, True, True]
)
if not delete_user:
cls.skipTest(
"A user named {0!r} already existed on the "
"A user named {!r} already existed on the "
"system and re-creating it was not possible".format(
username
)
)
log.debug("Second time creating system user {0!r}".format(username))
log.debug("Second time creating system user {!r}".format(username))
create_user = cls.run_function("user.add", [username], **kwargs)
if not create_user:
cls.skipTest(
"A user named {0!r} already existed, was deleted "
"A user named {!r} already existed, was deleted "
"as requested, but re-creating it was not possible".format(
username
)
@ -752,7 +748,7 @@ def with_system_user(
hashed_password = password
else:
hashed_password = salt.utils.pycrypto.gen_hash(password=password)
hashed_password = "'{0}'".format(hashed_password)
hashed_password = "'{}'".format(hashed_password)
add_pwd = cls.run_function(
"shadow.set_password", [username, hashed_password]
)
@ -763,7 +759,7 @@ def with_system_user(
return func(cls, username)
except Exception as exc: # pylint: disable=W0703
log.error(
"Running {0!r} raised an exception: {1}".format(func, exc),
"Running {!r} raised an exception: {}".format(func, exc),
exc_info=True,
)
# Store the original exception details which will be raised
@ -778,17 +774,17 @@ def with_system_user(
if failure is None:
log.warning(
"Although the actual test-case did not fail, "
"deleting the created system user {0!r} "
"deleting the created system user {!r} "
"afterwards did.".format(username)
)
else:
log.warning(
"The test-case failed and also did the removal"
" of the system user {0!r}".format(username)
" of the system user {!r}".format(username)
)
if failure is not None:
# If an exception was thrown, raise it
six.reraise(failure[0], failure[1], failure[2])
raise failure[1].with_traceback(failure[2])
return wrap
@ -824,27 +820,27 @@ def with_system_group(group, on_existing="delete", delete=True):
def wrap(cls):
# Let's add the user to the system.
log.debug("Creating system group {0!r}".format(group))
log.debug("Creating system group {!r}".format(group))
create_group = cls.run_function("group.add", [group])
if not create_group:
log.debug("Failed to create system group")
# The group was not created
if on_existing == "skip":
cls.skipTest("Failed to create system group {0!r}".format(group))
cls.skipTest("Failed to create system group {!r}".format(group))
if on_existing == "delete":
log.debug("Deleting the system group {0!r}".format(group))
log.debug("Deleting the system group {!r}".format(group))
delete_group = cls.run_function("group.delete", [group])
if not delete_group:
cls.skipTest(
"A group named {0!r} already existed on the "
"A group named {!r} already existed on the "
"system and re-creating it was not possible".format(group)
)
log.debug("Second time creating system group {0!r}".format(group))
log.debug("Second time creating system group {!r}".format(group))
create_group = cls.run_function("group.add", [group])
if not create_group:
cls.skipTest(
"A group named {0!r} already existed, was deleted "
"A group named {!r} already existed, was deleted "
"as requested, but re-creating it was not possible".format(
group
)
@ -856,7 +852,7 @@ def with_system_group(group, on_existing="delete", delete=True):
return func(cls, group)
except Exception as exc: # pylint: disable=W0703
log.error(
"Running {0!r} raised an exception: {1}".format(func, exc),
"Running {!r} raised an exception: {}".format(func, exc),
exc_info=True,
)
# Store the original exception details which will be raised
@ -869,17 +865,17 @@ def with_system_group(group, on_existing="delete", delete=True):
if failure is None:
log.warning(
"Although the actual test-case did not fail, "
"deleting the created system group {0!r} "
"deleting the created system group {!r} "
"afterwards did.".format(group)
)
else:
log.warning(
"The test-case failed and also did the removal"
" of the system group {0!r}".format(group)
" of the system group {!r}".format(group)
)
if failure is not None:
# If an exception was thrown, raise it
six.reraise(failure[0], failure[1], failure[2])
raise failure[1].with_traceback(failure[2])
return wrap
@ -918,33 +914,33 @@ def with_system_user_and_group(username, group, on_existing="delete", delete=Tru
def wrap(cls):
# Let's add the user to the system.
log.debug("Creating system user {0!r}".format(username))
log.debug("Creating system user {!r}".format(username))
create_user = cls.run_function("user.add", [username])
log.debug("Creating system group {0!r}".format(group))
log.debug("Creating system group {!r}".format(group))
create_group = cls.run_function("group.add", [group])
if not create_user:
log.debug("Failed to create system user")
# The user was not created
if on_existing == "skip":
cls.skipTest("Failed to create system user {0!r}".format(username))
cls.skipTest("Failed to create system user {!r}".format(username))
if on_existing == "delete":
log.debug("Deleting the system user {0!r}".format(username))
log.debug("Deleting the system user {!r}".format(username))
delete_user = cls.run_function(
"user.delete", [username, True, True]
)
if not delete_user:
cls.skipTest(
"A user named {0!r} already existed on the "
"A user named {!r} already existed on the "
"system and re-creating it was not possible".format(
username
)
)
log.debug("Second time creating system user {0!r}".format(username))
log.debug("Second time creating system user {!r}".format(username))
create_user = cls.run_function("user.add", [username])
if not create_user:
cls.skipTest(
"A user named {0!r} already existed, was deleted "
"A user named {!r} already existed, was deleted "
"as requested, but re-creating it was not possible".format(
username
)
@ -953,21 +949,21 @@ def with_system_user_and_group(username, group, on_existing="delete", delete=Tru
log.debug("Failed to create system group")
# The group was not created
if on_existing == "skip":
cls.skipTest("Failed to create system group {0!r}".format(group))
cls.skipTest("Failed to create system group {!r}".format(group))
if on_existing == "delete":
log.debug("Deleting the system group {0!r}".format(group))
log.debug("Deleting the system group {!r}".format(group))
delete_group = cls.run_function("group.delete", [group])
if not delete_group:
cls.skipTest(
"A group named {0!r} already existed on the "
"A group named {!r} already existed on the "
"system and re-creating it was not possible".format(group)
)
log.debug("Second time creating system group {0!r}".format(group))
log.debug("Second time creating system group {!r}".format(group))
create_group = cls.run_function("group.add", [group])
if not create_group:
cls.skipTest(
"A group named {0!r} already existed, was deleted "
"A group named {!r} already existed, was deleted "
"as requested, but re-creating it was not possible".format(
group
)
@ -979,7 +975,7 @@ def with_system_user_and_group(username, group, on_existing="delete", delete=Tru
return func(cls, username, group)
except Exception as exc: # pylint: disable=W0703
log.error(
"Running {0!r} raised an exception: {1}".format(func, exc),
"Running {!r} raised an exception: {}".format(func, exc),
exc_info=True,
)
# Store the original exception details which will be raised
@ -995,36 +991,36 @@ def with_system_user_and_group(username, group, on_existing="delete", delete=Tru
if failure is None:
log.warning(
"Although the actual test-case did not fail, "
"deleting the created system user {0!r} "
"deleting the created system user {!r} "
"afterwards did.".format(username)
)
else:
log.warning(
"The test-case failed and also did the removal"
" of the system user {0!r}".format(username)
" of the system user {!r}".format(username)
)
if not delete_group:
if failure is None:
log.warning(
"Although the actual test-case did not fail, "
"deleting the created system group {0!r} "
"deleting the created system group {!r} "
"afterwards did.".format(group)
)
else:
log.warning(
"The test-case failed and also did the removal"
" of the system group {0!r}".format(group)
" of the system group {!r}".format(group)
)
if failure is not None:
# If an exception was thrown, raise it
six.reraise(failure[0], failure[1], failure[2])
raise failure[1].with_traceback(failure[2])
return wrap
return decorator
class WithTempfile(object):
class WithTempfile:
def __init__(self, **kwargs):
self.create = kwargs.pop("create", True)
if "dir" not in kwargs:
@ -1057,7 +1053,7 @@ class WithTempfile(object):
with_tempfile = WithTempfile
class WithTempdir(object):
class WithTempdir:
def __init__(self, **kwargs):
self.create = kwargs.pop("create", True)
if "dir" not in kwargs:
@ -1227,20 +1223,20 @@ def skip_if_binaries_missing(*binaries, **kwargs):
if kwargs:
raise RuntimeError(
"The only supported keyword argument is 'check_all' and "
"'message'. Invalid keyword arguments: {0}".format(", ".join(kwargs.keys()))
"'message'. Invalid keyword arguments: {}".format(", ".join(kwargs.keys()))
)
if check_all:
for binary in binaries:
if salt.utils.path.which(binary) is None:
return skip(
"{0}The {1!r} binary was not found".format(
message and "{0}. ".format(message) or "", binary
"{}The {!r} binary was not found".format(
message and "{}. ".format(message) or "", binary
)
)
elif salt.utils.path.which_bin(binaries) is None:
return skip(
"{0}None of the following binaries was found: {1}".format(
message and "{0}. ".format(message) or "", ", ".join(binaries)
"{}None of the following binaries was found: {}".format(
message and "{}. ".format(message) or "", ", ".join(binaries)
)
)
return _id
@ -1424,7 +1420,7 @@ def random_string(prefix, size=6, uppercase=True, lowercase=True, digits=True):
return prefix + "".join(random.choice(choices) for _ in range(size))
class Webserver(object):
class Webserver:
"""
Starts a tornado webserver on 127.0.0.1 on a random available port
@ -1459,7 +1455,7 @@ class Webserver(object):
such as when enforcing authentication with the http_basic_auth
decorator.
"""
if port is not None and not isinstance(port, six.integer_types):
if port is not None and not isinstance(port, int):
raise ValueError("port must be an integer")
if root is None:
@ -1510,7 +1506,7 @@ class Webserver(object):
raise RuntimeError("Webserver instance has not been started")
err_msg = (
"invalid path, must be either a relative path or a path "
"within {0}".format(self.root)
"within {}".format(self.root)
)
try:
relpath = (
@ -1529,7 +1525,7 @@ class Webserver(object):
if self.port is None:
self.port = get_unused_localhost_port()
self.web_root = "http://127.0.0.1:{0}".format(self.port)
self.web_root = "http://127.0.0.1:{}".format(self.port)
self.server_thread = threading.Thread(target=self.target)
self.server_thread.daemon = True
@ -1542,8 +1538,8 @@ class Webserver(object):
time.sleep(1)
else:
raise Exception(
"Failed to start tornado webserver on 127.0.0.1:{0} within "
"{1} seconds".format(self.port, self.wait)
"Failed to start tornado webserver on 127.0.0.1:{} within "
"{} seconds".format(self.port, self.wait)
)
def stop(self):
@ -1603,12 +1599,12 @@ def dedent(text, linesep=os.linesep):
clean_text = linesep.join(unicode_text.splitlines())
if unicode_text.endswith("\n"):
clean_text += linesep
if not isinstance(text, six.text_type):
if not isinstance(text, str):
return salt.utils.stringutils.to_bytes(clean_text)
return clean_text
class PatchedEnviron(object):
class PatchedEnviron:
def __init__(self, **kwargs):
self.cleanup_keys = kwargs.pop("__cleanup__", ())
self.kwargs = kwargs
@ -1627,9 +1623,9 @@ class PatchedEnviron(object):
clean_kwargs = {}
for k in self.kwargs:
key = k
if isinstance(key, six.text_type):
if isinstance(key, str):
key = key.encode("utf-8")
if isinstance(self.kwargs[k], six.text_type):
if isinstance(self.kwargs[k], str):
kwargs[k] = kwargs[k].encode("utf-8")
clean_kwargs[key] = kwargs[k]
self.kwargs = clean_kwargs
@ -1645,7 +1641,7 @@ class PatchedEnviron(object):
patched_environ = PatchedEnviron
class VirtualEnv(object):
class VirtualEnv:
def __init__(self, venv_dir=None):
self.venv_dir = venv_dir or tempfile.mkdtemp(dir=RUNTIME_VARS.TMP)
if salt.utils.platform.is_windows():
@ -1677,7 +1673,16 @@ class VirtualEnv(object):
ret = ProcessResult(proc.returncode, proc.stdout, proc.stderr, proc.args)
log.debug(ret)
if check is True:
proc.check_returncode()
try:
proc.check_returncode()
except subprocess.CalledProcessError:
raise ProcessFailed(
"Command failed return code check",
cmdline=proc.args,
stdout=proc.stdout,
stderr=proc.stderr,
exitcode=proc.returncode,
)
return ret
def _get_real_python(self):

View file

@ -1,9 +1,7 @@
# -*- coding: utf-8 -*-
"""
tests.unit.setup.test_install
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"""
from __future__ import absolute_import, print_function, unicode_literals
import json
import logging