summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Bradford <david.bradford@mongodb.com>2021-10-31 19:49:26 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-02-23 21:24:10 +0000
commit26f0409fa99ac367923b1a32dd6c782fe5adca53 (patch)
tree23ca901df7b45937428e99a44081c6fb8007e0ee
parent60f8a0134bd837770ee75f85b2f144226529f4f3 (diff)
downloadmongo-26f0409fa99ac367923b1a32dd6c782fe5adca53.tar.gz
SERVER-63826: Add test discovery interface to resmoke
-rw-r--r--buildscripts/resmokelib/discovery/__init__.py142
-rw-r--r--buildscripts/resmokelib/multiversionconstants.py4
-rw-r--r--buildscripts/resmokelib/parser.py5
-rw-r--r--buildscripts/resmokelib/plugin.py2
-rw-r--r--buildscripts/resmokelib/testing/suite.py4
-rw-r--r--buildscripts/tests/resmokelib/discovery/__init__.py1
-rw-r--r--buildscripts/tests/resmokelib/discovery/test_discovery.py34
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)