From ecc706f1225e4c05f88b7fc424ede8721e7c40e5 Mon Sep 17 00:00:00 2001 From: Matt Clay Date: Tue, 18 Sep 2018 08:37:14 -0700 Subject: [PATCH] Fix ansible-test unit test execution. (#45772) * Fix ansible-test units requirements install. * Run unit tests as unprivileged user under Docker. (cherry picked from commit 379a7f4f5a0491964c7896834f3f326412888585) --- test/runner/lib/config.py | 7 +++++++ test/runner/lib/delegation.py | 23 +++++++++++++++++++++++ test/runner/lib/executor.py | 19 +++++++++++++++---- test/runner/test.py | 4 ++++ tox.ini | 1 + 5 files changed, 50 insertions(+), 4 deletions(-) diff --git a/test/runner/lib/config.py b/test/runner/lib/config.py index 0cc34f21d34..eeb179cc398 100644 --- a/test/runner/lib/config.py +++ b/test/runner/lib/config.py @@ -237,6 +237,13 @@ class UnitsConfig(TestConfig): self.collect_only = args.collect_only # type: bool + self.requirements_mode = args.requirements_mode if 'requirements_mode' in args else '' + + if self.requirements_mode == 'only': + self.requirements = True + elif self.requirements_mode == 'skip': + self.requirements = False + class CoverageConfig(EnvironmentConfig): """Configuration for the coverage command.""" diff --git a/test/runner/lib/delegation.py b/test/runner/lib/delegation.py index b75bb97bb60..8392fc59a79 100644 --- a/test/runner/lib/delegation.py +++ b/test/runner/lib/delegation.py @@ -275,6 +275,29 @@ def delegate_docker(args, exclude, require, integration_targets): if isinstance(args, UnitsConfig) and not args.python: cmd += ['--python', 'default'] + # run unit tests unprivileged to prevent stray writes to the source tree + if isinstance(args, UnitsConfig): + writable_dirs = [ + '/root/ansible/lib/ansible.egg-info', + '/root/ansible/.pytest_cache', + ] + + docker_exec(args, test_id, ['mkdir', '-p'] + writable_dirs) + docker_exec(args, test_id, ['chmod', '777'] + writable_dirs) + + docker_exec(args, test_id, ['find', '/root/ansible/test/results/', '-type', 'd', '-exec', 'chmod', '777', '{}', '+']) + + docker_exec(args, test_id, ['chmod', '755', '/root']) + docker_exec(args, test_id, ['chmod', '644', '/root/ansible/%s' % args.metadata_path]) + + docker_exec(args, test_id, ['useradd', 'pytest', '--create-home']) + + docker_exec(args, test_id, cmd + ['--requirements-mode', 'only'], options=cmd_options) + + cmd += ['--requirements-mode', 'skip'] + + cmd_options += ['--user', 'pytest'] + try: docker_exec(args, test_id, cmd, options=cmd_options) finally: diff --git a/test/runner/lib/executor.py b/test/runner/lib/executor.py index 2911a141c5f..53913e91427 100644 --- a/test/runner/lib/executor.py +++ b/test/runner/lib/executor.py @@ -12,6 +12,7 @@ import time import textwrap import functools import pipes +import sys import hashlib import lib.pytar @@ -49,6 +50,8 @@ from lib.util import ( raw_command, get_coverage_path, get_available_port, + generate_pip_command, + find_python, ) from lib.docker_util import ( @@ -148,9 +151,10 @@ def create_shell_command(command): return cmd -def install_command_requirements(args): +def install_command_requirements(args, python_version=None): """ :type args: EnvironmentConfig + :type python_version: str | None """ generate_egg_info(args) @@ -168,7 +172,10 @@ def install_command_requirements(args): if args.junit: packages.append('junit-xml') - pip = args.pip_command + if not python_version: + python_version = args.python_version + + pip = generate_pip_command(find_python(python_version)) commands = [generate_pip_install(pip, args.command, packages=packages)] @@ -1133,8 +1140,6 @@ def command_units(args): if args.delegate: raise Delegate(require=changes) - install_command_requirements(args) - version_commands = [] for version in SUPPORTED_PYTHON_VERSIONS: @@ -1142,6 +1147,9 @@ def command_units(args): if args.python and version != args.python_version: continue + if args.requirements_mode != 'skip': + install_command_requirements(args, version) + env = ansible_environment(args) cmd = [ @@ -1167,6 +1175,9 @@ def command_units(args): version_commands.append((version, cmd, env)) + if args.requirements_mode == 'only': + sys.exit() + for version, command, env in version_commands: display.info('Unit test with Python %s' % version) diff --git a/test/runner/test.py b/test/runner/test.py index b8e4d1f87b7..1529dd3ee1e 100755 --- a/test/runner/test.py +++ b/test/runner/test.py @@ -335,6 +335,10 @@ def parse_args(): action='store_true', help='collect tests but do not execute them') + units.add_argument('--requirements-mode', + choices=('only', 'skip'), + help=argparse.SUPPRESS) + add_extra_docker_options(units, integration=False) sanity = subparsers.add_parser('sanity', diff --git a/tox.ini b/tox.ini index f460eb31394..33522366c38 100644 --- a/tox.ini +++ b/tox.ini @@ -21,6 +21,7 @@ passenv = [pytest] xfail_strict = true +cache_dir = .pytest_cache [flake8] # These are things that the devs don't agree make the code more readable