Bump pytest-salt-factories to 0.92.x

This commit is contained in:
Pedro Algarvio 2020-09-03 09:58:54 +01:00
parent 3ab6b9dca2
commit 0aba49c7d3
No known key found for this signature in database
GPG key ID: BB36BF6584A298FF
47 changed files with 2067 additions and 2752 deletions

View file

@ -681,6 +681,7 @@ allowed-3rd-party-modules=msgpack,
libcloud,
zmq,
pytest,
attr,
setuptools,
pytestsalt,
saltfactories,

View file

@ -932,7 +932,15 @@ def _pytest(session, coverage, cmd_args):
try:
if coverage is True:
_run_with_coverage(
session, "python", "-m", "coverage", "run", "-m", "pytest", *cmd_args
session,
"python",
"-m",
"coverage",
"run",
"-m",
"pytest",
"--showlocals",
*cmd_args
)
else:
session.run("python", "-m", "pytest", *cmd_args, env=env)

View file

@ -2,6 +2,6 @@ mock >= 3.0.0
# PyTest
pytest >= 6.0.1
pytest-salt
pytest-salt-factories >= 0.11.4
pytest-salt-factories >= 0.92.0
pytest-tempdir >= 2019.10.12
pytest-helpers-namespace >= 2019.1.8

View file

@ -90,7 +90,7 @@ pyopenssl==19.0.0
pyparsing==2.4.5 # via junos-eznc, packaging
pyserial==3.4 # via junos-eznc
pytest-helpers-namespace==2019.1.8
pytest-salt-factories==0.11.4
pytest-salt-factories==0.92.0
pytest-salt==2020.1.27
pytest-tempdir==2019.10.12
pytest==6.0.1

View file

@ -90,7 +90,7 @@ pyopenssl==19.0.0
pyparsing==2.4.5 # via junos-eznc, packaging
pyserial==3.4 # via junos-eznc
pytest-helpers-namespace==2019.1.8
pytest-salt-factories==0.11.4
pytest-salt-factories==0.92.0
pytest-salt==2020.1.27
pytest-tempdir==2019.10.12
pytest==6.0.1

View file

@ -181,7 +181,7 @@ pyopenssl==19.0.0
pyparsing==2.4.5 # via junos-eznc, packaging
pyserial==3.4 # via junos-eznc
pytest-helpers-namespace==2019.1.8
pytest-salt-factories==0.11.4
pytest-salt-factories==0.92.0
pytest-salt==2020.1.27
pytest-tempdir==2019.10.12
pytest==6.0.1

View file

@ -83,7 +83,7 @@ pymysql==0.9.3
pyopenssl==19.0.0
pyparsing==2.4.5 # via packaging
pytest-helpers-namespace==2019.1.8
pytest-salt-factories==0.11.4
pytest-salt-factories==0.92.0
pytest-salt==2020.1.27
pytest-tempdir==2019.10.12
pytest==6.0.1

View file

@ -95,7 +95,7 @@ pyopenssl==19.0.0
pyparsing==2.4.5 # via junos-eznc, packaging
pyserial==3.4 # via junos-eznc, netmiko
pytest-helpers-namespace==2019.1.8
pytest-salt-factories==0.11.4
pytest-salt-factories==0.92.0
pytest-salt==2020.1.27
pytest-tempdir==2019.10.12
pytest==6.0.1

View file

@ -95,7 +95,7 @@ pyopenssl==19.0.0
pyparsing==2.4.5 # via junos-eznc, packaging
pyserial==3.4 # via junos-eznc, netmiko
pytest-helpers-namespace==2019.1.8
pytest-salt-factories==0.11.4
pytest-salt-factories==0.92.0
pytest-salt==2020.1.27
pytest-tempdir==2019.10.12
pytest==6.0.1

View file

@ -185,7 +185,7 @@ pyopenssl==19.0.0
pyparsing==2.4.5 # via junos-eznc, packaging
pyserial==3.4 # via junos-eznc, netmiko
pytest-helpers-namespace==2019.1.8
pytest-salt-factories==0.11.4
pytest-salt-factories==0.92.0
pytest-salt==2020.1.27
pytest-tempdir==2019.10.12
pytest==6.0.1

View file

@ -82,7 +82,7 @@ pymysql==0.9.3
pyopenssl==19.0.0
pyparsing==2.4.5 # via packaging
pytest-helpers-namespace==2019.1.8
pytest-salt-factories==0.11.4
pytest-salt-factories==0.92.0
pytest-salt==2020.1.27
pytest-tempdir==2019.10.12
pytest==6.0.1

View file

@ -93,7 +93,7 @@ pyopenssl==19.0.0
pyparsing==2.4.5 # via junos-eznc, packaging
pyserial==3.4 # via junos-eznc, netmiko
pytest-helpers-namespace==2019.1.8
pytest-salt-factories==0.11.4
pytest-salt-factories==0.92.0
pytest-salt==2020.1.27
pytest-tempdir==2019.10.12
pytest==6.0.1

View file

@ -94,7 +94,7 @@ pyopenssl==19.0.0
pyparsing==2.4.5 # via junos-eznc, packaging
pyserial==3.4 # via junos-eznc, netmiko
pytest-helpers-namespace==2019.1.8
pytest-salt-factories==0.11.4
pytest-salt-factories==0.92.0
pytest-salt==2020.1.27
pytest-tempdir==2019.10.12
pytest==6.0.1

View file

@ -184,7 +184,7 @@ pyopenssl==19.0.0
pyparsing==2.4.5 # via junos-eznc, packaging
pyserial==3.4 # via junos-eznc, netmiko
pytest-helpers-namespace==2019.1.8
pytest-salt-factories==0.11.4
pytest-salt-factories==0.92.0
pytest-salt==2020.1.27
pytest-tempdir==2019.10.12
pytest==6.0.1

View file

@ -80,7 +80,7 @@ pymysql==0.9.3
pyopenssl==19.0.0
pyparsing==2.4.5 # via packaging
pytest-helpers-namespace==2019.1.8
pytest-salt-factories==0.11.4
pytest-salt-factories==0.92.0
pytest-salt==2020.1.27
pytest-tempdir==2019.10.12
pytest==6.0.1

View file

@ -92,7 +92,7 @@ pyopenssl==19.0.0
pyparsing==2.4.5 # via junos-eznc, packaging
pyserial==3.4 # via junos-eznc, netmiko
pytest-helpers-namespace==2019.1.8
pytest-salt-factories==0.11.4
pytest-salt-factories==0.92.0
pytest-salt==2020.1.27
pytest-tempdir==2019.10.12
pytest==6.0.1

View file

@ -93,7 +93,7 @@ pyopenssl==19.0.0
pyparsing==2.4.5 # via junos-eznc, packaging
pyserial==3.4 # via junos-eznc, netmiko
pytest-helpers-namespace==2019.1.8
pytest-salt-factories==0.11.4
pytest-salt-factories==0.92.0
pytest-salt==2020.1.27
pytest-tempdir==2019.10.12
pytest==6.0.1

View file

@ -184,7 +184,7 @@ pyopenssl==19.0.0
pyparsing==2.4.5 # via junos-eznc, packaging
pyserial==3.4 # via junos-eznc, netmiko
pytest-helpers-namespace==2019.1.8
pytest-salt-factories==0.11.4
pytest-salt-factories==0.92.0
pytest-salt==2020.1.27
pytest-tempdir==2019.10.12
pytest==6.0.1

View file

@ -92,7 +92,7 @@ pyopenssl==19.0.0
pyparsing==2.4.5 # via junos-eznc, packaging
pyserial==3.4 # via junos-eznc, netmiko
pytest-helpers-namespace==2019.1.8
pytest-salt-factories==0.11.4
pytest-salt-factories==0.92.0
pytest-salt==2020.1.27
pytest-tempdir==2019.10.12
pytest==6.0.1

View file

@ -93,7 +93,7 @@ pyopenssl==19.0.0
pyparsing==2.4.5 # via junos-eznc, packaging
pyserial==3.4 # via junos-eznc, netmiko
pytest-helpers-namespace==2019.1.8
pytest-salt-factories==0.11.4
pytest-salt-factories==0.92.0
pytest-salt==2020.1.27
pytest-tempdir==2019.10.12
pytest==6.0.1

View file

@ -184,7 +184,7 @@ pyopenssl==19.0.0
pyparsing==2.4.5 # via junos-eznc, packaging
pyserial==3.4 # via junos-eznc, netmiko
pytest-helpers-namespace==2019.1.8
pytest-salt-factories==0.11.4
pytest-salt-factories==0.92.0
pytest-salt==2020.1.27
pytest-tempdir==2019.10.12
pytest==6.0.1

View file

@ -15,7 +15,10 @@ import os
import pathlib
import pprint
import re
import shutil
import stat
import sys
import textwrap
from functools import partial, wraps
from unittest import TestCase # pylint: disable=blacklisted-module
@ -33,11 +36,14 @@ import salt.utils.platform
import salt.utils.win_functions
import saltfactories.utils.compat
from salt.serializers import yaml
from tests.support.helpers import PRE_PYTEST_SKIP_OR_NOT, PRE_PYTEST_SKIP_REASON
from tests.support.pytest.fixtures import * # pylint: disable=unused-wildcard-import
from salt.utils.immutabletypes import freeze
from tests.support.helpers import (
PRE_PYTEST_SKIP_OR_NOT,
PRE_PYTEST_SKIP_REASON,
get_virtualenv_binary_path,
)
from tests.support.pytest.helpers import * # pylint: disable=unused-wildcard-import
from tests.support.runtests import RUNTIME_VARS
from tests.support.saltfactories_compat import LogServer
from tests.support.sminion import check_required_sminion_attributes, create_sminion
TESTS_DIR = pathlib.Path(__file__).resolve().parent
@ -232,39 +238,15 @@ def pytest_configure(config):
config.addinivalue_line(
"markers", "windows_whitelisted: Mark test as whitelisted to run under Windows"
)
config.addinivalue_line(
"markers", "requires_sshd_server: Mark test that require an SSH server running"
)
# Make sure the test suite "knows" this is a pytest test run
RUNTIME_VARS.PYTEST_SESSION = True
# "Flag" the slotTest decorator if we're skipping slow tests or not
os.environ["SLOW_TESTS"] = str(config.getoption("--run-slow"))
# If PyTest has no logging configured, default to ERROR level
levels = [logging.ERROR]
logging_plugin = config.pluginmanager.get_plugin("logging-plugin")
try:
level = logging_plugin.log_cli_handler.level
if level is not None:
levels.append(level)
except AttributeError:
# PyTest CLI logging not configured
pass
try:
level = logging_plugin.log_file_level
if level is not None:
levels.append(level)
except AttributeError:
# PyTest Log File logging not configured
pass
if logging.NOTSET in levels:
# We don't want the NOTSET level on the levels
levels.pop(levels.index(logging.NOTSET))
log_level = logging.getLevelName(min(levels))
log_server = LogServer(log_level=log_level)
config.pluginmanager.register(log_server, "salt-saltfactories-log-server")
# <---- Register Markers ---------------------------------------------------------------------------------------------
@ -464,29 +446,6 @@ def pytest_runtest_protocol(item, nextitem):
del used_fixture_defs
@pytest.hookimpl(tryfirst=True)
def pytest_sessionstart(session):
log_server = session.config.pluginmanager.get_plugin(
"salt-saltfactories-log-server"
)
log_server.start()
@pytest.hookimpl(trylast=True)
def pytest_sessionfinish(session):
log_server = session.config.pluginmanager.get_plugin(
"salt-saltfactories-log-server"
)
log_server.stop()
@pytest.fixture(scope="session")
def log_server():
"""
Just overriding the fixture
"""
# <---- PyTest Tweaks ------------------------------------------------------------------------------------------------
@ -509,6 +468,13 @@ def pytest_runtest_setup(item):
item._skipped_by_mark = True
pytest.skip("Slow tests are disabled!")
requires_sshd_server_marker = item.get_closest_marker("requires_sshd_server")
if requires_sshd_server_marker is not None:
if not item.config.getoption("--ssh-tests"):
item._skipped_by_mark = True
pytest.skip("SSH tests are disabled, pass '--ssh-tests' to enable them.")
item.fixturenames.append("sshd_server")
requires_salt_modules_marker = item.get_closest_marker("requires_salt_modules")
if requires_salt_modules_marker is not None:
required_salt_modules = requires_salt_modules_marker.args
@ -630,29 +596,561 @@ def groups_collection_modifyitems(config, items):
# ----- Fixtures Overrides ------------------------------------------------------------------------------------------>
@pytest.fixture(scope="session")
def salt_factories_config(request):
def salt_factories_config():
"""
Return a dictionary with the keyworkd arguments for SaltFactoriesManager
Return a dictionary with the keyworkd arguments for FactoriesManager
"""
log_server = request.config.pluginmanager.get_plugin(
"salt-saltfactories-log-server"
)
return {
"executable": sys.executable,
"code_dir": str(CODE_DIR),
"inject_coverage": MAYBE_RUN_COVERAGE,
"inject_sitecustomize": MAYBE_RUN_COVERAGE,
"start_timeout": 120
if (os.environ.get("JENKINS_URL") or os.environ.get("CI"))
else 60,
"log_server_host": log_server.log_host,
"log_server_port": log_server.log_port,
"log_server_level": log_server.log_level,
}
# <---- Pytest Helpers -----------------------------------------------------------------------------------------------
# ----- Salt Factories ---------------------------------------------------------------------------------------------->
@pytest.fixture(scope="session")
def integration_files_dir(salt_factories):
"""
Fixture which returns the salt integration files directory path.
Creates the directory if it does not yet exist.
"""
dirname = salt_factories.root_dir / "integration-files"
dirname.mkdir(exist_ok=True)
return dirname
@pytest.fixture(scope="session")
def state_tree_root_dir(integration_files_dir):
"""
Fixture which returns the salt state tree root directory path.
Creates the directory if it does not yet exist.
"""
dirname = integration_files_dir / "state-tree"
dirname.mkdir(exist_ok=True)
return dirname
@pytest.fixture(scope="session")
def pillar_tree_root_dir(integration_files_dir):
"""
Fixture which returns the salt pillar tree root directory path.
Creates the directory if it does not yet exist.
"""
dirname = integration_files_dir / "pillar-tree"
dirname.mkdir(exist_ok=True)
return dirname
@pytest.fixture(scope="session")
def base_env_state_tree_root_dir(state_tree_root_dir):
"""
Fixture which returns the salt base environment state tree directory path.
Creates the directory if it does not yet exist.
"""
dirname = state_tree_root_dir / "base"
dirname.mkdir(exist_ok=True)
RUNTIME_VARS.TMP_STATE_TREE = str(dirname.resolve())
RUNTIME_VARS.TMP_BASEENV_STATE_TREE = RUNTIME_VARS.TMP_STATE_TREE
return dirname
@pytest.fixture(scope="session")
def prod_env_state_tree_root_dir(state_tree_root_dir):
"""
Fixture which returns the salt prod environment state tree directory path.
Creates the directory if it does not yet exist.
"""
dirname = state_tree_root_dir / "prod"
dirname.mkdir(exist_ok=True)
RUNTIME_VARS.TMP_PRODENV_STATE_TREE = str(dirname.resolve())
return dirname
@pytest.fixture(scope="session")
def base_env_pillar_tree_root_dir(pillar_tree_root_dir):
"""
Fixture which returns the salt base environment pillar tree directory path.
Creates the directory if it does not yet exist.
"""
dirname = pillar_tree_root_dir / "base"
dirname.mkdir(exist_ok=True)
RUNTIME_VARS.TMP_PILLAR_TREE = str(dirname.resolve())
RUNTIME_VARS.TMP_BASEENV_PILLAR_TREE = RUNTIME_VARS.TMP_PILLAR_TREE
return dirname
@pytest.fixture(scope="session")
def prod_env_pillar_tree_root_dir(pillar_tree_root_dir):
"""
Fixture which returns the salt prod environment pillar tree directory path.
Creates the directory if it does not yet exist.
"""
dirname = pillar_tree_root_dir / "prod"
dirname.mkdir(exist_ok=True)
RUNTIME_VARS.TMP_PRODENV_PILLAR_TREE = str(dirname.resolve())
return dirname
@pytest.fixture(scope="session")
def salt_syndic_master_factory(
request,
salt_factories,
base_env_state_tree_root_dir,
base_env_pillar_tree_root_dir,
prod_env_state_tree_root_dir,
prod_env_pillar_tree_root_dir,
):
root_dir = salt_factories.get_root_dir_for_daemon("syndic_master")
conf_dir = root_dir / "conf"
conf_dir.mkdir(exist_ok=True)
with salt.utils.files.fopen(
os.path.join(RUNTIME_VARS.CONF_DIR, "syndic_master")
) as rfh:
config_defaults = yaml.deserialize(rfh.read())
tests_known_hosts_file = str(root_dir / "salt_ssh_known_hosts")
with salt.utils.files.fopen(tests_known_hosts_file, "w") as known_hosts:
known_hosts.write("")
config_defaults["root_dir"] = str(root_dir)
config_defaults["known_hosts_file"] = tests_known_hosts_file
config_defaults["syndic_master"] = "localhost"
config_defaults["transport"] = request.config.getoption("--transport")
config_overrides = {}
ext_pillar = []
if salt.utils.platform.is_windows():
ext_pillar.append(
{"cmd_yaml": "type {}".format(os.path.join(RUNTIME_VARS.FILES, "ext.yaml"))}
)
else:
ext_pillar.append(
{"cmd_yaml": "cat {}".format(os.path.join(RUNTIME_VARS.FILES, "ext.yaml"))}
)
# We need to copy the extension modules into the new master root_dir or
# it will be prefixed by it
extension_modules_path = str(root_dir / "extension_modules")
if not os.path.exists(extension_modules_path):
shutil.copytree(
os.path.join(RUNTIME_VARS.FILES, "extension_modules"),
extension_modules_path,
)
# Copy the autosign_file to the new master root_dir
autosign_file_path = str(root_dir / "autosign_file")
shutil.copyfile(
os.path.join(RUNTIME_VARS.FILES, "autosign_file"), autosign_file_path
)
# all read, only owner write
autosign_file_permissions = (
stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH | stat.S_IWUSR
)
os.chmod(autosign_file_path, autosign_file_permissions)
config_overrides.update(
{
"ext_pillar": ext_pillar,
"extension_modules": extension_modules_path,
"file_roots": {
"base": [
str(base_env_state_tree_root_dir),
os.path.join(RUNTIME_VARS.FILES, "file", "base"),
],
# Alternate root to test __env__ choices
"prod": [
str(prod_env_state_tree_root_dir),
os.path.join(RUNTIME_VARS.FILES, "file", "prod"),
],
},
"pillar_roots": {
"base": [
str(base_env_pillar_tree_root_dir),
os.path.join(RUNTIME_VARS.FILES, "pillar", "base"),
],
"prod": [str(prod_env_pillar_tree_root_dir)],
},
}
)
factory = salt_factories.get_salt_master_daemon(
"syndic_master",
order_masters=True,
config_defaults=config_defaults,
config_overrides=config_overrides,
extra_cli_arguments_after_first_start_failure=["--log-level=debug"],
)
return factory
@pytest.fixture(scope="session")
def salt_syndic_factory(salt_factories, salt_syndic_master_factory):
config_defaults = {"master": None, "minion": None, "syndic": None}
with salt.utils.files.fopen(os.path.join(RUNTIME_VARS.CONF_DIR, "syndic")) as rfh:
opts = yaml.deserialize(rfh.read())
opts["hosts.file"] = os.path.join(RUNTIME_VARS.TMP, "hosts")
opts["aliases.file"] = os.path.join(RUNTIME_VARS.TMP, "aliases")
opts["transport"] = salt_syndic_master_factory.config["transport"]
config_defaults["syndic"] = opts
factory = salt_syndic_master_factory.get_salt_syndic_daemon(
"syndic",
config_defaults=config_defaults,
extra_cli_arguments_after_first_start_failure=["--log-level=debug"],
)
return factory
@pytest.fixture(scope="session")
def salt_master_factory(
salt_factories,
salt_syndic_master_factory,
base_env_state_tree_root_dir,
base_env_pillar_tree_root_dir,
prod_env_state_tree_root_dir,
prod_env_pillar_tree_root_dir,
):
root_dir = salt_factories.get_root_dir_for_daemon("master")
conf_dir = root_dir / "conf"
conf_dir.mkdir(exist_ok=True)
with salt.utils.files.fopen(os.path.join(RUNTIME_VARS.CONF_DIR, "master")) as rfh:
config_defaults = yaml.deserialize(rfh.read())
tests_known_hosts_file = str(root_dir / "salt_ssh_known_hosts")
with salt.utils.files.fopen(tests_known_hosts_file, "w") as known_hosts:
known_hosts.write("")
config_defaults["root_dir"] = str(root_dir)
config_defaults["known_hosts_file"] = tests_known_hosts_file
config_defaults["syndic_master"] = "localhost"
config_defaults["transport"] = salt_syndic_master_factory.config["transport"]
config_defaults["reactor"] = [
{"salt/test/reactor": [os.path.join(RUNTIME_VARS.FILES, "reactor-test.sls")]}
]
config_overrides = {}
ext_pillar = []
if salt.utils.platform.is_windows():
ext_pillar.append(
{"cmd_yaml": "type {}".format(os.path.join(RUNTIME_VARS.FILES, "ext.yaml"))}
)
else:
ext_pillar.append(
{"cmd_yaml": "cat {}".format(os.path.join(RUNTIME_VARS.FILES, "ext.yaml"))}
)
ext_pillar.append(
{
"file_tree": {
"root_dir": os.path.join(RUNTIME_VARS.PILLAR_DIR, "base", "file_tree"),
"follow_dir_links": False,
"keep_newline": True,
}
}
)
config_overrides["pillar_opts"] = True
# We need to copy the extension modules into the new master root_dir or
# it will be prefixed by it
extension_modules_path = str(root_dir / "extension_modules")
if not os.path.exists(extension_modules_path):
shutil.copytree(
os.path.join(RUNTIME_VARS.FILES, "extension_modules"),
extension_modules_path,
)
# Copy the autosign_file to the new master root_dir
autosign_file_path = str(root_dir / "autosign_file")
shutil.copyfile(
os.path.join(RUNTIME_VARS.FILES, "autosign_file"), autosign_file_path
)
# all read, only owner write
autosign_file_permissions = (
stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH | stat.S_IWUSR
)
os.chmod(autosign_file_path, autosign_file_permissions)
config_overrides.update(
{
"ext_pillar": ext_pillar,
"extension_modules": extension_modules_path,
"file_roots": {
"base": [
str(base_env_state_tree_root_dir),
os.path.join(RUNTIME_VARS.FILES, "file", "base"),
],
# Alternate root to test __env__ choices
"prod": [
str(prod_env_state_tree_root_dir),
os.path.join(RUNTIME_VARS.FILES, "file", "prod"),
],
},
"pillar_roots": {
"base": [
str(base_env_pillar_tree_root_dir),
os.path.join(RUNTIME_VARS.FILES, "pillar", "base"),
],
"prod": [str(prod_env_pillar_tree_root_dir)],
},
}
)
# Let's copy over the test cloud config files and directories into the running master config directory
for entry in os.listdir(RUNTIME_VARS.CONF_DIR):
if not entry.startswith("cloud"):
continue
source = os.path.join(RUNTIME_VARS.CONF_DIR, entry)
dest = str(conf_dir / entry)
if os.path.isdir(source):
shutil.copytree(source, dest)
else:
shutil.copyfile(source, dest)
factory = salt_syndic_master_factory.get_salt_master_daemon(
"master",
config_defaults=config_defaults,
config_overrides=config_overrides,
extra_cli_arguments_after_first_start_failure=["--log-level=debug"],
)
return factory
@pytest.fixture(scope="session")
def salt_minion_factory(salt_master_factory):
with salt.utils.files.fopen(os.path.join(RUNTIME_VARS.CONF_DIR, "minion")) as rfh:
config_defaults = yaml.deserialize(rfh.read())
config_defaults["hosts.file"] = os.path.join(RUNTIME_VARS.TMP, "hosts")
config_defaults["aliases.file"] = os.path.join(RUNTIME_VARS.TMP, "aliases")
config_defaults["transport"] = salt_master_factory.config["transport"]
config_overrides = {
"file_roots": salt_master_factory.config["file_roots"].copy(),
"pillar_roots": salt_master_factory.config["pillar_roots"].copy(),
}
virtualenv_binary = get_virtualenv_binary_path()
if virtualenv_binary:
config_overrides["venv_bin"] = virtualenv_binary
factory = salt_master_factory.get_salt_minion_daemon(
"minion",
config_defaults=config_defaults,
config_overrides=config_overrides,
extra_cli_arguments_after_first_start_failure=["--log-level=debug"],
)
factory.register_after_terminate_callback(
pytest.helpers.remove_stale_minion_key, salt_master_factory, factory.id
)
return factory
@pytest.fixture(scope="session")
def salt_sub_minion_factory(salt_master_factory):
with salt.utils.files.fopen(
os.path.join(RUNTIME_VARS.CONF_DIR, "sub_minion")
) as rfh:
config_defaults = yaml.deserialize(rfh.read())
config_defaults["hosts.file"] = os.path.join(RUNTIME_VARS.TMP, "hosts")
config_defaults["aliases.file"] = os.path.join(RUNTIME_VARS.TMP, "aliases")
config_defaults["transport"] = salt_master_factory.config["transport"]
config_overrides = {
"file_roots": salt_master_factory.config["file_roots"].copy(),
"pillar_roots": salt_master_factory.config["pillar_roots"].copy(),
}
virtualenv_binary = get_virtualenv_binary_path()
if virtualenv_binary:
config_overrides["venv_bin"] = virtualenv_binary
factory = salt_master_factory.get_salt_minion_daemon(
"sub_minion",
config_defaults=config_defaults,
config_overrides=config_overrides,
extra_cli_arguments_after_first_start_failure=["--log-level=debug"],
)
factory.register_after_terminate_callback(
pytest.helpers.remove_stale_minion_key, salt_master_factory, factory.id
)
return factory
@pytest.fixture(scope="session")
def salt_proxy_factory(salt_factories, salt_master_factory):
proxy_minion_id = "proxytest"
root_dir = salt_factories.get_root_dir_for_daemon(proxy_minion_id)
conf_dir = root_dir / "conf"
conf_dir.mkdir(parents=True, exist_ok=True)
RUNTIME_VARS.TMP_PROXY_CONF_DIR = str(conf_dir)
with salt.utils.files.fopen(os.path.join(RUNTIME_VARS.CONF_DIR, "proxy")) as rfh:
config_defaults = yaml.deserialize(rfh.read())
config_defaults["root_dir"] = str(root_dir)
config_defaults["hosts.file"] = os.path.join(RUNTIME_VARS.TMP, "hosts")
config_defaults["aliases.file"] = os.path.join(RUNTIME_VARS.TMP, "aliases")
config_defaults["transport"] = salt_master_factory.config["transport"]
factory = salt_master_factory.get_salt_proxy_minion_daemon(
proxy_minion_id,
config_defaults=config_defaults,
extra_cli_arguments_after_first_start_failure=["--log-level=debug"],
)
factory.register_after_terminate_callback(
pytest.helpers.remove_stale_minion_key, salt_master_factory, factory.id
)
return factory
@pytest.fixture(scope="session")
def salt_cli(salt_master_factory):
return salt_master_factory.get_salt_cli()
@pytest.fixture(scope="session")
def salt_cp_cli(salt_master_factory):
return salt_master_factory.get_salt_cp_cli()
@pytest.fixture(scope="session")
def salt_key_cli(salt_master_factory):
return salt_master_factory.get_salt_key_cli()
@pytest.fixture(scope="session")
def salt_run_cli(salt_master_factory):
return salt_master_factory.get_salt_run_cli()
@pytest.fixture(scope="session")
def salt_ssh_cli(salt_master_factory):
return salt_master_factory.get_salt_ssh_cli()
@pytest.fixture(scope="session")
def salt_call_cli(salt_minion_factory):
return salt_minion_factory.get_salt_call_cli()
@pytest.fixture(scope="session", autouse=True)
def bridge_pytest_and_runtests(
reap_stray_processes,
salt_factories,
salt_syndic_master_factory,
salt_syndic_factory,
salt_master_factory,
salt_minion_factory,
salt_sub_minion_factory,
sshd_config_dir,
):
# Make sure unittest2 uses the pytest generated configuration
RUNTIME_VARS.RUNTIME_CONFIGS["master"] = freeze(salt_master_factory.config)
RUNTIME_VARS.RUNTIME_CONFIGS["minion"] = freeze(salt_minion_factory.config)
RUNTIME_VARS.RUNTIME_CONFIGS["sub_minion"] = freeze(salt_sub_minion_factory.config)
RUNTIME_VARS.RUNTIME_CONFIGS["syndic_master"] = freeze(
salt_syndic_master_factory.config
)
RUNTIME_VARS.RUNTIME_CONFIGS["syndic"] = freeze(salt_syndic_factory.config)
RUNTIME_VARS.RUNTIME_CONFIGS["client_config"] = freeze(
salt.config.client_config(salt_master_factory.config["conf_file"])
)
# Make sure unittest2 classes know their paths
RUNTIME_VARS.TMP_ROOT_DIR = str(salt_factories.root_dir.resolve())
RUNTIME_VARS.TMP_CONF_DIR = os.path.dirname(salt_master_factory.config["conf_file"])
RUNTIME_VARS.TMP_MINION_CONF_DIR = os.path.dirname(
salt_minion_factory.config["conf_file"]
)
RUNTIME_VARS.TMP_SUB_MINION_CONF_DIR = os.path.dirname(
salt_sub_minion_factory.config["conf_file"]
)
RUNTIME_VARS.TMP_SYNDIC_MASTER_CONF_DIR = os.path.dirname(
salt_syndic_master_factory.config["conf_file"]
)
RUNTIME_VARS.TMP_SYNDIC_MINION_CONF_DIR = os.path.dirname(
salt_syndic_factory.config["conf_file"]
)
RUNTIME_VARS.TMP_SSH_CONF_DIR = str(sshd_config_dir)
@pytest.fixture(scope="session")
def sshd_config_dir(salt_factories):
config_dir = salt_factories.get_root_dir_for_daemon("sshd")
yield config_dir
shutil.rmtree(str(config_dir), ignore_errors=True)
@pytest.fixture(scope="module")
def sshd_server(salt_factories, sshd_config_dir, salt_master):
sshd_config_dict = {
"Protocol": "2",
# Turn strict modes off so that we can operate in /tmp
"StrictModes": "no",
# Logging
"SyslogFacility": "AUTH",
"LogLevel": "INFO",
# Authentication:
"LoginGraceTime": "120",
"PermitRootLogin": "without-password",
"PubkeyAuthentication": "yes",
# Don't read the user's ~/.rhosts and ~/.shosts files
"IgnoreRhosts": "yes",
"HostbasedAuthentication": "no",
# To enable empty passwords, change to yes (NOT RECOMMENDED)
"PermitEmptyPasswords": "no",
# Change to yes to enable challenge-response passwords (beware issues with
# some PAM modules and threads)
"ChallengeResponseAuthentication": "no",
# Change to no to disable tunnelled clear text passwords
"PasswordAuthentication": "no",
"X11Forwarding": "no",
"X11DisplayOffset": "10",
"PrintMotd": "no",
"PrintLastLog": "yes",
"TCPKeepAlive": "yes",
"AcceptEnv": "LANG LC_*",
"Subsystem": "sftp /usr/lib/openssh/sftp-server",
"UsePAM": "yes",
}
factory = salt_factories.get_sshd_daemon(
sshd_config_dict=sshd_config_dict, config_dir=sshd_config_dir,
)
# We also need a salt-ssh roster config file
roster_path = pathlib.Path(salt_master.config_dir) / "roster"
roster_contents = textwrap.dedent(
"""\
localhost:
host: 127.0.0.1
port: {}
user: {}
mine_functions:
test.arg: ['itworked']
""".format(
factory.listen_port, RUNTIME_VARS.RUNNING_TESTS_USER
)
)
log.debug(
"Writing to configuration file %s. Configuration:\n%s",
roster_path,
roster_contents,
)
with salt.utils.files.fopen(str(roster_path), "w") as wfh:
wfh.write(roster_contents)
with factory.started():
yield factory
if roster_path.exists():
roster_path.unlink()
# <---- Salt Factories -----------------------------------------------------------------------------------------------
# ----- From Filenames Test Selection ------------------------------------------------------------------------------->
def _match_to_test_file(match):
parts = match.split(".")

View file

@ -4,9 +4,6 @@
Integration tests PyTest configuration/fixtures
"""
# pylint: disable=unused-argument,redefined-outer-name
import logging
import pytest
@ -14,79 +11,36 @@ import pytest
log = logging.getLogger(__name__)
# @pytest.fixture(scope='package')
# def salt_syndic_master(request, salt_factories):
# return salt_factories.spawn_master(request, 'syndic_master', order_masters=True)
# @pytest.fixture(scope='package')
# def salt_syndic(request, salt_factories, salt_syndic_master):
# return salt_factories.spawn_syndic(request, 'syndic', master_of_masters_id='syndic_master')
# @pytest.fixture(scope='package')
# def salt_master(request, salt_factories, salt_syndic_master):
# return salt_factories.spawn_master(request, 'master', master_of_masters_id='syndic_master')
@pytest.fixture(scope="package")
def salt_master(request, salt_factories, salt_master_config):
return salt_factories.spawn_master(request, "master")
@pytest.fixture(scope="package")
def salt_minion(request, salt_factories, salt_master, salt_minion_config):
proc = salt_factories.spawn_minion(request, "minion", master_id="master")
# Sync All
salt_call_cli = salt_factories.get_salt_call_cli("minion")
ret = salt_call_cli.run("saltutil.sync_all", _timeout=120)
assert ret.exitcode == 0, ret
return proc
@pytest.fixture(scope="package")
def salt_sub_minion(request, salt_factories, salt_master, salt_sub_minion_config):
proc = salt_factories.spawn_minion(request, "sub_minion", master_id="master")
# Sync All
salt_call_cli = salt_factories.get_salt_call_cli("sub_minion")
ret = salt_call_cli.run("saltutil.sync_all", _timeout=120)
assert ret.exitcode == 0, ret
return proc
@pytest.fixture(scope="package", autouse=True)
def salt_master(salt_master_factory):
"""
A running salt-master fixture
"""
with salt_master_factory.started():
yield salt_master_factory
@pytest.fixture(scope="package", autouse=True)
def bridge_pytest_and_runtests_integration(
bridge_pytest_and_runtests,
salt_factories,
# salt_syndic_master,
# salt_syndic,
salt_master,
salt_minion,
):
yield
def salt_minion(salt_minion_factory):
"""
A running salt-minion fixture
"""
with salt_minion_factory.started():
# Sync All
salt_call_cli = salt_minion_factory.get_salt_call_cli()
ret = salt_call_cli.run("saltutil.sync_all", _timeout=120)
assert ret.exitcode == 0, ret
yield salt_minion_factory
@pytest.fixture(scope="package")
def salt_cli(salt_factories, salt_minion, salt_master):
return salt_factories.get_salt_cli(salt_master.config["id"])
@pytest.fixture(scope="package")
def salt_cp_cli(salt_factories, salt_minion, salt_master):
return salt_factories.get_salt_cp_cli(salt_master.config["id"])
@pytest.fixture(scope="package")
def salt_key_cli(salt_factories, salt_minion, salt_master):
return salt_factories.get_salt_key_cli(salt_master.config["id"])
@pytest.fixture(scope="package")
def salt_run_cli(salt_factories, salt_minion, salt_master):
return salt_factories.get_salt_run_cli(salt_master.config["id"])
@pytest.fixture(scope="package")
def salt_call_cli(salt_factories, salt_minion, salt_master):
return salt_factories.get_salt_call_cli(salt_minion.config["id"])
@pytest.fixture(scope="module")
def salt_sub_minion(salt_sub_minion_factory):
"""
A second running salt-minion fixture
"""
with salt_sub_minion_factory.started():
# Sync All
salt_call_cli = salt_sub_minion_factory.get_salt_call_cli()
ret = salt_call_cli.run("saltutil.sync_all", _timeout=120)
assert ret.exitcode == 0, ret
yield salt_sub_minion_factory

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
tests.integration.master.test_event_return
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -7,18 +6,17 @@ tests.integration.master.test_event_return
https://github.com/saltstack/salt/pull/54731
"""
from __future__ import absolute_import, print_function, unicode_literals
import logging
import os
import shutil
import subprocess
import sys
import time
import salt.ext.six as six
from salt.utils.nb_popen import NonBlockingPopen
from saltfactories.utils.ports import get_unused_localhost_port
from saltfactories.utils.processes.helpers import terminate_process
from saltfactories.utils.processes import terminate_process
from tests.support.cli_scripts import ScriptPathMixin
from tests.support.mixins import AdaptedConfigurationTestCaseMixin
from tests.support.runtests import RUNTIME_VARS
@ -57,6 +55,7 @@ class TestEventReturn(AdaptedConfigurationTestCaseMixin, ScriptPathMixin, TestCa
def test_master_startup(self):
proc = NonBlockingPopen(
[
sys.executable,
self.get_script_path("master"),
"-c",
RUNTIME_VARS.TMP_CONF_DIR,
@ -66,8 +65,8 @@ class TestEventReturn(AdaptedConfigurationTestCaseMixin, ScriptPathMixin, TestCa
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
out = six.b("")
err = six.b("")
out = b""
err = b""
# Testing this should never be longer than 1 minute
max_time = time.time() + 60
@ -83,17 +82,17 @@ class TestEventReturn(AdaptedConfigurationTestCaseMixin, ScriptPathMixin, TestCa
if _err:
err += _err
if six.b("DeprecationWarning: object() takes no parameters") in out:
if b"DeprecationWarning: object() takes no parameters" in out:
self.fail(
"'DeprecationWarning: object() takes no parameters' was seen in output"
)
if six.b("TypeError: object() takes no parameters") in out:
if b"TypeError: object() takes no parameters" in out:
self.fail(
"'TypeError: object() takes no parameters' was seen in output"
)
if six.b("Setting up the master communication server") in out:
if b"Setting up the master communication server" in out:
# We got past the place we need, stop the process
break

View file

@ -1,6 +1,3 @@
# encoding: utf-8
from __future__ import absolute_import, print_function, unicode_literals
import logging
import os
import time
@ -11,20 +8,20 @@ import salt.netapi
from salt.exceptions import EauthAuthenticationError
from tests.support.case import SSHCase
from tests.support.helpers import (
SKIP_IF_NOT_RUNNING_PYTEST,
SaveRequestsPostHandler,
Webserver,
requires_sshd_server,
slowTest,
)
from tests.support.mixins import AdaptedConfigurationTestCaseMixin
from tests.support.mock import patch
from tests.support.paths import TMP, TMP_CONF_DIR
from tests.support.runtests import RUNTIME_VARS
from tests.support.unit import TestCase, skipIf
log = logging.getLogger(__name__)
@pytest.mark.usefixtures("salt_sub_minion")
@pytest.mark.usefixtures("salt_master", "salt_sub_minion")
class NetapiClientTest(TestCase):
eauth_creds = {
"username": "saltdev_auto",
@ -36,9 +33,7 @@ class NetapiClientTest(TestCase):
"""
Set up a NetapiClient instance
"""
opts = salt.config.client_config(
os.path.join(RUNTIME_VARS.TMP_CONF_DIR, "master")
)
opts = AdaptedConfigurationTestCaseMixin.get_config("client_config").copy()
self.netapi = salt.netapi.NetapiClient(opts)
def tearDown(self):
@ -118,9 +113,7 @@ class NetapiClientTest(TestCase):
self.maxDiff = None
self.assertTrue(
set(["master.pem", "master.pub"]).issubset(
set(ret["data"]["return"]["local"])
)
{"master.pem", "master.pub"}.issubset(set(ret["data"]["return"]["local"]))
)
@slowTest
@ -166,7 +159,8 @@ class NetapiClientTest(TestCase):
ret = self.netapi.run(low)
@requires_sshd_server
@SKIP_IF_NOT_RUNNING_PYTEST
@pytest.mark.requires_sshd_server
class NetapiSSHClientTest(SSHCase):
eauth_creds = {
"username": "saltdev_auto",
@ -178,10 +172,10 @@ class NetapiSSHClientTest(SSHCase):
"""
Set up a NetapiClient instance
"""
opts = salt.config.client_config(os.path.join(TMP_CONF_DIR, "master"))
opts = AdaptedConfigurationTestCaseMixin.get_config("client_config").copy()
self.netapi = salt.netapi.NetapiClient(opts)
self.priv_file = os.path.join(RUNTIME_VARS.TMP_CONF_DIR, "key_test")
self.priv_file = os.path.join(RUNTIME_VARS.TMP_SSH_CONF_DIR, "client_key")
self.rosters = os.path.join(RUNTIME_VARS.TMP_CONF_DIR)
# Initialize salt-ssh
@ -234,7 +228,7 @@ class NetapiSSHClientTest(SSHCase):
@slowTest
def test_ssh_unauthenticated_raw_shell_curl(self):
fun = "-o ProxyCommand curl {0}".format(self.post_web_root)
fun = "-o ProxyCommand curl {}".format(self.post_web_root)
low = {"client": "ssh", "tgt": "localhost", "fun": fun, "raw_shell": True}
ret = None
@ -247,8 +241,8 @@ class NetapiSSHClientTest(SSHCase):
@slowTest
def test_ssh_unauthenticated_raw_shell_touch(self):
badfile = os.path.join(TMP, "badfile.txt")
fun = "-o ProxyCommand touch {0}".format(badfile)
badfile = os.path.join(RUNTIME_VARS.TMP, "badfile.txt")
fun = "-o ProxyCommand touch {}".format(badfile)
low = {"client": "ssh", "tgt": "localhost", "fun": fun, "raw_shell": True}
ret = None
@ -261,8 +255,8 @@ class NetapiSSHClientTest(SSHCase):
@slowTest
def test_ssh_authenticated_raw_shell_disabled(self):
badfile = os.path.join(TMP, "badfile.txt")
fun = "-o ProxyCommand touch {0}".format(badfile)
badfile = os.path.join(RUNTIME_VARS.TMP, "badfile.txt")
fun = "-o ProxyCommand touch {}".format(badfile)
low = {"client": "ssh", "tgt": "localhost", "fun": fun, "raw_shell": True}
low.update(self.eauth_creds)

View file

@ -1,46 +1,17 @@
# -*- coding: utf-8 -*-
"""
tests.integration.proxy.conftest
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Proxy related fixtures
"""
from __future__ import absolute_import, unicode_literals
import logging
import os
import pytest
import salt.utils.files
from salt.serializers import yaml
from tests.support.runtests import RUNTIME_VARS
log = logging.getLogger(__name__)
@pytest.fixture(scope="package", autouse=True)
def salt_proxy(request, salt_factories, salt_master):
proxy_minion_id = "proxytest"
root_dir = salt_factories._get_root_dir_for_daemon(proxy_minion_id)
conf_dir = root_dir.join("conf").ensure(dir=True)
RUNTIME_VARS.TMP_PROXY_CONF_DIR = conf_dir.strpath
with salt.utils.files.fopen(os.path.join(RUNTIME_VARS.CONF_DIR, "proxy")) as rfh:
config_defaults = yaml.deserialize(rfh.read())
config_defaults["hosts.file"] = os.path.join(RUNTIME_VARS.TMP, "hosts")
config_defaults["aliases.file"] = os.path.join(RUNTIME_VARS.TMP, "aliases")
config_defaults["transport"] = request.config.getoption("--transport")
config_defaults["root_dir"] = root_dir
yield salt_factories.spawn_proxy_minion(
request, proxy_minion_id, master_id="master", config_defaults=config_defaults
)
proxy_key_file = os.path.join(
salt_master.config["pki_dir"], "minions", proxy_minion_id
)
log.debug("Proxy minion %r KEY FILE: %s", proxy_minion_id, proxy_key_file)
if os.path.exists(proxy_key_file):
os.unlink(proxy_key_file)
else:
log.warning("The proxy minion key was not found at %s", proxy_key_file)
def salt_proxy(salt_proxy):
return salt_proxy

View file

@ -1,8 +1,6 @@
# -*- coding: utf-8 -*-
"""
salt-ssh testing
"""
from __future__ import absolute_import, print_function, unicode_literals
import os
import shutil
@ -17,6 +15,10 @@ class SSHTest(SSHCase):
Test general salt-ssh functionality
"""
def setUp(self):
thin_dir = self.run_function("config.get", ["thin_dir"], wipe=False)
self.addCleanup(shutil.rmtree, thin_dir, ignore_errors=True)
@slowTest
def test_ping(self):
"""
@ -43,15 +45,7 @@ class SSHTest(SSHCase):
path = "/pathdoesnotexist/"
roster = os.path.join(RUNTIME_VARS.TMP, "roster-set-path")
self.custom_roster(
roster, data={"set_path": "$PATH:/usr/local/bin/:{0}".format(path)}
roster, data={"set_path": "$PATH:/usr/local/bin/:{}".format(path)}
)
ret = self.run_function("environ.get", ["PATH"], roster_file=roster)
assert path in ret
def tearDown(self):
"""
make sure to clean up any old ssh directories
"""
salt_dir = self.run_function("config.get", ["thin_dir"], wipe=False)
if os.path.exists(salt_dir):
shutil.rmtree(salt_dir)

View file

@ -1,25 +1,20 @@
# -*- coding: utf-8 -*-
"""
Test AnsibleGate State Module
"""
from __future__ import absolute_import, print_function, unicode_literals
# Import python libraries
import os
import shutil
import tempfile
# Import salt libraries
import pytest
import salt.utils.files
import salt.utils.path
import yaml
# Import testing libraries
from tests.support.case import ModuleCase
from tests.support.helpers import (
SKIP_IF_NOT_RUNNING_PYTEST,
destructiveTest,
flaky,
requires_sshd_server,
requires_system_grains,
)
from tests.support.mixins import SaltReturnAssertsMixin
@ -27,8 +22,9 @@ from tests.support.runtests import RUNTIME_VARS
from tests.support.unit import SkipTest, skipIf
@SKIP_IF_NOT_RUNNING_PYTEST
@destructiveTest
@requires_sshd_server
@pytest.mark.requires_sshd_server
@skipIf(
not salt.utils.path.which("ansible-playbook"), "ansible-playbook is not installed"
)
@ -46,7 +42,7 @@ class AnsiblePlaybooksTestCase(ModuleCase, SaltReturnAssertsMixin):
)
def setUp(self):
priv_file = os.path.join(RUNTIME_VARS.TMP_CONF_DIR, "key_test")
priv_file = os.path.join(RUNTIME_VARS.TMP_SSH_CONF_DIR, "client_key")
data = {
"all": {
"hosts": {

View file

@ -1,10 +1,8 @@
# -*- coding: utf-8 -*-
"""
Classes for starting/stopping/status salt daemons, auxiliary
scripts, generic commands.
"""
from __future__ import absolute_import
import atexit
import copy
@ -28,12 +26,7 @@ import salt.utils.platform
import salt.utils.process
import salt.utils.psutil_compat as psutils
import salt.utils.yaml
from salt.ext import six
from salt.ext.six.moves import range
from saltfactories.utils.processes.helpers import (
terminate_process,
terminate_process_list,
)
from saltfactories.utils.processes import terminate_process, terminate_process_list
from tests.support.cli_scripts import ScriptPathMixin
from tests.support.runtests import RUNTIME_VARS
from tests.support.unit import TestCase
@ -74,12 +67,12 @@ class TestProgramMeta(type):
dirtree.update(attrs.get("dirtree", []))
attrs["dirtree"] = dirtree
return super(TestProgramMeta, mcs).__new__(mcs, name, bases, attrs)
return super().__new__(mcs, name, bases, attrs)
# pylint: disable=too-many-instance-attributes
@pytest.mark.windows_whitelisted
class TestProgram(six.with_metaclass(TestProgramMeta, object)):
class TestProgram(metaclass=TestProgramMeta):
"""
Set up an arbitrary executable to run.
@ -89,14 +82,14 @@ class TestProgram(six.with_metaclass(TestProgramMeta, object)):
empty_config = ""
config_file = ""
config_attrs = set(["name", "test_dir", "config_dirs"])
config_attrs = {"name", "test_dir", "config_dirs"}
config_vals = {}
config_base = ""
config_dir = os.path.join("etc")
configs = {}
config_types = (
str,
six.string_types,
(str,),
)
dirtree = [
@ -157,7 +150,7 @@ class TestProgram(six.with_metaclass(TestProgramMeta, object)):
if not self.name:
if not self.program:
raise ValueError(
'"{0}" object must specify "program" parameter'.format(
'"{}" object must specify "program" parameter'.format(
self.__class__.__name__
)
)
@ -229,7 +222,7 @@ class TestProgram(six.with_metaclass(TestProgramMeta, object)):
os.makedirs(self._parent_dir)
elif not os.path.isdir(self._parent_dir):
raise ValueError(
'Parent path "{0}" exists but is not a directory'.format(
'Parent path "{}" exists but is not a directory'.format(
self._parent_dir
)
)
@ -243,9 +236,7 @@ class TestProgram(six.with_metaclass(TestProgramMeta, object)):
with salt.utils.files.fopen(cpath, "w") as cfo:
cfg = self.config_stringify(config)
log.debug(
"Writing configuration for {0} to {1}:\n{2}".format(
self.name, cpath, cfg
)
"Writing configuration for {} to {}:\n{}".format(self.name, cpath, cfg)
)
cfo.write(cfg)
cfo.flush()
@ -267,7 +258,7 @@ class TestProgram(six.with_metaclass(TestProgramMeta, object)):
def config_subs(self):
"""Get the substitution values for use to generate the config"""
subs = dict([(attr, getattr(self, attr, None)) for attr in self.config_attrs])
subs = {attr: getattr(self, attr, None) for attr in self.config_attrs}
for key, val in self.config_vals.items():
subs[key] = val.format(**subs)
return subs
@ -296,17 +287,17 @@ class TestProgram(six.with_metaclass(TestProgramMeta, object)):
"""Create directory structure."""
subdirs = []
for branch in self.dirtree:
log.debug("checking dirtree: {0}".format(branch))
log.debug("checking dirtree: {}".format(branch))
if not branch:
continue
if isinstance(branch, six.string_types) and branch[0] == "&":
log.debug('Looking up dirtree branch "{0}"'.format(branch))
if isinstance(branch, str) and branch[0] == "&":
log.debug('Looking up dirtree branch "{}"'.format(branch))
try:
dirattr = getattr(self, branch[1:], None)
log.debug('dirtree "{0}" => "{1}"'.format(branch, dirattr))
log.debug('dirtree "{}" => "{}"'.format(branch, dirattr))
except AttributeError:
raise ValueError(
'Unable to find dirtree attribute "{0}" on object "{1}.name = {2}: {3}"'.format(
'Unable to find dirtree attribute "{}" on object "{}.name = {}: {}"'.format(
branch, self.__class__.__name__, self.name, dir(self),
)
)
@ -314,25 +305,25 @@ class TestProgram(six.with_metaclass(TestProgramMeta, object)):
if not dirattr:
continue
if isinstance(dirattr, six.string_types):
if isinstance(dirattr, str):
subdirs.append(dirattr)
elif hasattr(dirattr, "__iter__"):
subdirs.extend(dirattr)
else:
raise TypeError(
"Branch type of {0} in dirtree is unhandled".format(branch)
"Branch type of {} in dirtree is unhandled".format(branch)
)
elif isinstance(branch, six.string_types):
elif isinstance(branch, str):
subdirs.append(branch)
else:
raise TypeError(
"Branch type of {0} in dirtree is unhandled".format(branch)
"Branch type of {} in dirtree is unhandled".format(branch)
)
for subdir in subdirs:
path = self.abs_path(subdir)
if not os.path.exists(path):
log.debug("make_dirtree: {0}".format(path))
log.debug("make_dirtree: {}".format(path))
os.makedirs(path)
def setup(self, *args, **kwargs):
@ -435,11 +426,6 @@ class TestProgram(six.with_metaclass(TestProgramMeta, object)):
cmd_env = dict(os.environ)
cmd_env.update(env_delta)
if salt.utils.platform.is_windows() and six.PY2:
for k, v in cmd_env.items():
if isinstance(k, six.text_type) or isinstance(v, six.text_type):
cmd_env[k.encode("ascii")] = v.encode("ascii")
popen_kwargs = {
"shell": self.shell,
"stdout": subprocess.PIPE,
@ -486,7 +472,7 @@ class TestProgram(six.with_metaclass(TestProgramMeta, object)):
out = process.stdout.read().splitlines()
out.extend(
[
"Process took more than {0} seconds to complete. "
"Process took more than {} seconds to complete. "
"Process Killed!".format(timeout)
]
)
@ -574,10 +560,10 @@ class TestSaltProgramMeta(TestProgramMeta):
def __new__(mcs, name, bases, attrs):
if attrs.get("script") is None:
if "Salt" in name:
script = "salt-{0}".format(name.rsplit("Salt", 1)[-1].lower())
script = "salt-{}".format(name.rsplit("Salt", 1)[-1].lower())
if script is None:
raise AttributeError(
'Class {0}: Unable to set "script" attribute: class name'
'Class {}: Unable to set "script" attribute: class name'
' must include "Salt" or "script" must be explicitly set.'.format(
name
)
@ -599,20 +585,18 @@ class TestSaltProgramMeta(TestProgramMeta):
configs.update(attrs.get("configs", {}))
attrs["configs"] = configs
return super(TestSaltProgramMeta, mcs).__new__(mcs, name, bases, attrs)
return super().__new__(mcs, name, bases, attrs)
@pytest.mark.windows_whitelisted
class TestSaltProgram(
six.with_metaclass(TestSaltProgramMeta, TestProgram, ScriptPathMixin)
):
class TestSaltProgram(TestProgram, ScriptPathMixin, metaclass=TestSaltProgramMeta):
"""
This is like TestProgram but with some functions to run a salt-specific
auxiliary program.
"""
config_types = (dict,)
config_attrs = set(["log_dir", "script_dir"])
config_attrs = {"log_dir", "script_dir"}
pub_port = 4505
ret_port = 4506
@ -620,7 +604,7 @@ class TestSaltProgram(
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
connect = sock.bind(("localhost", port))
except (socket.error, OSError):
except OSError:
# these ports are already in use, use different ones
pub_port = 4606
ret_port = 4607
@ -653,7 +637,7 @@ class TestSaltProgram(
if len(args) < 2 and "program" not in kwargs:
# This is effectively a place-holder - it gets set correctly after super()
kwargs["program"] = self.script
super(TestSaltProgram, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
self.program = self.get_script_path(self.script)
def config_merge(self, base, overrides):
@ -667,7 +651,7 @@ class TestSaltProgram(
cfg_base = {}
for key, val in self.config_base.items():
_val = val
if val and isinstance(val, six.string_types) and val[0] == "&":
if val and isinstance(val, str) and val[0] == "&":
_val = getattr(self, val[1:], None)
if _val is None:
continue
@ -676,13 +660,13 @@ class TestSaltProgram(
cfg = {}
for key, val in self.configs.get(config, {}).get("map", {}).items():
_val = val
if val and isinstance(val, six.string_types) and val[0] == "&":
if val and isinstance(val, str) and val[0] == "&":
_val = getattr(self, val[1:], None)
if _val is None:
continue
cfg[key] = _val
cfg = self.config_merge(cfg_base, cfg)
log.debug("Generated config => {0}".format(cfg))
log.debug("Generated config => {}".format(cfg))
return cfg
def config_stringify(self, config):
@ -690,7 +674,7 @@ class TestSaltProgram(
subs = self.config_subs()
cfg = {}
for key, val in self.config_get(config).items():
if isinstance(val, six.string_types):
if isinstance(val, str):
cfg[key] = val.format(**subs)
else:
cfg[key] = val
@ -701,7 +685,7 @@ class TestSaltProgram(
args = kwargs.setdefault("args", [])
if "-c" not in args and "--config-dir" not in args:
args.extend(["--config-dir", self.abs_path(self.config_dir)])
return super(TestSaltProgram, self).run(**kwargs)
return super().run(**kwargs)
@pytest.mark.windows_whitelisted
@ -728,7 +712,7 @@ class TestProgramSaltRun(TestSaltProgram):
def __init__(self, *args, **kwargs):
cfgb = kwargs.setdefault("config_base", {})
_ = cfgb.setdefault("user", getpass.getuser())
super(TestProgramSaltRun, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
@pytest.mark.windows_whitelisted
@ -749,14 +733,14 @@ class TestDaemon(TestProgram):
self.script = kwargs.pop("script", self.script)
self.pid_file = kwargs.pop(
"pid_file",
self.pid_file if self.pid_file else "{0}.pid".format(self.script),
self.pid_file if self.pid_file else "{}.pid".format(self.script),
)
self.pid_dir = kwargs.pop("pid_dir", self.pid_dir)
self._shutdown = False
if not args and "program" not in kwargs:
# This is effectively a place-holder - it gets set correctly after super()
kwargs["program"] = self.script
super(TestDaemon, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
@property
def pid_path(self):
@ -785,7 +769,7 @@ class TestDaemon(TestProgram):
return pid
if endtime < time.time():
raise TimeoutError(
'Timeout waiting for "{0}" pid in "{1}"'.format(
'Timeout waiting for "{}" pid in "{}"'.format(
self.name, self.abs_path(self.pid_path)
)
)
@ -805,55 +789,27 @@ class TestDaemon(TestProgram):
def find_orphans(self, cmdline):
"""Find orphaned processes matching the specified cmdline"""
ret = []
if six.PY3:
cmdline = " ".join(cmdline)
for proc in psutils.process_iter():
try:
for item in proc.cmdline():
if cmdline in item:
ret.append(proc)
except psutils.NoSuchProcess:
# Process exited between when process_iter was invoked and
# when we tried to invoke this instance's cmdline() func.
cmdline = " ".join(cmdline)
for proc in psutils.process_iter():
try:
for item in proc.cmdline():
if cmdline in item:
ret.append(proc)
except psutils.NoSuchProcess:
# Process exited between when process_iter was invoked and
# when we tried to invoke this instance's cmdline() func.
continue
except psutils.AccessDenied:
# We might get access denied if not running as root
if not salt.utils.platform.is_windows():
pinfo = proc.as_dict(attrs=["pid", "name", "username"])
log.error(
"Unable to access process %s, " "running command %s as user %s",
pinfo["pid"],
pinfo["name"],
pinfo["username"],
)
continue
except psutils.AccessDenied:
# We might get access denied if not running as root
if not salt.utils.platform.is_windows():
pinfo = proc.as_dict(attrs=["pid", "name", "username"])
log.error(
"Unable to access process %s, "
"running command %s as user %s",
pinfo["pid"],
pinfo["name"],
pinfo["username"],
)
continue
else:
cmd_len = len(cmdline)
for proc in psutils.process_iter():
try:
proc_cmdline = proc.cmdline()
except psutils.NoSuchProcess:
# Process exited between when process_iter was invoked and
# when we tried to invoke this instance's cmdline() func.
continue
except psutils.AccessDenied:
# We might get access denied if not running as root
if not salt.utils.platform.is_windows():
pinfo = proc.as_dict(attrs=["pid", "name", "username"])
log.error(
"Unable to access process %s, "
"running command %s as user %s",
pinfo["pid"],
pinfo["name"],
pinfo["username"],
)
continue
if any(
(cmdline == proc_cmdline[n : n + cmd_len])
for n in range(len(proc_cmdline) - cmd_len + 1)
):
ret.append(proc)
return ret
def shutdown(self, signum=signal.SIGTERM, timeout=10, wait_for_orphans=0):
@ -890,13 +846,11 @@ class TestDaemon(TestProgram):
# Shutdown if not alreadt shutdown
self.shutdown()
super(TestDaemon, self).cleanup(*args, **kwargs)
super().cleanup(*args, **kwargs)
@pytest.mark.windows_whitelisted
class TestSaltDaemon(
six.with_metaclass(TestSaltProgramMeta, TestDaemon, TestSaltProgram)
):
class TestSaltDaemon(TestDaemon, TestSaltProgram, metaclass=TestSaltProgramMeta):
"""
A class to run arbitrary salt daemons (master, minion, syndic, etc.)
"""
@ -913,7 +867,7 @@ class TestDaemonSaltMaster(TestSaltDaemon):
def __init__(self, *args, **kwargs):
cfgb = kwargs.setdefault("config_base", {})
_ = cfgb.setdefault("user", getpass.getuser())
super(TestDaemonSaltMaster, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
@pytest.mark.windows_whitelisted
@ -927,7 +881,7 @@ class TestDaemonSaltMinion(TestSaltDaemon):
def __init__(self, *args, **kwargs):
cfgb = kwargs.setdefault("config_base", {})
_ = cfgb.setdefault("user", getpass.getuser())
super(TestDaemonSaltMinion, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
@pytest.mark.windows_whitelisted
@ -951,7 +905,7 @@ class TestDaemonSaltSyndic(TestSaltDaemon):
def __init__(self, *args, **kwargs):
cfgb = kwargs.setdefault("config_base", {})
_ = cfgb.setdefault("user", getpass.getuser())
super(TestDaemonSaltSyndic, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
@pytest.mark.windows_whitelisted
@ -966,14 +920,14 @@ class TestDaemonSaltProxy(TestSaltDaemon):
def __init__(self, *args, **kwargs):
cfgb = kwargs.setdefault("config_base", {})
_ = cfgb.setdefault("user", getpass.getuser())
super(TestDaemonSaltProxy, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
def run(self, **kwargs):
if not kwargs.get("verbatim_args"):
args = kwargs.setdefault("args", [])
if "--proxyid" not in args:
args.extend(["--proxyid", self.name])
return super(TestDaemonSaltProxy, self).run(**kwargs)
return super().run(**kwargs)
@pytest.mark.windows_whitelisted
@ -986,14 +940,14 @@ class TestProgramCase(TestCase):
# Setup for scripts
if not getattr(self, "_test_dir", None):
self._test_dir = tempfile.mkdtemp(prefix="salt-testdaemon-")
super(TestProgramCase, self).setUp()
super().setUp()
def tearDown(self):
# shutdown for scripts
if self._test_dir and os.path.sep == self._test_dir[0]:
shutil.rmtree(self._test_dir)
self._test_dir = None
super(TestProgramCase, self).tearDown()
super().tearDown()
def assert_exit_status(
self, status, ex_status, message=None, stdout=None, stderr=None
@ -1003,13 +957,13 @@ class TestProgramCase(TestCase):
"""
ex_val = getattr(exitcodes, ex_status)
_message = "" if not message else " ({0})".format(message)
_stdout = "" if not stdout else "\nstdout: {0}".format(stdout)
_stderr = "" if not stderr else "\nstderr: {0}".format(stderr)
_message = "" if not message else " ({})".format(message)
_stdout = "" if not stdout else "\nstdout: {}".format(stdout)
_stderr = "" if not stderr else "\nstderr: {}".format(stderr)
self.assertEqual(
status,
ex_val,
"Exit status was {0}, must be {1} (salt.default.exitcodes.{2}){3}{4}{5}".format(
"Exit status was {}, must be {} (salt.default.exitcodes.{}){}{}{}".format(
status, ex_val, ex_status, _message, _stdout, _stderr,
),
)

View file

@ -7,6 +7,7 @@
import logging
import os
import pathlib
import shutil
import pytest
@ -19,14 +20,27 @@ log = logging.getLogger(__name__)
@pytest.fixture(scope="package")
def salt_mm_master_config(request, salt_factories):
root_dir = salt_factories._get_root_dir_for_daemon("mm-master")
def ext_pillar_file_tree():
pillar_file_tree = {
"root_dir": str(pathlib.Path(RUNTIME_VARS.PILLAR_DIR) / "base" / "file_tree"),
"follow_dir_links": False,
"keep_newline": True,
}
return {"file_tree": pillar_file_tree}
@pytest.fixture(scope="package")
def salt_mm_master(request, salt_factories, ext_pillar_file_tree):
with salt.utils.files.fopen(
os.path.join(RUNTIME_VARS.CONF_DIR, "mm_master")
) as rfh:
config_defaults = yaml.deserialize(rfh.read())
config_defaults["root_dir"] = root_dir.strpath
master_id = "mm-master"
root_dir = salt_factories.get_root_dir_for_daemon(master_id)
config_defaults["root_dir"] = str(root_dir)
config_defaults["ext_pillar"] = [ext_pillar_file_tree]
config_defaults["open_mode"] = True
config_defaults["transport"] = request.config.getoption("--transport")
config_overrides = {
@ -49,152 +63,125 @@ def salt_mm_master_config(request, salt_factories):
"prod": [RUNTIME_VARS.TMP_PRODENV_PILLAR_TREE],
},
}
return salt_factories.configure_master(
request,
"mm-master",
factory = salt_factories.get_salt_master_daemon(
master_id,
config_defaults=config_defaults,
config_overrides=config_overrides,
extra_cli_arguments_after_first_start_failure=["--log-level=debug"],
)
with factory.started():
yield factory
@pytest.fixture(scope="package")
def salt_mm_minion_config(request, salt_factories, salt_mm_master, salt_mm_sub_master):
def salt_mm_sub_master(salt_factories, salt_mm_master, ext_pillar_file_tree):
with salt.utils.files.fopen(
os.path.join(RUNTIME_VARS.CONF_DIR, "mm_sub_master")
) as rfh:
config_defaults = yaml.deserialize(rfh.read())
master_id = "mm-sub-master"
root_dir = salt_factories.get_root_dir_for_daemon(master_id)
config_defaults["root_dir"] = str(root_dir)
config_defaults["ext_pillar"] = [ext_pillar_file_tree]
config_defaults["open_mode"] = True
config_defaults["transport"] = salt_mm_master.config["transport"]
config_overrides = {
"file_roots": {
"base": [
RUNTIME_VARS.TMP_STATE_TREE,
os.path.join(RUNTIME_VARS.FILES, "file", "base"),
],
# Alternate root to test __env__ choices
"prod": [
RUNTIME_VARS.TMP_PRODENV_STATE_TREE,
os.path.join(RUNTIME_VARS.FILES, "file", "prod"),
],
},
"pillar_roots": {
"base": [
RUNTIME_VARS.TMP_PILLAR_TREE,
os.path.join(RUNTIME_VARS.FILES, "pillar", "base"),
],
"prod": [RUNTIME_VARS.TMP_PRODENV_PILLAR_TREE],
},
}
factory = salt_factories.get_salt_master_daemon(
master_id,
config_defaults=config_defaults,
config_overrides=config_overrides,
extra_cli_arguments_after_first_start_failure=["--log-level=debug"],
)
# The secondary salt master depends on the primarily salt master fixture
# because we need to clone the keys
for keyfile in ("master.pem", "master.pub"):
shutil.copyfile(
os.path.join(salt_mm_master.config["pki_dir"], keyfile),
os.path.join(factory.config["pki_dir"], keyfile),
)
with factory.started():
yield factory
@pytest.fixture(scope="package")
def salt_mm_minion(salt_mm_master, salt_mm_sub_master):
with salt.utils.files.fopen(
os.path.join(RUNTIME_VARS.CONF_DIR, "mm_minion")
) as rfh:
config_defaults = yaml.deserialize(rfh.read())
config_defaults["hosts.file"] = os.path.join(RUNTIME_VARS.TMP, "hosts")
config_defaults["aliases.file"] = os.path.join(RUNTIME_VARS.TMP, "aliases")
config_defaults["transport"] = request.config.getoption("--transport")
config_defaults["transport"] = salt_mm_master.config["transport"]
mm_master_port = salt_mm_master.config["ret_port"]
mm_sub_master_port = salt_mm_sub_master.config["ret_port"]
config_overrides = {
"master_port": "",
"master": [
"localhost:{}".format(mm_master_port),
"localhost:{}".format(mm_sub_master_port),
],
"test.foo": "baz",
}
return salt_factories.configure_minion(
request,
factory = salt_mm_master.get_salt_minion_daemon(
"mm-minion",
master_id=salt_mm_master.config["id"],
config_defaults=config_defaults,
config_overrides=config_overrides,
extra_cli_arguments_after_first_start_failure=["--log-level=debug"],
)
with factory.started():
yield factory
@pytest.fixture(scope="package")
def salt_mm_sub_master_config(request, salt_factories, salt_mm_master):
with salt.utils.files.fopen(
os.path.join(RUNTIME_VARS.CONF_DIR, "mm_sub_master")
) as rfh:
config_defaults = yaml.deserialize(rfh.read())
root_dir = salt_factories._get_root_dir_for_daemon("mm-master")
config_defaults["root_dir"] = root_dir.strpath
config_defaults["transport"] = request.config.getoption("--transport")
config_overrides = {
"file_roots": {
"base": [
RUNTIME_VARS.TMP_STATE_TREE,
os.path.join(RUNTIME_VARS.FILES, "file", "base"),
],
# Alternate root to test __env__ choices
"prod": [
RUNTIME_VARS.TMP_PRODENV_STATE_TREE,
os.path.join(RUNTIME_VARS.FILES, "file", "prod"),
],
},
"pillar_roots": {
"base": [
RUNTIME_VARS.TMP_PILLAR_TREE,
os.path.join(RUNTIME_VARS.FILES, "pillar", "base"),
],
"prod": [RUNTIME_VARS.TMP_PRODENV_PILLAR_TREE],
},
}
return salt_factories.configure_master(
request,
"mm-sub-master",
config_defaults=config_defaults,
config_overrides=config_overrides,
)
@pytest.fixture(scope="package")
def salt_mm_sub_minion_config(
request, salt_factories, salt_mm_master, salt_mm_sub_master
):
def salt_mm_sub_minion(salt_mm_master, salt_mm_sub_master):
with salt.utils.files.fopen(
os.path.join(RUNTIME_VARS.CONF_DIR, "mm_sub_minion")
) as rfh:
config_defaults = yaml.deserialize(rfh.read())
config_defaults["hosts.file"] = os.path.join(RUNTIME_VARS.TMP, "hosts")
config_defaults["aliases.file"] = os.path.join(RUNTIME_VARS.TMP, "aliases")
config_defaults["transport"] = request.config.getoption("--transport")
config_defaults["transport"] = salt_mm_master.config["transport"]
mm_master_port = salt_mm_master.config["ret_port"]
mm_sub_master_port = salt_mm_sub_master.config["ret_port"]
config_overrides = {
"master_port": "",
"master": [
"localhost:{}".format(mm_master_port),
"localhost:{}".format(mm_sub_master_port),
],
"test.foo": "baz",
}
return salt_factories.configure_minion(
request,
factory = salt_mm_sub_master.get_salt_minion_daemon(
"mm-sub-minion",
master_id=salt_mm_sub_master.config["id"],
config_defaults=config_defaults,
config_overrides=config_overrides,
extra_cli_arguments_after_first_start_failure=["--log-level=debug"],
)
@pytest.fixture(scope="package")
def salt_mm_master(request, salt_factories, salt_mm_master_config):
return salt_factories.spawn_master(request, "mm-master")
@pytest.fixture(scope="package")
def salt_mm_sub_master(
request, salt_factories, salt_mm_master, salt_mm_sub_master_config
):
# The secondary salt master depends on the primarily salt master fixture
# because we need to clone the keys
for keyfile in ("master.pem", "master.pub"):
shutil.copyfile(
os.path.join(salt_mm_master.config["pki_dir"], keyfile),
os.path.join(salt_mm_sub_master_config["pki_dir"], keyfile),
)
return salt_factories.spawn_master(request, "mm-sub-master")
@pytest.fixture(scope="package")
def salt_mm_minion(
request, salt_factories, salt_mm_master, salt_mm_sub_master, salt_mm_minion_config
):
return salt_factories.spawn_minion(
request, "mm-minion", master_id=salt_mm_master.config["id"]
)
@pytest.fixture(scope="package")
def salt_mm_sub_minion(
request,
salt_factories,
salt_mm_master,
salt_mm_sub_master,
salt_mm_sub_minion_config,
):
return salt_factories.spawn_minion(
request, "mm-sub-minion", master_id=salt_mm_sub_master.config["id"]
)
with factory.started():
yield factory
@pytest.fixture(scope="package", autouse=True)
@ -204,10 +191,9 @@ def bridge_pytest_and_runtests( # pylint: disable=function-redefined
prod_env_state_tree_root_dir,
base_env_pillar_tree_root_dir,
prod_env_pillar_tree_root_dir,
salt_factories,
salt_mm_master,
salt_mm_minion,
salt_mm_sub_master,
salt_mm_minion,
salt_mm_sub_minion,
):
# Make sure unittest2 uses the pytest generated configuration

227
tests/pytests/conftest.py Normal file
View file

@ -0,0 +1,227 @@
"""
tests.pytests.conftest
~~~~~~~~~~~~~~~~~~~~~~
"""
import logging
import os
import shutil
import stat
import pytest
import salt.utils.files
import salt.utils.platform
from salt.serializers import yaml
from saltfactories.utils import random_string
from tests.support.helpers import get_virtualenv_binary_path
from tests.support.runtests import RUNTIME_VARS
log = logging.getLogger(__name__)
@pytest.fixture(scope="session")
def salt_master_factory(
request,
salt_factories,
base_env_state_tree_root_dir,
base_env_pillar_tree_root_dir,
prod_env_state_tree_root_dir,
prod_env_pillar_tree_root_dir,
):
master_id = random_string("master-")
root_dir = salt_factories.get_root_dir_for_daemon(master_id)
conf_dir = root_dir / "conf"
conf_dir.mkdir(exist_ok=True)
with salt.utils.files.fopen(os.path.join(RUNTIME_VARS.CONF_DIR, "master")) as rfh:
config_defaults = yaml.deserialize(rfh.read())
tests_known_hosts_file = str(root_dir / "salt_ssh_known_hosts")
with salt.utils.files.fopen(tests_known_hosts_file, "w") as known_hosts:
known_hosts.write("")
config_defaults["root_dir"] = str(root_dir)
config_defaults["known_hosts_file"] = tests_known_hosts_file
config_defaults["syndic_master"] = "localhost"
config_defaults["transport"] = request.config.getoption("--transport")
config_defaults["reactor"] = [
{"salt/test/reactor": [os.path.join(RUNTIME_VARS.FILES, "reactor-test.sls")]}
]
config_overrides = {}
ext_pillar = []
if salt.utils.platform.is_windows():
ext_pillar.append(
{"cmd_yaml": "type {}".format(os.path.join(RUNTIME_VARS.FILES, "ext.yaml"))}
)
else:
ext_pillar.append(
{"cmd_yaml": "cat {}".format(os.path.join(RUNTIME_VARS.FILES, "ext.yaml"))}
)
ext_pillar.append(
{
"file_tree": {
"root_dir": os.path.join(RUNTIME_VARS.PILLAR_DIR, "base", "file_tree"),
"follow_dir_links": False,
"keep_newline": True,
}
}
)
config_overrides["pillar_opts"] = True
# We need to copy the extension modules into the new master root_dir or
# it will be prefixed by it
extension_modules_path = str(root_dir / "extension_modules")
if not os.path.exists(extension_modules_path):
shutil.copytree(
os.path.join(RUNTIME_VARS.FILES, "extension_modules"),
extension_modules_path,
)
# Copy the autosign_file to the new master root_dir
autosign_file_path = str(root_dir / "autosign_file")
shutil.copyfile(
os.path.join(RUNTIME_VARS.FILES, "autosign_file"), autosign_file_path
)
# all read, only owner write
autosign_file_permissions = (
stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH | stat.S_IWUSR
)
os.chmod(autosign_file_path, autosign_file_permissions)
config_overrides.update(
{
"ext_pillar": ext_pillar,
"extension_modules": extension_modules_path,
"file_roots": {
"base": [
str(base_env_state_tree_root_dir),
os.path.join(RUNTIME_VARS.FILES, "file", "base"),
],
# Alternate root to test __env__ choices
"prod": [
str(prod_env_state_tree_root_dir),
os.path.join(RUNTIME_VARS.FILES, "file", "prod"),
],
},
"pillar_roots": {
"base": [
str(base_env_pillar_tree_root_dir),
os.path.join(RUNTIME_VARS.FILES, "pillar", "base"),
],
"prod": [str(prod_env_pillar_tree_root_dir)],
},
}
)
# Let's copy over the test cloud config files and directories into the running master config directory
for entry in os.listdir(RUNTIME_VARS.CONF_DIR):
if not entry.startswith("cloud"):
continue
source = os.path.join(RUNTIME_VARS.CONF_DIR, entry)
dest = str(conf_dir / entry)
if os.path.isdir(source):
shutil.copytree(source, dest)
else:
shutil.copyfile(source, dest)
factory = salt_factories.get_salt_master_daemon(
master_id,
config_defaults=config_defaults,
config_overrides=config_overrides,
extra_cli_arguments_after_first_start_failure=["--log-level=debug"],
)
return factory
@pytest.fixture(scope="session")
def salt_minion_factory(salt_master_factory):
with salt.utils.files.fopen(os.path.join(RUNTIME_VARS.CONF_DIR, "minion")) as rfh:
config_defaults = yaml.deserialize(rfh.read())
config_defaults["hosts.file"] = os.path.join(RUNTIME_VARS.TMP, "hosts")
config_defaults["aliases.file"] = os.path.join(RUNTIME_VARS.TMP, "aliases")
config_defaults["transport"] = salt_master_factory.config["transport"]
config_overrides = {
"file_roots": salt_master_factory.config["file_roots"].copy(),
"pillar_roots": salt_master_factory.config["pillar_roots"].copy(),
}
virtualenv_binary = get_virtualenv_binary_path()
if virtualenv_binary:
config_overrides["venv_bin"] = virtualenv_binary
factory = salt_master_factory.get_salt_minion_daemon(
random_string("minion-"),
config_defaults=config_defaults,
config_overrides=config_overrides,
extra_cli_arguments_after_first_start_failure=["--log-level=debug"],
)
factory.register_after_terminate_callback(
pytest.helpers.remove_stale_minion_key, salt_master_factory, factory.id
)
return factory
@pytest.fixture(scope="session")
def salt_sub_minion_factory(salt_master_factory):
with salt.utils.files.fopen(
os.path.join(RUNTIME_VARS.CONF_DIR, "sub_minion")
) as rfh:
config_defaults = yaml.deserialize(rfh.read())
config_defaults["hosts.file"] = os.path.join(RUNTIME_VARS.TMP, "hosts")
config_defaults["aliases.file"] = os.path.join(RUNTIME_VARS.TMP, "aliases")
config_defaults["transport"] = salt_master_factory.config["transport"]
config_overrides = {
"file_roots": salt_master_factory.config["file_roots"].copy(),
"pillar_roots": salt_master_factory.config["pillar_roots"].copy(),
}
virtualenv_binary = get_virtualenv_binary_path()
if virtualenv_binary:
config_overrides["venv_bin"] = virtualenv_binary
factory = salt_master_factory.get_salt_minion_daemon(
random_string("sub-minion-"),
config_defaults=config_defaults,
config_overrides=config_overrides,
extra_cli_arguments_after_first_start_failure=["--log-level=debug"],
)
factory.register_after_terminate_callback(
pytest.helpers.remove_stale_minion_key, salt_master_factory, factory.id
)
return factory
@pytest.fixture(scope="session")
def salt_proxy_factory(salt_factories, salt_master_factory):
proxy_minion_id = random_string("proxytest-")
root_dir = salt_factories.get_root_dir_for_daemon(proxy_minion_id)
conf_dir = root_dir / "conf"
conf_dir.mkdir(parents=True, exist_ok=True)
RUNTIME_VARS.TMP_PROXY_CONF_DIR = str(conf_dir)
with salt.utils.files.fopen(os.path.join(RUNTIME_VARS.CONF_DIR, "proxy")) as rfh:
config_defaults = yaml.deserialize(rfh.read())
config_defaults["root_dir"] = str(root_dir)
config_defaults["hosts.file"] = os.path.join(RUNTIME_VARS.TMP, "hosts")
config_defaults["aliases.file"] = os.path.join(RUNTIME_VARS.TMP, "aliases")
config_defaults["transport"] = salt_master_factory.config["transport"]
config_defaults["user"] = salt_master_factory.config["user"]
factory = salt_master_factory.get_salt_proxy_minion_daemon(
proxy_minion_id,
config_defaults=config_defaults,
extra_cli_arguments_after_first_start_failure=["--log-level=debug"],
start_timeout=240,
)
factory.register_after_terminate_callback(
pytest.helpers.remove_stale_minion_key, salt_master_factory, factory.id
)
return factory
@pytest.fixture(scope="session")
def bridge_pytest_and_runtests():
"""
We're basically overriding the same fixture defined in tests/conftest.py
"""

View file

@ -1,51 +1,108 @@
"""
tests.pytests.integration.conftest
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PyTest fixtures
"""
import pytest
@pytest.fixture(scope="package")
def salt_master(request, salt_factories, salt_master_config):
return salt_factories.spawn_master(request, "master")
def salt_master(salt_master_factory):
"""
A running salt-master fixture
"""
with salt_master_factory.started():
yield salt_master_factory
@pytest.fixture(scope="package")
def salt_minion(request, salt_factories, salt_master, salt_minion_config):
proc = salt_factories.spawn_minion(request, "minion", master_id="master")
# Sync All
salt_call_cli = salt_factories.get_salt_call_cli("minion")
ret = salt_call_cli.run("saltutil.sync_all", _timeout=120)
assert ret.exitcode == 0, ret
return proc
def salt_minion(salt_master, salt_minion_factory):
"""
A running salt-minion fixture
"""
assert salt_master.is_running()
with salt_minion_factory.started():
# Sync All
salt_call_cli = salt_minion_factory.get_salt_call_cli()
ret = salt_call_cli.run("saltutil.sync_all", _timeout=120)
assert ret.exitcode == 0, ret
yield salt_minion_factory
@pytest.fixture(scope="module")
def salt_sub_minion(salt_master, salt_sub_minion_factory):
"""
A second running salt-minion fixture
"""
assert salt_master.is_running()
with salt_sub_minion_factory.started():
# Sync All
salt_call_cli = salt_sub_minion_factory.get_salt_call_cli()
ret = salt_call_cli.run("saltutil.sync_all", _timeout=120)
assert ret.exitcode == 0, ret
yield salt_sub_minion_factory
@pytest.fixture(scope="package")
def salt_sub_minion(request, salt_factories, salt_master, salt_sub_minion_config):
proc = salt_factories.spawn_minion(request, "sub_minion", master_id="master")
# Sync All
salt_call_cli = salt_factories.get_salt_call_cli("sub_minion")
ret = salt_call_cli.run("saltutil.sync_all", _timeout=120)
assert ret.exitcode == 0, ret
return proc
def salt_proxy(salt_master, salt_proxy_factory):
"""
A running salt-proxy fixture
"""
assert salt_master.is_running()
with salt_proxy_factory.started():
yield salt_proxy_factory
@pytest.fixture(scope="package")
def salt_cli(salt_factories, salt_minion, salt_master):
return salt_factories.get_salt_cli(salt_master.config["id"])
def salt_cli(salt_master):
"""
The ``salt`` CLI as a fixture against the running master
"""
assert salt_master.is_running()
return salt_master.get_salt_cli()
@pytest.fixture(scope="package")
def salt_cp_cli(salt_factories, salt_minion, salt_master):
return salt_factories.get_salt_cp_cli(salt_master.config["id"])
def salt_call_cli(salt_minion):
"""
The ``salt-call`` CLI as a fixture against the running minion
"""
assert salt_minion.is_running()
return salt_minion.get_salt_call_cli()
@pytest.fixture(scope="package")
def salt_key_cli(salt_factories, salt_minion, salt_master):
return salt_factories.get_salt_key_cli(salt_master.config["id"])
def salt_cp_cli(salt_master):
"""
The ``salt-cp`` CLI as a fixture against the running master
"""
assert salt_master.is_running()
return salt_master.get_salt_cp_cli()
@pytest.fixture(scope="package")
def salt_run_cli(salt_factories, salt_minion, salt_master):
return salt_factories.get_salt_run_cli(salt_master.config["id"])
def salt_key_cli(salt_master):
"""
The ``salt-key`` CLI as a fixture against the running master
"""
assert salt_master.is_running()
return salt_master.get_salt_key_cli()
@pytest.fixture(scope="package")
def salt_call_cli(salt_factories, salt_minion, salt_master):
return salt_factories.get_salt_call_cli(salt_minion.config["id"])
def salt_run_cli(salt_master):
"""
The ``salt-run`` CLI as a fixture against the running master
"""
assert salt_master.is_running()
return salt_master.get_salt_run_cli()
@pytest.fixture(scope="package")
def salt_ssh_cli(salt_master):
"""
The ``salt-ssh`` CLI as a fixture against the running master
"""
assert salt_master.is_running()
return salt_master.get_salt_ssh_cli()

View file

@ -2,17 +2,13 @@
Validate the virt module
"""
import logging
import pathlib
from numbers import Number
from xml.etree import ElementTree
import pytest
from saltfactories.utils import cli_scripts
from tests.support.helpers import skip_if_binaries_missing, slowTest
from tests.support.saltfactories_compat import (
ContainerFactory,
SaltVirtMinionContainerFactory,
)
from tests.support.virt import SaltVirtMinionContainerFactory
docker = pytest.importorskip("docker")
@ -26,7 +22,7 @@ def docker_client():
urllib3_connectionpool_handler.setLevel(logging.INFO)
try:
client = docker.from_env()
connectable = ContainerFactory.client_connectable(client)
connectable = SaltVirtMinionContainerFactory.client_connectable(client)
if connectable is not True: # pragma: no cover
pytest.skip(connectable)
client.images.pull("quay.io/rst0git/virt-minion")
@ -65,10 +61,7 @@ def virt_minion_0(
virt_minion_0_id,
virt_minion_1_id,
):
salt_master.id = salt_master.config["id"]
root_dir = pathlib.Path(
salt_factories._get_root_dir_for_daemon(virt_minion_0_id).strpath
)
root_dir = salt_factories.get_root_dir_for_daemon(virt_minion_0_id)
config_defaults = {
"root_dir": str(root_dir),
"id": virt_minion_0_id,
@ -102,6 +95,9 @@ def virt_minion_0(
}
},
)
factory.register_after_terminate_callback(
pytest.helpers.remove_stale_minion_key, salt_master, factory.id
)
with factory.started():
yield factory
@ -115,10 +111,7 @@ def virt_minion_1(
virt_minion_0_id,
virt_minion_1_id,
):
salt_master.id = salt_master.config["id"]
root_dir = pathlib.Path(
salt_factories._get_root_dir_for_daemon(virt_minion_1_id).strpath
)
root_dir = salt_factories.get_root_dir_for_daemon(virt_minion_1_id)
config_defaults = {
"root_dir": str(root_dir),
"id": virt_minion_1_id,
@ -152,13 +145,16 @@ def virt_minion_1(
}
},
)
factory.register_after_terminate_callback(
pytest.helpers.remove_stale_minion_key, salt_master, factory.id
)
with factory.started():
yield factory
@pytest.fixture(scope="module")
def salt_cli(salt_factories, salt_master, virt_minion_0, virt_minion_1):
return salt_factories.get_salt_cli(salt_master.config["id"])
def salt_cli(salt_master, virt_minion_0, virt_minion_1):
return salt_master.get_salt_cli()
@skip_if_binaries_missing("docker")

View file

@ -23,10 +23,11 @@ import textwrap
import time
from datetime import datetime, timedelta
import pytest
import salt.utils.files
from saltfactories.utils.processes.helpers import terminate_process
from saltfactories.utils.processes import terminate_process
from tests.support.cli_scripts import ScriptPathMixin
from tests.support.helpers import RedirectStdStreams, requires_sshd_server
from tests.support.helpers import SKIP_IF_NOT_RUNNING_PYTEST, RedirectStdStreams
from tests.support.mixins import ( # pylint: disable=unused-import
AdaptedConfigurationTestCaseMixin,
SaltClientTestCaseMixin,
@ -107,14 +108,17 @@ class ShellCase(TestCase, AdaptedConfigurationTestCaseMixin, ScriptPathMixin):
timeout = self.RUN_TIMEOUT
if not roster_file:
roster_file = os.path.join(RUNTIME_VARS.TMP_CONF_DIR, "roster")
arg_str = "{} {} -l{} -i --priv {} --roster-file {} {} localhost {} --out=json".format(
" -W" if wipe else "",
" -r" if raw else "",
log_level,
os.path.join(RUNTIME_VARS.TMP_CONF_DIR, "key_test"),
roster_file,
ssh_opts,
arg_str,
arg_str = (
"{wipe} {raw} -l {log_level} --ignore-host-keys --priv {client_key} --roster-file "
"{roster_file} {ssh_opts} localhost {arg_str} --out=json"
).format(
wipe=" -W" if wipe else "",
raw=" -r" if raw else "",
log_level=log_level,
client_key=os.path.join(RUNTIME_VARS.TMP_SSH_CONF_DIR, "client_key"),
roster_file=roster_file,
ssh_opts=ssh_opts,
arg_str=arg_str,
)
ret = self.run_script(
"salt-ssh",
@ -453,6 +457,7 @@ class ShellCase(TestCase, AdaptedConfigurationTestCaseMixin, ScriptPathMixin):
return ret[0] if len(ret) == 1 else tuple(ret)
log.debug("Running Popen(%r, %r)", cmd, popen_kwargs)
process = subprocess.Popen(cmd, **popen_kwargs)
if timeout is not None:
@ -931,7 +936,9 @@ class SyndicCase(TestCase, SaltClientTestCaseMixin):
return orig["minion"]
@requires_sshd_server
@SKIP_IF_NOT_RUNNING_PYTEST
@pytest.mark.usefixtures("salt_ssh_cli")
@pytest.mark.requires_sshd_server
class SSHCase(ShellCase):
"""
Execute a command via salt-ssh

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
tests.support.cli_scripts
~~~~~~~~~~~~~~~~~~~~~~~~~
@ -6,13 +5,11 @@
Code to generate Salt CLI scripts for test runs
"""
from __future__ import absolute_import, unicode_literals
import logging
import os
import sys
from saltfactories.utils import cli_scripts
from tests.support.saltfactories_compat import generate_script
log = logging.getLogger(__name__)
@ -31,10 +28,9 @@ def get_script_path(bin_dir, script_name):
script_path = os.path.join(bin_dir, cli_script_name)
if not os.path.isfile(script_path):
cli_scripts.generate_script(
generate_script(
bin_dir=bin_dir,
script_name=script_name,
executable=sys.executable,
code_dir=RUNTIME_VARS.CODE_DIR,
inject_coverage="COVERAGE_PROCESS_START" in os.environ,
inject_sitecustomize="COVERAGE_PROCESS_START" in os.environ,
@ -43,7 +39,7 @@ def get_script_path(bin_dir, script_name):
return script_path
class ScriptPathMixin(object):
class ScriptPathMixin:
def get_script_path(self, script_name):
"""
Return the path to a testing runtime script

View file

@ -9,7 +9,7 @@ import shutil
import tempfile
import textwrap
import attr # pylint: disable=3rd-party-module-not-gated
import attr
import pytest
import salt.utils.files
import salt.utils.path
@ -18,6 +18,8 @@ import salt.utils.yaml
from salt.fileserver import gitfs
from salt.pillar import git_pillar
from salt.utils.immutabletypes import freeze
from saltfactories.factories.base import DaemonFactory
from saltfactories.factories.daemons.sshd import SshdDaemonFactory as _SshdDaemonFactory
from saltfactories.utils.ports import get_unused_localhost_port
from tests.support.case import ModuleCase
from tests.support.helpers import (
@ -28,8 +30,6 @@ from tests.support.helpers import (
from tests.support.mixins import LoaderModuleMockMixin
from tests.support.mock import patch
from tests.support.runtests import RUNTIME_VARS
from tests.support.saltfactories_compat import DaemonFactory
from tests.support.saltfactories_compat import SshdDaemonFactory as _SshdDaemonFactory
log = logging.getLogger(__name__)
@ -269,15 +269,11 @@ class NginxDaemon(DaemonFactory):
@pytest.fixture(scope="class")
def ssh_pillar_tests_prep(request, salt_factories, salt_master, salt_minion):
def ssh_pillar_tests_prep(request, salt_master, salt_minion):
"""
Stand up an SSHD server to serve up git repos for tests.
"""
try:
salt_call_cli = salt_minion.get_salt_call_cli()
raise RuntimeError("s0undt3ch, it's time to cleanup this spaghetti code!")
except AttributeError:
salt_call_cli = salt_factories.get_salt_call_cli(salt_minion.config["id"])
salt_call_cli = salt_minion.get_salt_call_cli()
sshd_bin = salt.utils.path.which("sshd")
sshd_config_dir = tempfile.mkdtemp(dir=RUNTIME_VARS.TMP)
@ -325,16 +321,12 @@ def ssh_pillar_tests_prep(request, salt_factories, salt_master, salt_minion):
@pytest.fixture(scope="class")
def webserver_pillar_tests_prep(request, salt_factories, salt_master, salt_minion):
def webserver_pillar_tests_prep(request, salt_master, salt_minion):
"""
Stand up an nginx + uWSGI + git-http-backend webserver to
serve up git repos for tests.
"""
try:
salt_call_cli = salt_minion.get_salt_call_cli()
raise RuntimeError("s0undt3ch, it's time to cleanup this spaghetti code!")
except AttributeError:
salt_call_cli = salt_factories.get_salt_call_cli(salt_minion.config["id"])
salt_call_cli = salt_minion.get_salt_call_cli()
root_dir = tempfile.mkdtemp(dir=RUNTIME_VARS.TMP)
config_dir = os.path.join(root_dir, "config")

View file

@ -39,9 +39,9 @@ import salt.utils.stringutils
import salt.utils.versions
from salt.ext import six
from salt.ext.six.moves import builtins
from saltfactories.exceptions import ProcessFailed
from saltfactories.exceptions import FactoryFailure as ProcessFailed
from saltfactories.utils.ports import get_unused_localhost_port
from saltfactories.utils.processes.bases import ProcessResult
from saltfactories.utils.processes import ProcessResult
from tests.support.mock import patch
from tests.support.runtests import RUNTIME_VARS
from tests.support.sminion import create_sminion
@ -176,6 +176,7 @@ def slowTest(caller):
if RUNTIME_VARS.PYTEST_SESSION:
setattr(caller, "__slow_test__", True)
return caller
if os.environ.get("SLOW_TESTS", "False").lower() == "false":
reason = "Slow tests are disabled"
@ -285,27 +286,9 @@ def requires_sshd_server(caller):
def test_create_user(self):
pass
"""
if inspect.isclass(caller):
# We're decorating a class
old_setup = getattr(caller, "setUp", None)
def setUp(self, *args, **kwargs):
if os.environ.get("SSH_DAEMON_RUNNING", "False").lower() == "false":
self.skipTest("SSH tests are disabled")
if old_setup is not None:
old_setup(self, *args, **kwargs)
caller.setUp = setUp
return caller
# We're simply decorating functions
@functools.wraps(caller)
def wrap(cls):
if os.environ.get("SSH_DAEMON_RUNNING", "False").lower() == "false":
cls.skipTest("SSH tests are disabled")
return caller(cls)
return wrap
raise RuntimeError(
"Please replace @requires_sshd_server with @pytest.mark.requires_sshd_server"
)
class RedirectStdStreams:
@ -1673,7 +1656,12 @@ class VirtualEnv:
kwargs.setdefault("stderr", subprocess.PIPE)
kwargs.setdefault("universal_newlines", True)
proc = subprocess.run(args, check=False, **kwargs)
ret = ProcessResult(proc.returncode, proc.stdout, proc.stderr, proc.args)
ret = ProcessResult(
exitcode=proc.returncode,
stdout=proc.stdout,
stderr=proc.stderr,
cmdline=proc.args,
)
log.debug(ret)
if check is True:
try:

View file

@ -77,6 +77,7 @@ TMP_MM_SUB_CONF_DIR = TMP_MM_SUB_MINION_CONF_DIR = os.path.join(
TMP_CONF_DIR, "sub-multimaster"
)
TMP_PROXY_CONF_DIR = TMP_CONF_DIR
TMP_SSH_CONF_DIR = TMP_MINION_CONF_DIR
CONF_DIR = os.path.join(INTEGRATION_TEST_DIR, "files", "conf")
PILLAR_DIR = os.path.join(FILES, "pillar")
TMP_SCRIPT_DIR = os.path.join(TMP, "scripts")

View file

@ -12,12 +12,13 @@
import logging
from saltfactories.utils.processes.helpers import ( # pylint: disable=unused-import
from saltfactories.utils.processes import ( # pylint: disable=unused-import
collect_child_processes,
terminate_process,
terminate_process_list,
)
from tests.support.cli_scripts import ScriptPathMixin
from tests.support.cli_scripts import ScriptPathMixin, get_script_path
from tests.support.runtests import RUNTIME_VARS
try:
from pytestsalt.fixtures.daemons import Salt as PytestSalt
@ -32,14 +33,14 @@ except ImportError:
# If this happens, we are running under pytest which uninstalls pytest-salt due to impatabilites
# These imports won't actually work but these classes are only used when running under runtests,
# so, we're just making sure we also don't hit NameError's
from saltfactories.utils.processes.salts import SaltCallCLI as PytestSaltCall
from saltfactories.utils.processes.salts import SaltCLI as PytestSalt
from saltfactories.utils.processes.salts import SaltKeyCLI as PytestSaltKey
from saltfactories.utils.processes.salts import SaltMaster as PytestSaltMaster
from saltfactories.utils.processes.salts import SaltMinion as PytestSaltMinion
from saltfactories.utils.processes.salts import SaltProxyMinion as PytestSaltProxy
from saltfactories.utils.processes.salts import SaltRunCLI as PytestSaltRun
from saltfactories.utils.processes.salts import SaltSyndic as PytestSaltSyndic
from tests.support.saltfactories_compat import SaltCallCLI as PytestSaltCall
from tests.support.saltfactories_compat import SaltCLI as PytestSalt
from tests.support.saltfactories_compat import SaltKeyCLI as PytestSaltKey
from tests.support.saltfactories_compat import SaltMaster as PytestSaltMaster
from tests.support.saltfactories_compat import SaltMinion as PytestSaltMinion
from tests.support.saltfactories_compat import SaltProxyMinion as PytestSaltProxy
from tests.support.saltfactories_compat import SaltRunCLI as PytestSaltRun
from tests.support.saltfactories_compat import SaltSyndic as PytestSaltSyndic
log = logging.getLogger(__name__)
@ -144,6 +145,7 @@ def start_daemon(
log.info("[%s] Starting pytest %s(%s)", daemon_name, daemon_log_prefix, daemon_id)
attempts = 0
process = None
get_script_path(RUNTIME_VARS.TMP_SCRIPT_DIR, daemon_cli_script_name)
while attempts <= 3: # pylint: disable=too-many-nested-blocks
attempts += 1
try:

View file

@ -1,475 +0,0 @@
"""
tests.support.pytest.fixtures
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The purpose of this fixtures module is provide the same set of available fixture for the old unittest
test suite under ``test/integration``, ``tests/multimaster`` and ``tests/unit``.
Please refrain from adding fixtures to this module and instead add them to the appropriate
``conftest.py`` file.
"""
import os
import shutil
import stat
import pytest
import salt.utils.files
from salt.serializers import yaml
from salt.utils.immutabletypes import freeze
from tests.support.helpers import get_virtualenv_binary_path
from tests.support.runtests import RUNTIME_VARS
@pytest.fixture(scope="session")
def integration_files_dir(salt_factories):
"""
Fixture which returns the salt integration files directory path.
Creates the directory if it does not yet exist.
"""
dirname = salt_factories.root_dir.join("integration-files")
dirname.ensure(dir=True)
return dirname
@pytest.fixture(scope="session")
def state_tree_root_dir(integration_files_dir):
"""
Fixture which returns the salt state tree root directory path.
Creates the directory if it does not yet exist.
"""
dirname = integration_files_dir.join("state-tree")
dirname.ensure(dir=True)
return dirname
@pytest.fixture(scope="session")
def pillar_tree_root_dir(integration_files_dir):
"""
Fixture which returns the salt pillar tree root directory path.
Creates the directory if it does not yet exist.
"""
dirname = integration_files_dir.join("pillar-tree")
dirname.ensure(dir=True)
return dirname
@pytest.fixture(scope="session")
def base_env_state_tree_root_dir(state_tree_root_dir):
"""
Fixture which returns the salt base environment state tree directory path.
Creates the directory if it does not yet exist.
"""
dirname = state_tree_root_dir.join("base")
dirname.ensure(dir=True)
RUNTIME_VARS.TMP_STATE_TREE = dirname.realpath().strpath
RUNTIME_VARS.TMP_BASEENV_STATE_TREE = RUNTIME_VARS.TMP_STATE_TREE
return dirname
@pytest.fixture(scope="session")
def prod_env_state_tree_root_dir(state_tree_root_dir):
"""
Fixture which returns the salt prod environment state tree directory path.
Creates the directory if it does not yet exist.
"""
dirname = state_tree_root_dir.join("prod")
dirname.ensure(dir=True)
RUNTIME_VARS.TMP_PRODENV_STATE_TREE = dirname.realpath().strpath
return dirname
@pytest.fixture(scope="session")
def base_env_pillar_tree_root_dir(pillar_tree_root_dir):
"""
Fixture which returns the salt base environment pillar tree directory path.
Creates the directory if it does not yet exist.
"""
dirname = pillar_tree_root_dir.join("base")
dirname.ensure(dir=True)
RUNTIME_VARS.TMP_PILLAR_TREE = dirname.realpath().strpath
RUNTIME_VARS.TMP_BASEENV_PILLAR_TREE = RUNTIME_VARS.TMP_PILLAR_TREE
return dirname
@pytest.fixture(scope="session")
def prod_env_pillar_tree_root_dir(pillar_tree_root_dir):
"""
Fixture which returns the salt prod environment pillar tree directory path.
Creates the directory if it does not yet exist.
"""
dirname = pillar_tree_root_dir.join("prod")
dirname.ensure(dir=True)
RUNTIME_VARS.TMP_PRODENV_PILLAR_TREE = dirname.realpath().strpath
return dirname
@pytest.fixture(scope="session")
def salt_syndic_master_config(request, salt_factories):
root_dir = salt_factories._get_root_dir_for_daemon("syndic_master")
with salt.utils.files.fopen(
os.path.join(RUNTIME_VARS.CONF_DIR, "syndic_master")
) as rfh:
config_defaults = yaml.deserialize(rfh.read())
tests_known_hosts_file = root_dir.join("salt_ssh_known_hosts").strpath
with salt.utils.files.fopen(tests_known_hosts_file, "w") as known_hosts:
known_hosts.write("")
config_defaults["root_dir"] = root_dir.strpath
config_defaults["known_hosts_file"] = tests_known_hosts_file
config_defaults["syndic_master"] = "localhost"
config_defaults["transport"] = request.config.getoption("--transport")
config_overrides = {}
ext_pillar = []
if salt.utils.platform.is_windows():
ext_pillar.append(
{"cmd_yaml": "type {}".format(os.path.join(RUNTIME_VARS.FILES, "ext.yaml"))}
)
else:
ext_pillar.append(
{"cmd_yaml": "cat {}".format(os.path.join(RUNTIME_VARS.FILES, "ext.yaml"))}
)
# We need to copy the extension modules into the new master root_dir or
# it will be prefixed by it
extension_modules_path = root_dir.join("extension_modules").strpath
if not os.path.exists(extension_modules_path):
shutil.copytree(
os.path.join(RUNTIME_VARS.FILES, "extension_modules"),
extension_modules_path,
)
# Copy the autosign_file to the new master root_dir
autosign_file_path = root_dir.join("autosign_file").strpath
shutil.copyfile(
os.path.join(RUNTIME_VARS.FILES, "autosign_file"), autosign_file_path
)
# all read, only owner write
autosign_file_permissions = (
stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH | stat.S_IWUSR
)
os.chmod(autosign_file_path, autosign_file_permissions)
config_overrides.update(
{
"ext_pillar": ext_pillar,
"extension_modules": extension_modules_path,
"file_roots": {
"base": [
RUNTIME_VARS.TMP_STATE_TREE,
os.path.join(RUNTIME_VARS.FILES, "file", "base"),
],
# Alternate root to test __env__ choices
"prod": [
RUNTIME_VARS.TMP_PRODENV_STATE_TREE,
os.path.join(RUNTIME_VARS.FILES, "file", "prod"),
],
},
"pillar_roots": {
"base": [
RUNTIME_VARS.TMP_PILLAR_TREE,
os.path.join(RUNTIME_VARS.FILES, "pillar", "base"),
],
"prod": [RUNTIME_VARS.TMP_PRODENV_PILLAR_TREE],
},
}
)
return salt_factories.configure_master(
request,
"syndic_master",
order_masters=True,
config_defaults=config_defaults,
config_overrides=config_overrides,
)
@pytest.fixture(scope="session")
def salt_syndic_config(request, salt_factories, salt_syndic_master_config):
return salt_factories.configure_syndic(
request, "syndic", master_of_masters_id="syndic_master"
)
@pytest.fixture(scope="session")
def salt_master_config(request, salt_factories, salt_syndic_master_config):
root_dir = salt_factories._get_root_dir_for_daemon("master")
conf_dir = root_dir.join("conf").ensure(dir=True)
with salt.utils.files.fopen(os.path.join(RUNTIME_VARS.CONF_DIR, "master")) as rfh:
config_defaults = yaml.deserialize(rfh.read())
tests_known_hosts_file = root_dir.join("salt_ssh_known_hosts").strpath
with salt.utils.files.fopen(tests_known_hosts_file, "w") as known_hosts:
known_hosts.write("")
config_defaults["root_dir"] = root_dir.strpath
config_defaults["known_hosts_file"] = tests_known_hosts_file
config_defaults["syndic_master"] = "localhost"
config_defaults["transport"] = request.config.getoption("--transport")
config_defaults["reactor"] = [
{"salt/test/reactor": [os.path.join(RUNTIME_VARS.FILES, "reactor-test.sls")]}
]
config_overrides = {}
ext_pillar = []
if salt.utils.platform.is_windows():
ext_pillar.append(
{"cmd_yaml": "type {}".format(os.path.join(RUNTIME_VARS.FILES, "ext.yaml"))}
)
else:
ext_pillar.append(
{"cmd_yaml": "cat {}".format(os.path.join(RUNTIME_VARS.FILES, "ext.yaml"))}
)
ext_pillar.append(
{
"file_tree": {
"root_dir": os.path.join(RUNTIME_VARS.PILLAR_DIR, "base", "file_tree"),
"follow_dir_links": False,
"keep_newline": True,
}
}
)
config_overrides["pillar_opts"] = True
# We need to copy the extension modules into the new master root_dir or
# it will be prefixed by it
extension_modules_path = root_dir.join("extension_modules").strpath
if not os.path.exists(extension_modules_path):
shutil.copytree(
os.path.join(RUNTIME_VARS.FILES, "extension_modules"),
extension_modules_path,
)
# Copy the autosign_file to the new master root_dir
autosign_file_path = root_dir.join("autosign_file").strpath
shutil.copyfile(
os.path.join(RUNTIME_VARS.FILES, "autosign_file"), autosign_file_path
)
# all read, only owner write
autosign_file_permissions = (
stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH | stat.S_IWUSR
)
os.chmod(autosign_file_path, autosign_file_permissions)
config_overrides.update(
{
"ext_pillar": ext_pillar,
"extension_modules": extension_modules_path,
"file_roots": {
"base": [
RUNTIME_VARS.TMP_STATE_TREE,
os.path.join(RUNTIME_VARS.FILES, "file", "base"),
],
# Alternate root to test __env__ choices
"prod": [
RUNTIME_VARS.TMP_PRODENV_STATE_TREE,
os.path.join(RUNTIME_VARS.FILES, "file", "prod"),
],
},
"pillar_roots": {
"base": [
RUNTIME_VARS.TMP_PILLAR_TREE,
os.path.join(RUNTIME_VARS.FILES, "pillar", "base"),
],
"prod": [RUNTIME_VARS.TMP_PRODENV_PILLAR_TREE],
},
}
)
# Let's copy over the test cloud config files and directories into the running master config directory
for entry in os.listdir(RUNTIME_VARS.CONF_DIR):
if not entry.startswith("cloud"):
continue
source = os.path.join(RUNTIME_VARS.CONF_DIR, entry)
dest = conf_dir.join(entry).strpath
if os.path.isdir(source):
shutil.copytree(source, dest)
else:
shutil.copyfile(source, dest)
return salt_factories.configure_master(
request,
"master",
master_of_masters_id="syndic_master",
config_defaults=config_defaults,
config_overrides=config_overrides,
)
@pytest.fixture(scope="session")
def salt_minion_config(request, salt_factories, salt_master_config):
with salt.utils.files.fopen(os.path.join(RUNTIME_VARS.CONF_DIR, "minion")) as rfh:
config_defaults = yaml.deserialize(rfh.read())
config_defaults["hosts.file"] = os.path.join(RUNTIME_VARS.TMP, "hosts")
config_defaults["aliases.file"] = os.path.join(RUNTIME_VARS.TMP, "aliases")
config_defaults["transport"] = request.config.getoption("--transport")
config_overrides = {
"file_roots": {
"base": [
RUNTIME_VARS.TMP_STATE_TREE,
os.path.join(RUNTIME_VARS.FILES, "file", "base"),
],
# Alternate root to test __env__ choices
"prod": [
RUNTIME_VARS.TMP_PRODENV_STATE_TREE,
os.path.join(RUNTIME_VARS.FILES, "file", "prod"),
],
},
"pillar_roots": {
"base": [
RUNTIME_VARS.TMP_PILLAR_TREE,
os.path.join(RUNTIME_VARS.FILES, "pillar", "base"),
],
"prod": [RUNTIME_VARS.TMP_PRODENV_PILLAR_TREE],
},
}
virtualenv_binary = get_virtualenv_binary_path()
if virtualenv_binary:
config_overrides["venv_bin"] = virtualenv_binary
return salt_factories.configure_minion(
request,
"minion",
master_id="master",
config_defaults=config_defaults,
config_overrides=config_overrides,
)
@pytest.fixture(scope="session")
def salt_sub_minion_config(request, salt_factories, salt_master_config):
with salt.utils.files.fopen(
os.path.join(RUNTIME_VARS.CONF_DIR, "sub_minion")
) as rfh:
config_defaults = yaml.deserialize(rfh.read())
config_defaults["hosts.file"] = os.path.join(RUNTIME_VARS.TMP, "hosts")
config_defaults["aliases.file"] = os.path.join(RUNTIME_VARS.TMP, "aliases")
config_defaults["transport"] = request.config.getoption("--transport")
config_overrides = {
"file_roots": {
"base": [
RUNTIME_VARS.TMP_STATE_TREE,
os.path.join(RUNTIME_VARS.FILES, "file", "base"),
],
# Alternate root to test __env__ choices
"prod": [
RUNTIME_VARS.TMP_PRODENV_STATE_TREE,
os.path.join(RUNTIME_VARS.FILES, "file", "prod"),
],
},
"pillar_roots": {
"base": [
RUNTIME_VARS.TMP_PILLAR_TREE,
os.path.join(RUNTIME_VARS.FILES, "pillar", "base"),
],
"prod": [RUNTIME_VARS.TMP_PRODENV_PILLAR_TREE],
},
}
virtualenv_binary = get_virtualenv_binary_path()
if virtualenv_binary:
config_overrides["venv_bin"] = virtualenv_binary
return salt_factories.configure_minion(
request,
"sub_minion",
master_id="master",
config_defaults=config_defaults,
config_overrides=config_overrides,
)
@pytest.hookspec(firstresult=True)
def pytest_saltfactories_syndic_configuration_defaults(
request, factories_manager, root_dir, syndic_id, syndic_master_port
):
"""
Hook which should return a dictionary tailored for the provided syndic_id with 3 keys:
* `master`: The default config for the master running along with the syndic
* `minion`: The default config for the master running along with the syndic
* `syndic`: The default config for the master running along with the syndic
Stops at the first non None result
"""
factory_opts = {"master": None, "minion": None, "syndic": None}
if syndic_id == "syndic":
with salt.utils.files.fopen(
os.path.join(RUNTIME_VARS.CONF_DIR, "syndic")
) as rfh:
opts = yaml.deserialize(rfh.read())
opts["hosts.file"] = os.path.join(RUNTIME_VARS.TMP, "hosts")
opts["aliases.file"] = os.path.join(RUNTIME_VARS.TMP, "aliases")
opts["transport"] = request.config.getoption("--transport")
factory_opts["syndic"] = opts
return factory_opts
@pytest.hookspec(firstresult=True)
def pytest_saltfactories_syndic_configuration_overrides(
request, factories_manager, syndic_id, config_defaults
):
"""
Hook which should return a dictionary tailored for the provided syndic_id.
This dictionary will override the default_options dictionary.
The returned dictionary should contain 3 keys:
* `master`: The config overrides for the master running along with the syndic
* `minion`: The config overrides for the master running along with the syndic
* `syndic`: The config overridess for the master running along with the syndic
The `default_options` parameter be None or have 3 keys, `master`, `minion`, `syndic`,
while will contain the default options for each of the daemons.
Stops at the first non None result
"""
@pytest.fixture(scope="session", autouse=True)
def bridge_pytest_and_runtests(
reap_stray_processes,
base_env_state_tree_root_dir,
prod_env_state_tree_root_dir,
base_env_pillar_tree_root_dir,
prod_env_pillar_tree_root_dir,
salt_factories,
salt_syndic_master_config,
salt_syndic_config,
salt_master_config,
salt_minion_config,
salt_sub_minion_config,
):
# Make sure unittest2 uses the pytest generated configuration
RUNTIME_VARS.RUNTIME_CONFIGS["master"] = freeze(salt_master_config)
RUNTIME_VARS.RUNTIME_CONFIGS["minion"] = freeze(salt_minion_config)
RUNTIME_VARS.RUNTIME_CONFIGS["sub_minion"] = freeze(salt_sub_minion_config)
RUNTIME_VARS.RUNTIME_CONFIGS["syndic_master"] = freeze(salt_syndic_master_config)
RUNTIME_VARS.RUNTIME_CONFIGS["syndic"] = freeze(salt_syndic_config)
RUNTIME_VARS.RUNTIME_CONFIGS["client_config"] = freeze(
salt.config.client_config(salt_master_config["conf_file"])
)
# Make sure unittest2 classes know their paths
RUNTIME_VARS.TMP_ROOT_DIR = salt_factories.root_dir.realpath().strpath
RUNTIME_VARS.TMP_CONF_DIR = os.path.dirname(salt_master_config["conf_file"])
RUNTIME_VARS.TMP_MINION_CONF_DIR = os.path.dirname(salt_minion_config["conf_file"])
RUNTIME_VARS.TMP_SUB_MINION_CONF_DIR = os.path.dirname(
salt_sub_minion_config["conf_file"]
)
RUNTIME_VARS.TMP_SYNDIC_MASTER_CONF_DIR = os.path.dirname(
salt_syndic_master_config["conf_file"]
)
RUNTIME_VARS.TMP_SYNDIC_MINION_CONF_DIR = os.path.dirname(
salt_syndic_config["conf_file"]
)
# Only allow star importing the functions defined in this module
__all__ = [
name
for (name, func) in locals().items()
if getattr(func, "__module__", None) == __name__
]

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
tests.support.pytest.helpers
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -251,6 +250,15 @@ def salt_loader_module_functions(module):
return funcs
@pytest.helpers.register
def remove_stale_minion_key(master, minion_id):
key_path = os.path.join(master.config["pki_dir"], "minions", minion_id)
if os.path.exists(key_path):
os.unlink(key_path)
else:
log.debug("The minion(id=%r) key was not found at %s", minion_id, key_path)
# Only allow star importing the functions defined in this module
__all__ = [
name

View file

@ -42,8 +42,8 @@
minion_config_path = os.path.join(RUNTIME_VARS.TMP_CONF_DIR, 'minion')
.. _`pytest`: http://pytest.org
.. _`nose`: https://nose.readthedocs.org
"""
"""
import logging
import os
import shutil
@ -189,6 +189,7 @@ RUNTIME_VARS = RuntimeVars(
TMP_MM_MINION_CONF_DIR=paths.TMP_MM_MINION_CONF_DIR,
TMP_MM_SUB_CONF_DIR=paths.TMP_MM_SUB_CONF_DIR,
TMP_MM_SUB_MINION_CONF_DIR=paths.TMP_MM_SUB_CONF_DIR,
TMP_SSH_CONF_DIR=paths.TMP_SSH_CONF_DIR,
TMP_SCRIPT_DIR=paths.TMP_SCRIPT_DIR,
TMP_STATE_TREE=paths.TMP_STATE_TREE,
TMP_BASEENV_STATE_TREE=paths.TMP_STATE_TREE,

File diff suppressed because it is too large Load diff

85
tests/support/virt.py Normal file
View file

@ -0,0 +1,85 @@
import time
import uuid
import attr
from saltfactories.factories.daemons.container import SaltMinionContainerFactory
from saltfactories.utils import ports
from tests.support.runtests import RUNTIME_VARS
@attr.s(kw_only=True, slots=True)
class SaltVirtMinionContainerFactory(SaltMinionContainerFactory):
host_uuid = attr.ib(default=attr.Factory(uuid.uuid4))
ssh_port = attr.ib(
default=attr.Factory(ports.get_unused_localhost_port), repr=False
)
sshd_port = attr.ib(default=attr.Factory(ports.get_unused_localhost_port))
libvirt_tcp_port = attr.ib(
default=attr.Factory(ports.get_unused_localhost_port), repr=False
)
libvirt_tls_port = attr.ib(
default=attr.Factory(ports.get_unused_localhost_port), repr=False
)
uri = attr.ib(init=False)
ssh_uri = attr.ib(init=False)
tcp_uri = attr.ib(init=False)
tls_uri = attr.ib(init=False)
def __attrs_post_init__(self):
self.uri = "localhost:{}".format(self.sshd_port)
self.ssh_uri = "qemu+ssh://{}/system".format(self.uri)
self.tcp_uri = "qemu+tcp://localhost:{}/system".format(self.libvirt_tcp_port)
self.tls_uri = "qemu+tls://localhost:{}/system".format(self.libvirt_tls_port)
if self.check_ports is None:
self.check_ports = []
self.check_ports.extend(
[self.sshd_port, self.libvirt_tcp_port, self.libvirt_tls_port]
)
if "environment" not in self.container_run_kwargs:
self.container_run_kwargs["environment"] = {}
self.container_run_kwargs["environment"].update(
{
"SSH_PORT": str(self.ssh_port),
"SSHD_PORT": str(self.sshd_port),
"LIBVIRT_TCP_PORT": str(self.libvirt_tcp_port),
"LIBVIRT_TLS_PORT": str(self.libvirt_tls_port),
"NO_START_MINION": "1",
"HOST_UUID": self.host_uuid,
}
)
if "ports" not in self.container_run_kwargs:
self.container_run_kwargs["ports"] = {}
self.container_run_kwargs["ports"].update(
{
"{}/tcp".format(self.ssh_port): self.ssh_port,
"{}/tcp".format(self.sshd_port): self.sshd_port,
"{}/tcp".format(self.libvirt_tcp_port): self.libvirt_tcp_port,
"{}/tcp".format(self.libvirt_tls_port): self.libvirt_tls_port,
}
)
if "volumes" not in self.container_run_kwargs:
self.container_run_kwargs["volumes"] = {}
self.container_run_kwargs["volumes"].update(
{
RUNTIME_VARS.CODE_DIR: {"bind": "/salt", "mode": "z"},
RUNTIME_VARS.CODE_DIR: {"bind": RUNTIME_VARS.CODE_DIR, "mode": "z"},
}
)
self.container_run_kwargs["working_dir"] = RUNTIME_VARS.CODE_DIR
self.container_run_kwargs["network_mode"] = "host"
self.container_run_kwargs["cap_add"] = ["ALL"]
self.container_run_kwargs["privileged"] = True
super().__attrs_post_init__()
self.python_executable = "python3"
def _container_start_checks(self):
# Once we're able to ls the salt-minion script it means the container
# has salt installed
ret = self.run("ls", "-lah", self.get_script_path())
if ret.exitcode == 0:
return True
time.sleep(1)
return False

View file

@ -9,17 +9,13 @@ import copy
import logging
import textwrap
import pytest
import salt.modules.aptpkg as aptpkg
from salt.exceptions import CommandExecutionError, SaltInvocationError
from tests.support.mixins import LoaderModuleMockMixin
from tests.support.mock import MagicMock, Mock, call, patch
from tests.support.unit import TestCase, skipIf
try:
import pytest
except ImportError:
pytest = None
log = logging.getLogger(__name__)
@ -852,7 +848,7 @@ class AptUtilsTestCase(TestCase, LoaderModuleMockMixin):
aptpkg.__salt__,
{"cmd.run_all": cmd_mock, "config.get": MagicMock(return_value=False)},
):
with patch("time.sleep", MagicMock()) as sleep_mock:
with patch("salt.modules.aptpkg.time.sleep", MagicMock()) as sleep_mock:
aptpkg._call_apt(
["dpkg", "-l", "python"],
python_shell=True,

View file

@ -1,10 +1,8 @@
# -*- coding: utf-8 -*-
"""
tests.unit.utils.scheduler.base
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"""
from __future__ import absolute_import
import copy
import logging
@ -14,7 +12,7 @@ import salt.utils.platform
import salt.utils.schedule
from salt.modules.test import ping
from salt.utils.process import SubprocessList
from saltfactories.utils.processes.helpers import terminate_process
from saltfactories.utils.processes import terminate_process
from tests.support.mixins import SaltReturnAssertsMixin
from tests.support.mock import MagicMock, patch
from tests.support.runtests import RUNTIME_VARS

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
:codeauthor: Pedro Algarvio (pedro@algarvio.me)
@ -6,7 +5,6 @@
tests.unit.utils.event_test
~~~~~~~~~~~~~~~~~~~~~~~~~~~
"""
from __future__ import absolute_import, print_function, unicode_literals
import hashlib
import os
@ -21,7 +19,7 @@ import zmq
import zmq.eventloop.ioloop
from salt.ext.six.moves import range
from salt.ext.tornado.testing import AsyncTestCase
from saltfactories.utils.processes.helpers import terminate_process
from saltfactories.utils.processes import terminate_process
from tests.support.events import eventpublisher_process, eventsender_process
from tests.support.helpers import slowTest
from tests.support.runtests import RUNTIME_VARS
@ -49,7 +47,7 @@ class TestSaltEvent(TestCase):
def assertGotEvent(self, evt, data, msg=None):
self.assertIsNotNone(evt, msg)
for key in data:
self.assertIn(key, evt, "{0}: Key {1} missing".format(msg, key))
self.assertIn(key, evt, "{}: Key {} missing".format(msg, key))
assertMsg = "{0}: Key {1} value mismatch, {2} != {3}"
assertMsg = assertMsg.format(msg, key, data[key], evt[key])
self.assertEqual(data[key], evt[key], assertMsg)
@ -57,11 +55,11 @@ class TestSaltEvent(TestCase):
def test_master_event(self):
me = salt.utils.event.MasterEvent(self.sock_dir, listen=False)
self.assertEqual(
me.puburi, "{0}".format(os.path.join(self.sock_dir, "master_event_pub.ipc"))
me.puburi, "{}".format(os.path.join(self.sock_dir, "master_event_pub.ipc"))
)
self.assertEqual(
me.pulluri,
"{0}".format(os.path.join(self.sock_dir, "master_event_pull.ipc")),
"{}".format(os.path.join(self.sock_dir, "master_event_pull.ipc")),
)
def test_minion_event(self):
@ -72,14 +70,14 @@ class TestSaltEvent(TestCase):
me = salt.utils.event.MinionEvent(opts, listen=False)
self.assertEqual(
me.puburi,
"{0}".format(
os.path.join(self.sock_dir, "minion_event_{0}_pub.ipc".format(id_hash))
"{}".format(
os.path.join(self.sock_dir, "minion_event_{}_pub.ipc".format(id_hash))
),
)
self.assertEqual(
me.pulluri,
"{0}".format(
os.path.join(self.sock_dir, "minion_event_{0}_pull.ipc".format(id_hash))
"{}".format(
os.path.join(self.sock_dir, "minion_event_{}_pull.ipc".format(id_hash))
),
)
@ -94,14 +92,14 @@ class TestSaltEvent(TestCase):
id_hash = hashlib.sha256(salt.utils.stringutils.to_bytes("")).hexdigest()[:10]
self.assertEqual(
me.puburi,
"{0}".format(
os.path.join(self.sock_dir, "minion_event_{0}_pub.ipc".format(id_hash))
"{}".format(
os.path.join(self.sock_dir, "minion_event_{}_pub.ipc".format(id_hash))
),
)
self.assertEqual(
me.pulluri,
"{0}".format(
os.path.join(self.sock_dir, "minion_event_{0}_pull.ipc".format(id_hash))
"{}".format(
os.path.join(self.sock_dir, "minion_event_{}_pull.ipc".format(id_hash))
),
)
@ -270,11 +268,9 @@ class TestSaltEvent(TestCase):
with eventpublisher_process(self.sock_dir):
me = salt.utils.event.MasterEvent(self.sock_dir, listen=True)
for i in range(500):
me.fire_event({"data": "{0}".format(i)}, "testevents")
me.fire_event({"data": "{}".format(i)}, "testevents")
evt = me.get_event(tag="testevents")
self.assertGotEvent(
evt, {"data": "{0}".format(i)}, "Event {0}".format(i)
)
self.assertGotEvent(evt, {"data": "{}".format(i)}, "Event {}".format(i))
@slowTest
def test_event_many_backlog(self):
@ -283,12 +279,10 @@ class TestSaltEvent(TestCase):
me = salt.utils.event.MasterEvent(self.sock_dir, listen=True)
# Must not exceed zmq HWM
for i in range(500):
me.fire_event({"data": "{0}".format(i)}, "testevents")
me.fire_event({"data": "{}".format(i)}, "testevents")
for i in range(500):
evt = me.get_event(tag="testevents")
self.assertGotEvent(
evt, {"data": "{0}".format(i)}, "Event {0}".format(i)
)
self.assertGotEvent(evt, {"data": "{}".format(i)}, "Event {}".format(i))
# Test the fire_master function. As it wraps the underlying fire_event,
# we don't need to perform extensive testing.
@ -312,7 +306,7 @@ class TestAsyncEventPublisher(AsyncTestCase):
return salt.ext.tornado.ioloop.IOLoop()
def setUp(self):
super(TestAsyncEventPublisher, self).setUp()
super().setUp()
self.sock_dir = os.path.join(RUNTIME_VARS.TMP, "test-socks")
if not os.path.exists(self.sock_dir):
os.makedirs(self.sock_dir)