mongo/buildscripts/resmokelib/discovery/__init__.py

150 lines
4.7 KiB
Python

"""Subcommands for test discovery."""
import argparse
from typing import List, Optional
import yaml
from pydantic import BaseModel
from buildscripts.resmokelib import configure_resmoke, suitesconfig
from buildscripts.resmokelib.multiversion.multiversion_service import (
MongoReleases,
MongoVersion,
MultiversionService,
)
from buildscripts.resmokelib.plugin import PluginInterface, Subcommand
from buildscripts.resmokelib.testing.suite import Suite
__all__ = ["MultiversionService", "MongoReleases", "MongoVersion"]
TEST_DISCOVERY_SUBCOMMAND = "test-discovery"
SUITECONFIG_SUBCOMMAND = "suiteconfig"
class SuiteTestList(BaseModel):
"""Collection of tests belonging to a suite."""
suite_name: str
tests: List[str]
class TestDiscoverySubcommand(Subcommand):
"""Subcommand for test discovery."""
def __init__(self, suite_name: str) -> None:
"""
Initialize the subcommand.
:param suite_name: Suite to discover.
"""
self.suite_name = suite_name
self.suite_config = suitesconfig
def execute(self):
"""Execute the subcommand."""
suite = self.suite_config.get_suite(self.suite_name)
test_list = self.gather_tests(suite)
print(yaml.safe_dump(test_list.dict()))
@staticmethod
def gather_tests(suite: Suite) -> SuiteTestList:
"""
Find all the tests that belong to the given suite.
:param suite: Suite to query.
:return: List of tests belonging to the suite.
"""
test_list = []
for tests in suite.tests:
# `tests` could return individual tests or lists of tests, we need to handle both.
if isinstance(tests, list):
test_list.extend(tests)
else:
test_list.append(tests)
return SuiteTestList(
suite_name=suite.get_display_name(),
tests=test_list,
)
class SuiteConfigSubcommand(Subcommand):
"""Subcommand for discovering configuration of a suite."""
def __init__(self, suite_name: str) -> None:
"""
Initialize the subcommand.
:param suite_name: Suite to discover.
"""
self.suite_name = suite_name
self.suite_config = suitesconfig
def execute(self):
"""Execute the subcommand."""
suite = self.suite_config.get_suite(self.suite_name)
print(yaml.safe_dump(suite.get_config()))
class DiscoveryPlugin(PluginInterface):
"""Test discovery plugin."""
def add_subcommand(self, subparsers) -> None:
"""
Add parser options for this plugin.
:param subparsers: argparse subparsers
"""
parser = subparsers.add_parser(
TEST_DISCOVERY_SUBCOMMAND, help="Discover what tests are run by a suite."
)
parser.add_argument("--suite", metavar="SUITE", help="Suite to run against.")
parser.add_argument(
"--skipTestsCoveredByMoreComplexSuites",
dest="skip_tests_covered_by_more_complex_suites",
action="store_true",
help=(
"Excludes tests from running on some suite_A if a more complex"
" suite_A_B will also run the same tests."
),
)
parser.add_argument(
"--includeFullyDisabledFeatureTests",
dest="include_fully_disabled_feature_tests",
action="store_true",
help=(
"Include tests tagged with features that are in fully_disabled_feature_flags.yml."
),
)
parser = subparsers.add_parser(
SUITECONFIG_SUBCOMMAND, help="Display configuration of a test suite."
)
parser.add_argument("--suite", metavar="SUITE", help="Suite to run against.")
def parse(
self,
subcommand: str,
parser: argparse.ArgumentParser,
parsed_args: dict,
should_configure_otel: bool = True,
**kwargs,
) -> Optional[Subcommand]:
"""
Resolve command-line options to a Subcommand or None.
:param subcommand: equivalent to parsed_args.command.
:param parser: parser used.
:param parsed_args: output of parsing.
:param kwargs: additional args.
:return: None or a Subcommand.
"""
if subcommand == TEST_DISCOVERY_SUBCOMMAND:
configure_resmoke.validate_and_update_config(parser, parsed_args, should_configure_otel)
return TestDiscoverySubcommand(parsed_args["suite"])
if subcommand == SUITECONFIG_SUBCOMMAND:
configure_resmoke.validate_and_update_config(parser, parsed_args, should_configure_otel)
return SuiteConfigSubcommand(parsed_args["suite"])
return None