diff --git a/.gitignore b/.gitignore index e92fca57b2b..b3d444d2fba 100644 --- a/.gitignore +++ b/.gitignore @@ -95,6 +95,9 @@ tests/integration/cloud/providers/pki/minions # Ignore tox virtualenvs /.tox/ +# Ignore nox virtualenvs +/.nox/ + # Kitchen tests files .kitchen.local.yml .kitchen/ diff --git a/noxfile.py b/noxfile.py new file mode 100644 index 00000000000..227bc300195 --- /dev/null +++ b/noxfile.py @@ -0,0 +1,144 @@ +# -*- coding: utf-8 -*- +''' +noxfile +~~~~~~~ + +Nox configuration script +''' + +# Import Python libs +import os +import sys + + +if __name__ == '__main__': + sys.stderr.write('Do not execute this file directly. Use nox instead, it will know how to handle this file\n') + sys.stderr.flush() + exit(1) + +# Import 3rd-party libs +import nox + +# Global Path Definitions +REPO_ROOT = os.path.abspath(os.path.dirname(__file__)) +SITECUSTOMIZE_DIR = os.path.join(REPO_ROOT, 'tests', 'support', 'coverage') + +# Python versions to run against +_PYTHON_VERSIONS = ('2', '2.7', '3', '3.4', '3.5', '3.6') + +# Nox options +# Reuse existing virtualenvs +nox.options.reuse_existing_virtualenvs = True +# Don't fail on missing interpreters +nox.options.error_on_missing_interpreters = False + +def _create_ci_directories(): + for dirname in ('logs', 'coverage', 'xml-unittests-output'): + path = os.path.join(REPO_ROOT, 'artifacts', dirname) + if not os.path.exists(path): + os.makedirs(path) + + +def _install_requirements(session, *extra_requirements): + # Install requirements + _requirements_files = [] + if sys.platform.startswith('linux'): + requirements_files = [ + os.path.join(REPO_ROOT, 'requirements', 'tests.txt') + ] + elif sys.platform.startswith('win'): + requirements_files = [ + os.path.join(REPO_ROOT, 'pkg', 'windows', 'req.txt'), + os.path.join(REPO_ROOT, 'pkg', 'windows', 'req_testing.txt'), + ] + elif sys.platform.startswith('darwin'): + requirements_files = [ + os.path.join(REPO_ROOT, 'pkg', 'osx', 'req.txt'), + os.path.join(REPO_ROOT, 'pkg', 'osx', 'req_ext.txt'), + ] + + while True: + if not requirements_files: + break + requirements_file = requirements_files.pop(0) + session.log('Processing {}'.format(requirements_file)) + with open(requirements_file) as rfh: # pylint: disable=resource-leakage + for line in rfh: + line = line.strip() + if not line: + continue + if line.startswith('-r'): + reqfile = os.path.join(os.path.dirname(requirements_file), line.strip().split()[-1]) + if reqfile in _requirements_files: + continue + _requirements_files.append(reqfile) + continue + + for requirements_file in _requirements_files: + session.install('-r', requirements_file) + + if extra_requirements: + session.install(*extra_requirements) + + +def _run_with_coverage(session, *test_cmd): + session.run('coverage', 'erase') + python_path_env_var = os.environ.get('PYTHONPATH') or None + if python_path_env_var is None: + python_path_env_var = SITECUSTOMIZE_DIR + else: + python_path_env_var = '{}:{}'.format(SITECUSTOMIZE_DIR, python_path_env_var) + session.run( + *test_cmd, + env={ + 'PYTHONPATH': python_path_env_var, + 'COVERAGE_PROCESS_START': os.path.join(REPO_ROOT, '.coveragerc') + } + ) + session.run('coverage', 'combine') + session.run('coverage', 'xml', '-o', os.path.join(REPO_ROOT, 'artifacts', 'coverage', 'coverage.xml')) + + +@nox.session(python=_PYTHON_VERSIONS) +@nox.parametrize('coverage', [False, True]) +def runtests(session, coverage): + # Install requirements + _install_requirements(session, 'unittest-xml-reporting') + # Create required artifacts directories + _create_ci_directories() + + cmd_args = [ + '-v', + '--tests-logfile={}'.format( + os.path.join(REPO_ROOT, 'artifacts', 'logs', 'runtests.log') + ) + ] + session.posargs + + if coverage is True: + _run_with_coverage(session, 'coverage', 'run', '-m', 'tests.runtests', *cmd_args) + else: + session.run('python', os.path.join('tests', 'runtests.py'), *cmd_args) + + +@nox.session(python=_PYTHON_VERSIONS) +@nox.parametrize('coverage', [False, True]) +def pytest(session, coverage): + # Install requirements + _install_requirements(session) + # Create required artifacts directories + _create_ci_directories() + + cmd_args = [ + '--rootdir', REPO_ROOT, + '--log-file={}'.format( + os.path.join(REPO_ROOT, 'artifacts', 'logs', 'runtests.log') + ), + '--no-print-logs', + '-ra', + '-sv' + ] + session.posargs + + if coverage is True: + _run_with_coverage(session, 'coverage', 'run', '-m', 'py.test', *cmd_args) + else: + session.run('py.test', *cmd_args) diff --git a/tox.ini b/tox.ini index 6d72c1831f3..651c2c76a4d 100644 --- a/tox.ini +++ b/tox.ini @@ -12,205 +12,10 @@ skip_missing_interpreters = True skipsdist = True [testenv] -deps = -Ur{toxinidir}/requirements/tests.txt -changedir = {toxinidir} -commands_pre = {envpython} tests/tox-helper.py create-dirs passenv = LANG HOME sitepackages = True -commands = {[testenv:runtests]commands} - -[testenv:runtests] -deps = - {[testenv]deps} - unittest-xml-reporting -commands = {envpython} {toxinidir}/tests/runtests.py --tests-logfile={toxinidir}/artifacts/logs/runtests.log {posargs} - -[testenv:pytest] -commands = pytest --rootdir {toxinidir} --log-file={toxinidir}/artifacts/logs/runtests.log {posargs} - -[testenv:runtests-coverage] -# Add tests/support/coverage to PYTHONPATH in order to get code coverage from subprocesses. -setenv = - PYTHONPATH={toxinidir}/tests/support/coverage -commands_pre = - - coverage erase commands = - coverage run -m tests.runtests {posargs} -commands_post = - - coverage combine - - coverage xml -o {toxinidir}/artifacts/coverage/coverage.xml - -[testenv:pytest-coverage] -setenv = {[testenv:runtests-coverage]setenv} -commands_pre = {[testenv:runtests-coverage]commands_pre} -commands = coverage run -m py.test --rootdir {toxinidir} {posargs} -commands_post = {[testenv:runtests-coverage]commands_post} - -[testenv:py2-pytest] -commands = {[testenv:pytest]commands} - -[testenv:py2-runtests] -deps = {[testenv:runtests]deps} -commands = {[testenv:runtests]commands} - -[testenv:py2-coverage] -deps = {[testenv:runtests]deps} -setenv = {[testenv:runtests-coverage]setenv} -commands = {[testenv:runtests-coverage]commands} -commands_pre = {[testenv:runtests-coverage]commands_pre} -commands_post = {[testenv:runtests-coverage]commands_post} - -[testenv:py2-runtests-coverage] -deps = {[testenv:runtests]deps} -setenv = {[testenv:runtests-coverage]setenv} -commands = {[testenv:runtests-coverage]commands} -commands_pre = {[testenv:runtests-coverage]commands_pre} -commands_post = {[testenv:runtests-coverage]commands_post} - -[testenv:py2-pytest-coverage] -setenv = {[testenv:runtests-coverage]setenv} -commands = {[testenv:pytest-coverage]commands} -commands_pre = {[testenv:pytest-coverage]commands_pre} -commands_post = {[testenv:pytest-coverage]commands_post} - -[testenv:py27-pytest] -commands = {[testenv:pytest]commands} - -[testenv:py27-runtests] -deps = {[testenv:runtests]deps} -commands = {[testenv:runtests]commands} - -[testenv:py27-coverage] -deps = {[testenv:runtests]deps} -setenv = {[testenv:runtests-coverage]setenv} -commands = {[testenv:runtests-coverage]commands} -commands_pre = {[testenv:runtests-coverage]commands_pre} -commands_post = {[testenv:runtests-coverage]commands_post} - -[testenv:py27-runtests-coverage] -deps = {[testenv:runtests]deps} -setenv = {[testenv:runtests-coverage]setenv} -commands = {[testenv:runtests-coverage]commands} -commands_pre = {[testenv:runtests-coverage]commands_pre} -commands_post = {[testenv:runtests-coverage]commands_post} - -[testenv:py27-pytest-coverage] -setenv = {[testenv:runtests-coverage]setenv} -commands = {[testenv:pytest-coverage]commands} -commands_pre = {[testenv:pytest-coverage]commands_pre} -commands_post = {[testenv:pytest-coverage]commands_post} - -[testenv:py3-pytest] -commands = {[testenv:pytest]commands} - -[testenv:py3-runtests] -deps = {[testenv:runtests]deps} -commands = {[testenv:runtests]commands} - -[testenv:py3-coverage] -deps = {[testenv:runtests]deps} -setenv = {[testenv:runtests-coverage]setenv} -commands = {[testenv:runtests-coverage]commands} -commands_pre = {[testenv:runtests-coverage]commands_pre} -commands_post = {[testenv:runtests-coverage]commands_post} - -[testenv:py3-runtests-coverage] -deps = {[testenv:runtests]deps} -setenv = {[testenv:runtests-coverage]setenv} -commands = {[testenv:runtests-coverage]commands} -commands_pre = {[testenv:runtests-coverage]commands_pre} -commands_post = {[testenv:runtests-coverage]commands_post} - -[testenv:py3-pytest-coverage] -setenv = {[testenv:runtests-coverage]setenv} -commands = {[testenv:pytest-coverage]commands} -commands_pre = {[testenv:pytest-coverage]commands_pre} -commands_post = {[testenv:pytest-coverage]commands_post} - - -[testenv:py34-pytest] -commands = {[testenv:pytest]commands} - -[testenv:py34-runtests] -deps = {[testenv:runtests]deps} -commands = {[testenv:runtests]commands} - -[testenv:py34-coverage] -deps = {[testenv:runtests]deps} -setenv = {[testenv:runtests-coverage]setenv} -commands = {[testenv:runtests-coverage]commands} -commands_pre = {[testenv:runtests-coverage]commands_pre} -commands_post = {[testenv:runtests-coverage]commands_post} - -[testenv:py34-runtests-coverage] -deps = {[testenv:runtests]deps} -setenv = {[testenv:runtests-coverage]setenv} -commands = {[testenv:runtests-coverage]commands} -commands_pre = {[testenv:runtests-coverage]commands_pre} -commands_post = {[testenv:runtests-coverage]commands_post} - -[testenv:py34-pytest-coverage] -setenv = {[testenv:runtests-coverage]setenv} -commands = {[testenv:pytest-coverage]commands} -commands_pre = {[testenv:pytest-coverage]commands_pre} -commands_post = {[testenv:pytest-coverage]commands_post} - - -[testenv:py35-pytest] -commands = {[testenv:pytest]commands} - -[testenv:py35-runtests] -deps = {[testenv:runtests]deps} -commands = {[testenv:runtests]commands} - -[testenv:py35-coverage] -deps = {[testenv:runtests]deps} -setenv = {[testenv:runtests-coverage]setenv} -commands = {[testenv:runtests-coverage]commands} -commands_pre = {[testenv:runtests-coverage]commands_pre} -commands_post = {[testenv:runtests-coverage]commands_post} - -[testenv:py35-runtests-coverage] -deps = {[testenv:runtests]deps} -setenv = {[testenv:runtests-coverage]setenv} -commands = {[testenv:runtests-coverage]commands} -commands_pre = {[testenv:runtests-coverage]commands_pre} -commands_post = {[testenv:runtests-coverage]commands_post} - -[testenv:py35-pytest-coverage] -setenv = {[testenv:runtests-coverage]setenv} -commands = {[testenv:pytest-coverage]commands} -commands_pre = {[testenv:pytest-coverage]commands_pre} -commands_post = {[testenv:pytest-coverage]commands_post} - - -[testenv:py36-pytest] -commands = {[testenv:pytest]commands} - -[testenv:py36-runtests] -deps = {[testenv:runtests]deps} -commands = {[testenv:runtests]commands} - -[testenv:py36-coverage] -deps = {[testenv:runtests]deps} -setenv = {[testenv:runtests-coverage]setenv} -commands = {[testenv:runtests-coverage]commands} -commands_pre = {[testenv:runtests-coverage]commands_pre} -commands_post = {[testenv:runtests-coverage]commands_post} - -[testenv:py36-runtests-coverage] -deps = {[testenv:runtests]deps} -setenv = {[testenv:runtests-coverage]setenv} -commands = {[testenv:runtests-coverage]commands} -commands_pre = {[testenv:runtests-coverage]commands_pre} -commands_post = {[testenv:runtests-coverage]commands_post} - -[testenv:py36-pytest-coverage] -setenv = {[testenv:runtests-coverage]setenv} -commands = {[testenv:pytest-coverage]commands} -commands_pre = {[testenv:pytest-coverage]commands_pre} -commands_post = {[testenv:pytest-coverage]commands_post} - + python -c 'import sys; sys.stderr.write("\n\nPlease use nox instead.\n\n"); sys.exit(1)' [testenv:pylint-salt] basepython = python2.7 @@ -228,8 +33,3 @@ commands = pylint --version pylint --rcfile=.testing.pylintrc --disable=I,W0232,E1002,W1307,C0411,C0413,W8410,str-format-in-logging {posargs:tests/} sitepackages = False - -[pytest] -addopts = --no-print-logs --ssh-tests -ra -sv -testpaths = tests -norecursedirs = tests/kitchen