Move ansible-test coverage config to test/lib/

This commit is contained in:
Matt Clay 2019-08-07 11:43:42 -07:00
parent 2e7d36a3f9
commit 5f67b5a757
11 changed files with 79 additions and 72 deletions

View file

@ -1,26 +0,0 @@
# This configuration file is used for manual execution of coverage
# as well as for tests run through ansible-test.
[run]
branch = True
# Enable concurrency. This also enables parallel mode, which results in
# multiple coverage files being created. Concurrency allows us to collect
# results from multiple tests simultaneously, as well as supporting multiple
# test runs, such as from integration tests.
concurrency = multiprocessing
parallel = True
# When running tests through ansible-test, this option is overridden by
# the COVERAGE_FILE environment variable. This option is present for
# convenience when running coverage manually from this directory.
data_file = test/results/coverage/coverage
# Don't collect or report code coverage from files matching these patterns.
omit =
*/python*/dist-packages/*
*/python*/site-packages/*
*/python*/distutils/*
*/pyshared/*
*/pytest
*/AnsiballZ_*.py

View file

@ -2,7 +2,6 @@ include README.rst
include COPYING
include SYMLINK_CACHE.json
include requirements.txt
include .coveragerc
include shippable.yml
include bin/ansible-test
include examples/hosts

View file

View file

@ -836,7 +836,6 @@ class PathMapper:
if path in (
'shippable.yml',
'.coveragerc',
):
return all_tests(self.args) # test infrastructure, run all tests

View file

@ -14,6 +14,7 @@ from .util import (
display,
ApplicationError,
common_environment,
ANSIBLE_TEST_DATA_ROOT,
)
from .util_common import (
@ -37,6 +38,7 @@ from .data import (
COVERAGE_DIR = 'test/results/coverage'
COVERAGE_FILE = os.path.join(COVERAGE_DIR, 'coverage')
COVERAGE_GROUPS = ('command', 'target', 'environment', 'version')
COVERAGE_CONFIG_PATH = os.path.join(ANSIBLE_TEST_DATA_ROOT, 'coveragerc')
def command_coverage_combine(args):
@ -239,7 +241,7 @@ def command_coverage_report(args):
env = common_environment()
env.update(dict(COVERAGE_FILE=output_file))
run_command(args, env=env, cmd=['coverage', 'report'] + options)
run_command(args, env=env, cmd=['coverage', 'report', '--rcfile', COVERAGE_CONFIG_PATH] + options)
def command_coverage_html(args):
@ -252,7 +254,7 @@ def command_coverage_html(args):
dir_name = 'test/results/reports/%s' % os.path.basename(output_file)
env = common_environment()
env.update(dict(COVERAGE_FILE=output_file))
run_command(args, env=env, cmd=['coverage', 'html', '-i', '-d', dir_name])
run_command(args, env=env, cmd=['coverage', 'html', '--rcfile', COVERAGE_CONFIG_PATH, '-i', '-d', dir_name])
def command_coverage_xml(args):
@ -265,7 +267,7 @@ def command_coverage_xml(args):
xml_name = 'test/results/reports/%s.xml' % os.path.basename(output_file)
env = common_environment()
env.update(dict(COVERAGE_FILE=output_file))
run_command(args, env=env, cmd=['coverage', 'xml', '-i', '-o', xml_name])
run_command(args, env=env, cmd=['coverage', 'xml', '--rcfile', COVERAGE_CONFIG_PATH, '-i', '-o', xml_name])
def command_coverage_erase(args):

View file

@ -13,7 +13,7 @@ from .config import (
)
from .util import (
COVERAGE_CONFIG_PATH,
COVERAGE_CONFIG_NAME,
remove_tree,
)
@ -35,16 +35,18 @@ def coverage_context(args): # type: (TestConfig) -> None
def coverage_setup(args): # type: (TestConfig) -> None
"""Set up code coverage configuration before running tests."""
if args.coverage and data_context().content.collection:
coverage_config = generate_collection_coverage_config(args)
if not args.coverage:
return
if args.explain:
args.coverage_config_base_path = '/tmp/coverage-temp-dir'
else:
args.coverage_config_base_path = tempfile.mkdtemp()
coverage_config = generate_coverage_config(args)
with open(os.path.join(args.coverage_config_base_path, COVERAGE_CONFIG_PATH), 'w') as coverage_config_path_fd:
coverage_config_path_fd.write(coverage_config)
if args.explain:
args.coverage_config_base_path = '/tmp/coverage-temp-dir'
else:
args.coverage_config_base_path = tempfile.mkdtemp()
with open(os.path.join(args.coverage_config_base_path, COVERAGE_CONFIG_NAME), 'w') as coverage_config_path_fd:
coverage_config_path_fd.write(coverage_config)
def coverage_cleanup(args): # type: (TestConfig) -> None
@ -54,8 +56,38 @@ def coverage_cleanup(args): # type: (TestConfig) -> None
args.coverage_config_base_path = None
def generate_collection_coverage_config(args): # type: (TestConfig) -> str
def generate_coverage_config(args): # type: (TestConfig) -> str
"""Generate code coverage configuration for tests."""
if data_context().content.collection:
coverage_config = generate_collection_coverage_config(args)
else:
coverage_config = generate_ansible_coverage_config()
return coverage_config
def generate_ansible_coverage_config(): # type: () -> str
"""Generate code coverage configuration for Ansible tests."""
coverage_config = '''
[run]
branch = True
concurrency = multiprocessing
parallel = True
omit =
*/python*/dist-packages/*
*/python*/site-packages/*
*/python*/distutils/*
*/pyshared/*
*/pytest
*/AnsiballZ_*.py
'''
return coverage_config
def generate_collection_coverage_config(args): # type: (TestConfig) -> str
"""Generate code coverage configuration for Ansible Collection tests."""
coverage_config = '''
[run]
branch = True

View file

@ -58,7 +58,7 @@ from .util import (
find_python,
get_docker_completion,
get_remote_completion,
COVERAGE_OUTPUT_PATH,
COVERAGE_OUTPUT_NAME,
cmd_quote,
ANSIBLE_ROOT,
ANSIBLE_TEST_DATA_ROOT,
@ -985,7 +985,7 @@ def command_integration_filtered(args, targets, all_targets, inventory_path, pre
finally:
if not args.explain:
if args.coverage:
coverage_temp_path = os.path.join(common_temp_path, COVERAGE_OUTPUT_PATH)
coverage_temp_path = os.path.join(common_temp_path, COVERAGE_OUTPUT_NAME)
coverage_save_path = 'test/results/coverage'
for filename in os.listdir(coverage_temp_path):

View file

@ -23,8 +23,8 @@ from ..util import (
ApplicationError,
display,
make_dirs,
COVERAGE_CONFIG_PATH,
COVERAGE_OUTPUT_PATH,
COVERAGE_CONFIG_NAME,
COVERAGE_OUTPUT_NAME,
MODE_DIRECTORY,
MODE_DIRECTORY_WRITE,
MODE_FILE,
@ -37,7 +37,7 @@ from ..util_common import (
)
from ..coverage_util import (
generate_collection_coverage_config,
generate_coverage_config,
)
from ..cache import (
@ -48,10 +48,6 @@ from ..cloud import (
CloudEnvironmentConfig,
)
from ..data import (
data_context,
)
def setup_common_temp_dir(args, path):
"""
@ -64,22 +60,20 @@ def setup_common_temp_dir(args, path):
os.mkdir(path)
os.chmod(path, MODE_DIRECTORY)
coverage_config_path = os.path.join(path, COVERAGE_CONFIG_PATH)
if args.coverage:
coverage_config_path = os.path.join(path, COVERAGE_CONFIG_NAME)
if data_context().content.collection:
coverage_config = generate_collection_coverage_config(args)
coverage_config = generate_coverage_config(args)
with open(coverage_config_path, 'w') as coverage_config_fd:
coverage_config_fd.write(coverage_config)
else:
shutil.copy(os.path.join(ANSIBLE_ROOT, COVERAGE_CONFIG_PATH), coverage_config_path)
os.chmod(coverage_config_path, MODE_FILE)
os.chmod(coverage_config_path, MODE_FILE)
coverage_output_path = os.path.join(path, COVERAGE_OUTPUT_PATH)
coverage_output_path = os.path.join(path, COVERAGE_OUTPUT_NAME)
os.mkdir(coverage_output_path)
os.chmod(coverage_output_path, MODE_DIRECTORY_WRITE)
os.mkdir(coverage_output_path)
os.chmod(coverage_output_path, MODE_DIRECTORY_WRITE)
def generate_dependency_map(integration_targets):

View file

@ -79,7 +79,7 @@ class ManageWindowsCI:
for dummy in range(1, 120):
try:
intercept_command(self.core_ci.args, cmd, 'ping', env=env)
intercept_command(self.core_ci.args, cmd, 'ping', env=env, disable_coverage=True)
return
except SubprocessError:
time.sleep(10)
@ -171,7 +171,7 @@ class ManageNetworkCI:
for dummy in range(1, 90):
try:
intercept_command(self.core_ci.args, cmd, 'ping', env=env)
intercept_command(self.core_ci.args, cmd, 'ping', env=env, disable_coverage=True)
return
except SubprocessError:
time.sleep(10)

View file

@ -59,8 +59,8 @@ try:
except AttributeError:
MAXFD = -1
COVERAGE_CONFIG_PATH = '.coveragerc'
COVERAGE_OUTPUT_PATH = 'coverage'
COVERAGE_CONFIG_NAME = 'coveragerc'
COVERAGE_OUTPUT_NAME = 'coverage'
ANSIBLE_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
ANSIBLE_TEST_ROOT = os.path.join(ANSIBLE_ROOT, 'test', 'lib', 'ansible_test')

View file

@ -11,8 +11,8 @@ import textwrap
from .util import (
common_environment,
COVERAGE_CONFIG_PATH,
COVERAGE_OUTPUT_PATH,
COVERAGE_CONFIG_NAME,
COVERAGE_OUTPUT_NAME,
display,
find_python,
ANSIBLE_ROOT,
@ -155,16 +155,22 @@ def get_coverage_environment(args, target_name, version, temp_path, module_cover
# config and results are in a temporary directory
coverage_config_base_path = temp_path
coverage_output_base_path = temp_path
else:
elif args.coverage_config_base_path:
# unit tests, sanity tests and other special cases (localhost only)
# config and results are in the source tree
coverage_config_base_path = args.coverage_config_base_path or ANSIBLE_ROOT
# config is in a temporary directory
# results are in the source tree
coverage_config_base_path = args.coverage_config_base_path
coverage_output_base_path = os.path.abspath(os.path.join('test/results'))
else:
raise Exception('No temp path and no coverage config base path. Check for missing coverage_context usage.')
config_file = os.path.join(coverage_config_base_path, COVERAGE_CONFIG_PATH)
coverage_file = os.path.join(coverage_output_base_path, COVERAGE_OUTPUT_PATH, '%s=%s=%s=%s=coverage' % (
config_file = os.path.join(coverage_config_base_path, COVERAGE_CONFIG_NAME)
coverage_file = os.path.join(coverage_output_base_path, COVERAGE_OUTPUT_NAME, '%s=%s=%s=%s=coverage' % (
args.command, target_name, args.coverage_label or 'local-%s' % version, 'python-%s' % version))
if not args.explain and not os.path.exists(config_file):
raise Exception('Missing coverage config file: %s' % config_file)
if args.coverage_check:
# cause the 'coverage' module to be found, but not imported or enabled
coverage_file = ''
@ -190,7 +196,7 @@ def get_coverage_environment(args, target_name, version, temp_path, module_cover
def intercept_command(args, cmd, target_name, env, capture=False, data=None, cwd=None, python_version=None, temp_path=None, module_coverage=True,
virtualenv=None):
virtualenv=None, disable_coverage=False):
"""
:type args: TestConfig
:type cmd: collections.Iterable[str]
@ -203,6 +209,7 @@ def intercept_command(args, cmd, target_name, env, capture=False, data=None, cwd
:type temp_path: str | None
:type module_coverage: bool
:type virtualenv: str | None
:type disable_coverage: bool
:rtype: str | None, str | None
"""
if not env:
@ -223,7 +230,7 @@ def intercept_command(args, cmd, target_name, env, capture=False, data=None, cwd
env['ANSIBLE_TEST_PYTHON_VERSION'] = version
env['ANSIBLE_TEST_PYTHON_INTERPRETER'] = interpreter
if args.coverage:
if args.coverage and not disable_coverage:
# add the necessary environment variables to enable code coverage collection
env.update(get_coverage_environment(args, target_name, version, temp_path, module_coverage))