diff --git a/test/conftest.py b/test/conftest.py index 53ce240eb3..40293aafe5 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -66,6 +66,8 @@ def pytest_addoption(parser: pytest.Parser) -> None: "Will route the profiles to `tmpdir`/mode/coverage/`suite` and post process them in order to generate " "lcov file per suite, lcov file per mode, and an lcov file for the entire run, " "The lcov files can eventually be used for generating coverage reports") + parser.addoption("--coverage-mode", action='append', type=str, dest="coverage_modes", + help="Collect and process coverage only for the modes specified. implies: --coverage, default: All built modes") parser.addoption("--cluster-pool-size", type=int, help="Set the pool_size for PythonTest and its descendants. Alternatively environment variable " "CLUSTER_POOL_SIZE can be used to achieve the same") diff --git a/test/pylib/cpp/common_cpp_conftest.py b/test/pylib/cpp/common_cpp_conftest.py index 5ad3317a39..62b9850533 100644 --- a/test/pylib/cpp/common_cpp_conftest.py +++ b/test/pylib/cpp/common_cpp_conftest.py @@ -12,7 +12,7 @@ from pytest import Collector from test import ALL_MODES, DEBUG_MODES from test.pylib.cpp.facade import CppTestFacade -from test.pylib.cpp.item import CppFile +from test.pylib.cpp.item import CppFile, coverage from test.pylib.util import get_modes_to_run @@ -90,7 +90,8 @@ def collect_items(file_path: PosixPath, parent: Collector, facade: CppTestFacade ASAN_OPTIONS=":".join(filter(None, ASAN_OPTIONS)), SCYLLA_TEST_ENV='yes', ) - run_id = parent.config.getoption('run_id') + pytest_config = parent.config + run_id = pytest_config.getoption('run_id') modes = get_modes_to_run(parent.session.config) suite_config = read_suite_config(file_path.parent) no_parallel_cases = suite_config.get('no_parallel_cases', []) @@ -100,14 +101,17 @@ def collect_items(file_path: PosixPath, parent: Collector, facade: CppTestFacade extra_scylla_cmdline_options = suite_config.get('extra_scylla_cmdline_options', []) test_name = file_path.stem no_parallel_run = True if test_name in no_parallel_cases else False + coverage_config = coverage(pytest_config.getoption('coverage'), suite_config.get('coverage', True), + pytest_config.getoption('coverage_modes')) custom_args = custom_args_config.get(file_path.stem, ['-c2 -m2G']) args.extend(extra_scylla_cmdline_options) if len(custom_args) > 1: return CppFile.from_parent(parent=parent, path=file_path, arguments=args, parameters=custom_args, no_parallel_run=no_parallel_run, modes=modes, disabled_tests=disabled_tests, - run_id=run_id, facade=facade, env=test_env) + run_id=run_id, facade=facade, env=test_env, coverage_config=coverage_config) else: args.extend(custom_args) return CppFile.from_parent(parent=parent, path=file_path, arguments=args, no_parallel_run=no_parallel_run, - modes=modes, disabled_tests=disabled_tests, run_id=run_id, facade=facade, env=test_env) + modes=modes, disabled_tests=disabled_tests, run_id=run_id, facade=facade, + env=test_env, coverage_config=coverage_config) diff --git a/test/pylib/cpp/item.py b/test/pylib/cpp/item.py index 1963ecfba7..15f15bdcea 100644 --- a/test/pylib/cpp/item.py +++ b/test/pylib/cpp/item.py @@ -25,6 +25,9 @@ # from __future__ import annotations +from collections import namedtuple + +from scripts import coverage as coverage_script from pathlib import Path from typing import Sequence, Any, Iterator @@ -35,6 +38,8 @@ from _pytest._io import TerminalWriter from test import COMBINED_TESTS, BUILD_DIR from test.pylib.cpp.facade import CppTestFailure, CppTestFailureList, CppTestFacade +coverage = namedtuple('coverage', ['global_coverage_flag', 'suite_coverage_flag', 'coverage_modes']) + class CppFailureRepr(object): failure_sep = "---" @@ -122,8 +127,8 @@ class CppFile(pytest.File): Represents the C++ test file with all necessary information for test execution """ def __init__(self, *, no_parallel_run: bool = False, modes: list[str], disabled_tests: dict[str, set[str]], - run_id=None, facade: CppTestFacade, arguments: Sequence[str], parameters: list[str] = None, - env: dict = None, **kwargs: Any) -> None: + run_id=None, facade: CppTestFacade, arguments: Sequence[str], coverage_config: coverage, + parameters: list[str] = None, env: dict = None, **kwargs: Any) -> None: super().__init__(**kwargs) self.facade = facade self.modes = modes @@ -133,6 +138,7 @@ class CppFile(pytest.File): self.parameters = parameters self.env = env self._arguments = arguments + self.coverage_config = coverage_config def collect(self) -> Iterator[CppTestFunction]: for mode in self.modes: @@ -144,6 +150,8 @@ class CppFile(pytest.File): combined, tests = self.facade.list_tests(executable, self.no_parallel_run, mode) if combined: executable = executable.parent / COMBINED_TESTS.stem + if mode == "coverage": + self.env.update(coverage_script.env(executable)) for test_name in tests: if '/' in test_name: test_name = test_name.replace('/', '_')