"""Utility code for facilitating collection of code coverage when running tests.""" from __future__ import (absolute_import, division, print_function) __metaclass__ = type import contextlib import os import tempfile from .config import ( IntegrationConfig, SanityConfig, TestConfig, ) from .io import ( write_text_file, ) from .util import ( COVERAGE_CONFIG_NAME, remove_tree, ) from .data import ( data_context, ) @contextlib.contextmanager def coverage_context(args): # type: (TestConfig) -> None """Content to set up and clean up code coverage configuration for tests.""" coverage_setup(args) try: yield finally: coverage_cleanup(args) def coverage_setup(args): # type: (TestConfig) -> None """Set up code coverage configuration before running tests.""" if not args.coverage: return coverage_config = generate_coverage_config(args) if args.explain: args.coverage_config_base_path = '/tmp/coverage-temp-dir' else: args.coverage_config_base_path = tempfile.mkdtemp() write_text_file(os.path.join(args.coverage_config_base_path, COVERAGE_CONFIG_NAME), coverage_config) def coverage_cleanup(args): # type: (TestConfig) -> None """Clean up code coverage configuration after tests have finished.""" if args.coverage_config_base_path and not args.explain: remove_tree(args.coverage_config_base_path) args.coverage_config_base_path = None 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 */test/results/* ''' 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 concurrency = multiprocessing parallel = True disable_warnings = no-data-collected ''' if isinstance(args, IntegrationConfig): coverage_config += ''' include = %s/* */%s/* ''' % (data_context().content.root, data_context().content.collection.directory) elif isinstance(args, SanityConfig): # temporary work-around for import sanity test coverage_config += ''' include = %s/* omit = %s/* ''' % (data_context().content.root, os.path.join(data_context().content.root, data_context().content.results_path)) else: coverage_config += ''' include = %s/* ''' % data_context().content.root return coverage_config