From f28faa7fbf9b6b621a88f9d10b14964c718ecb19 Mon Sep 17 00:00:00 2001 From: Matt Clay Date: Tue, 29 Jul 2025 15:22:57 -0700 Subject: [PATCH] [stable-2.19] ansible-test - Fix coverage config (#85555) (#85559) (cherry picked from commit 35830cb05413bd3a2c8298e086b9a9ab23f9b9b1) --- .../ansible-test-coverage-config.yml | 7 +++ .../commands/integration/coverage.py | 4 +- .../ansible_test/_internal/coverage_util.py | 53 ++++++++++--------- 3 files changed, 37 insertions(+), 27 deletions(-) create mode 100644 changelogs/fragments/ansible-test-coverage-config.yml diff --git a/changelogs/fragments/ansible-test-coverage-config.yml b/changelogs/fragments/ansible-test-coverage-config.yml new file mode 100644 index 00000000000..66a23c84f16 --- /dev/null +++ b/changelogs/fragments/ansible-test-coverage-config.yml @@ -0,0 +1,7 @@ +bugfixes: + - ansible-test - Use a consistent coverage config for all collection testing. + - ansible-test - Always exclude the ``tests/output/`` directory from a collection's code coverage. + (https://github.com/ansible/ansible/issues/84244) + +minor_changes: + - ansible-test - Improve formatting of generated coverage config file. diff --git a/test/lib/ansible_test/_internal/commands/integration/coverage.py b/test/lib/ansible_test/_internal/commands/integration/coverage.py index f518b5bd372..21cf0537e0f 100644 --- a/test/lib/ansible_test/_internal/commands/integration/coverage.py +++ b/test/lib/ansible_test/_internal/commands/integration/coverage.py @@ -167,7 +167,7 @@ class PosixCoverageHandler(CoverageHandler[PosixConfig]): coverage_config_path = os.path.join(self.common_temp_path, COVERAGE_CONFIG_NAME) coverage_output_path = os.path.join(self.common_temp_path, ResultType.COVERAGE.name) - coverage_config = generate_coverage_config(self.args) + coverage_config = generate_coverage_config() write_text_file(coverage_config_path, coverage_config, create_directories=True) @@ -260,7 +260,7 @@ class PosixCoverageHandler(CoverageHandler[PosixConfig]): """Return a dictionary of variables for setup and teardown of POSIX coverage.""" return dict( common_temp_dir=self.common_temp_path, - coverage_config=generate_coverage_config(self.args), + coverage_config=generate_coverage_config(), coverage_config_path=os.path.join(self.common_temp_path, COVERAGE_CONFIG_NAME), coverage_output_path=os.path.join(self.common_temp_path, ResultType.COVERAGE.name), mode_directory=f'{MODE_DIRECTORY:04o}', diff --git a/test/lib/ansible_test/_internal/coverage_util.py b/test/lib/ansible_test/_internal/coverage_util.py index 07134419be1..1fbba2d9c7e 100644 --- a/test/lib/ansible_test/_internal/coverage_util.py +++ b/test/lib/ansible_test/_internal/coverage_util.py @@ -6,11 +6,10 @@ import dataclasses import os import sqlite3 import tempfile +import textwrap import typing as t from .config import ( - IntegrationConfig, - SanityConfig, TestConfig, ) @@ -217,7 +216,7 @@ def get_coverage_config(args: TestConfig) -> str: except AttributeError: pass - coverage_config = generate_coverage_config(args) + coverage_config = generate_coverage_config() if args.explain: temp_dir = '/tmp/coverage-temp-dir' @@ -235,10 +234,10 @@ def get_coverage_config(args: TestConfig) -> str: return path -def generate_coverage_config(args: TestConfig) -> str: +def generate_coverage_config() -> str: """Generate code coverage configuration for tests.""" if data_context().content.collection: - coverage_config = generate_collection_coverage_config(args) + coverage_config = generate_collection_coverage_config() else: coverage_config = generate_ansible_coverage_config() @@ -265,12 +264,29 @@ omit = */test/results/* """ + coverage_config = coverage_config.lstrip() + return coverage_config -def generate_collection_coverage_config(args: TestConfig) -> str: +def generate_collection_coverage_config() -> str: """Generate code coverage configuration for Ansible Collection tests.""" - coverage_config = """ + include_patterns = [ + # {base}/ansible_collections/{ns}/{col}/* + os.path.join(data_context().content.root, '*'), + # */ansible_collections/{ns}/{col}/* (required to pick up AnsiballZ coverage) + os.path.join('*', data_context().content.collection.directory, '*'), + ] + + omit_patterns = [ + # {base}/ansible_collections/{ns}/{col}/tests/output/* + os.path.join(data_context().content.root, data_context().content.results_path, '*'), + ] + + include = textwrap.indent('\n'.join(include_patterns), ' ' * 4) + omit = textwrap.indent('\n'.join(omit_patterns), ' ' * 4) + + coverage_config = f""" [run] branch = True concurrency = @@ -279,28 +295,15 @@ concurrency = 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/* +{include} 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 +{omit} +""" + + coverage_config = coverage_config.lstrip() return coverage_config