diff options
-rw-r--r-- | buildscripts/resmokelib/discovery/__init__.py | 142 | ||||
-rw-r--r-- | buildscripts/resmokelib/multiversionconstants.py | 4 | ||||
-rw-r--r-- | buildscripts/resmokelib/parser.py | 5 | ||||
-rw-r--r-- | buildscripts/resmokelib/plugin.py | 2 | ||||
-rw-r--r-- | buildscripts/resmokelib/testing/suite.py | 4 | ||||
-rw-r--r-- | buildscripts/tests/resmokelib/discovery/__init__.py | 1 | ||||
-rw-r--r-- | buildscripts/tests/resmokelib/discovery/test_discovery.py | 34 |
7 files changed, 190 insertions, 2 deletions
diff --git a/buildscripts/resmokelib/discovery/__init__.py b/buildscripts/resmokelib/discovery/__init__.py new file mode 100644 index 00000000000..2a01c49d0ed --- /dev/null +++ b/buildscripts/resmokelib/discovery/__init__.py @@ -0,0 +1,142 @@ +"""Subcommands for test discovery.""" +from typing import List, Optional + +import yaml +from pydantic import BaseModel + +import buildscripts.resmokelib.parser as _parser +from buildscripts.resmokelib import suitesconfig +from buildscripts.resmokelib.plugin import PluginInterface, Subcommand +from buildscripts.resmokelib.testing.suite import Suite + +TEST_DISCOVERY_SUBCOMMAND = "test-discovery" +SUITECONFIG_SUBCOMMAND = "suiteconfig" +MULTIVERSION_SUBCOMMAND = "multiversion-config" + + +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. + """ + _parser.set_run_options() + 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. + """ + _parser.set_run_options() + 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 MultiversionConfig(BaseModel): + """Multiversion Configuration.""" + + last_versions: List[str] + + +class MultiversionConfigSubcommand(Subcommand): + """Subcommand for discovering multiversion configuration.""" + + def execute(self): + """Execute the subcommand.""" + mv_config = self.determine_multiversion_config() + print(yaml.safe_dump(mv_config.dict())) + + @staticmethod + def determine_multiversion_config() -> MultiversionConfig: + """Discover the current multiversion configuration.""" + from buildscripts.resmokelib import multiversionconstants + return MultiversionConfig(last_versions=multiversionconstants.OLD_VERSIONS) + + +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 = subparsers.add_parser(SUITECONFIG_SUBCOMMAND, + help="Display configuration of a test suite.") + parser.add_argument("--suite", metavar="SUITE", help="Suite to run against.") + + parser = subparsers.add_parser(MULTIVERSION_SUBCOMMAND, + help="Display configuration for multiversion testing") + + def parse(self, subcommand, parser, parsed_args, **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: + return TestDiscoverySubcommand(parsed_args.suite) + if subcommand == SUITECONFIG_SUBCOMMAND: + return SuiteConfigSubcommand(parsed_args.suite) + if subcommand == MULTIVERSION_SUBCOMMAND: + return MultiversionConfigSubcommand() + return None diff --git a/buildscripts/resmokelib/multiversionconstants.py b/buildscripts/resmokelib/multiversionconstants.py index a25b9bdc2ae..6055e771c24 100644 --- a/buildscripts/resmokelib/multiversionconstants.py +++ b/buildscripts/resmokelib/multiversionconstants.py @@ -172,3 +172,7 @@ REQUIRES_FCV_TAG = ",".join([tag_str(fcv) for fcv in fcv_constants.requires_fcv_ # Generate evergreen project names for all FCVs less than latest. EVERGREEN_PROJECTS = ['mongodb-mongo-master'] EVERGREEN_PROJECTS.extend([evg_project_str(fcv) for fcv in fcv_constants.fcvs_less_than_latest]) + +OLD_VERSIONS = ["last_lts"] +if LAST_LTS_FCV != LAST_CONTINUOUS_FCV: + OLD_VERSIONS.append("last_continuous") diff --git a/buildscripts/resmokelib/parser.py b/buildscripts/resmokelib/parser.py index 70ec736ab95..d247d854b70 100644 --- a/buildscripts/resmokelib/parser.py +++ b/buildscripts/resmokelib/parser.py @@ -4,7 +4,9 @@ import argparse import shlex from buildscripts.resmokelib import configure_resmoke -from buildscripts.resmokelib.generate_fcv_constants import GenerateFCVConstantsPlugin +from buildscripts.resmokelib.discovery import DiscoveryPlugin +from buildscripts.resmokelib.generate_fcv_constants import \ + GenerateFCVConstantsPlugin from buildscripts.resmokelib.hang_analyzer import HangAnalyzerPlugin from buildscripts.resmokelib.powercycle import PowercyclePlugin from buildscripts.resmokelib.run import RunPlugin @@ -18,6 +20,7 @@ _PLUGINS = [ PowercyclePlugin(), SymbolizerPlugin(), GenerateFCVConstantsPlugin(), + DiscoveryPlugin(), ] diff --git a/buildscripts/resmokelib/plugin.py b/buildscripts/resmokelib/plugin.py index 3ce8f788d62..75a3ff9f317 100644 --- a/buildscripts/resmokelib/plugin.py +++ b/buildscripts/resmokelib/plugin.py @@ -8,7 +8,7 @@ class Subcommand(object): def execute(self): """Execute the subcommand.""" - raise NotImplementedError("execue must be implemented by Subcommand subclasses") + raise NotImplementedError("execute must be implemented by Subcommand subclasses") class PluginInterface(abc.ABC): diff --git a/buildscripts/resmokelib/testing/suite.py b/buildscripts/resmokelib/testing/suite.py index 5de8bdd5855..7d7b87c08dd 100644 --- a/buildscripts/resmokelib/testing/suite.py +++ b/buildscripts/resmokelib/testing/suite.py @@ -87,6 +87,10 @@ class Suite(object): # pylint: disable=too-many-instance-attributes # report intermediate results. self._partial_reports = None + def get_config(self): + """Return the configuration of this suite.""" + return self._suite_config + def __repr__(self): """Create a string representation of object for debugging.""" return f"{self.test_kind}:{self._suite_name}" diff --git a/buildscripts/tests/resmokelib/discovery/__init__.py b/buildscripts/tests/resmokelib/discovery/__init__.py new file mode 100644 index 00000000000..4b7a2bb941b --- /dev/null +++ b/buildscripts/tests/resmokelib/discovery/__init__.py @@ -0,0 +1 @@ +"""Empty.""" diff --git a/buildscripts/tests/resmokelib/discovery/test_discovery.py b/buildscripts/tests/resmokelib/discovery/test_discovery.py new file mode 100644 index 00000000000..e3a45e03e63 --- /dev/null +++ b/buildscripts/tests/resmokelib/discovery/test_discovery.py @@ -0,0 +1,34 @@ +"""Unit tests for discovery subcommand.""" + +import unittest +from unittest.mock import MagicMock + +import buildscripts.resmokelib.discovery as under_test +from buildscripts.resmokelib.testing.suite import Suite + +# pylint: disable=missing-docstring + + +class TestTestDiscoverySubCommand(unittest.TestCase): + def test_gather_tests_should_return_discovered_tests(self): + suite_name = "my suite" + mock_suite = MagicMock(spec_set=Suite) + mock_suite.get_display_name.return_value = suite_name + mock_suite.tests = [ + "test_0.js", + "test_1.js", + [ + "test_2.js", + "test_3.js", + "test_4.js", + ], + "test_5.js", + ] + test_discovery_subcommand = under_test.TestDiscoverySubcommand(suite_name) + + tests = test_discovery_subcommand.gather_tests(mock_suite) + + self.assertEqual(suite_name, tests.suite_name) + + for i in range(6): + self.assertIn(f"test_{i}.js", tests.tests) |