2019-04-10 17:42:47 +02:00
|
|
|
#!/usr/bin/env python3
|
2018-03-27 20:30:46 +02:00
|
|
|
"""Command line utility for executing MongoDB tests in Evergreen."""
|
2017-10-18 07:45:51 +02:00
|
|
|
|
|
|
|
import collections
|
|
|
|
import os.path
|
|
|
|
import sys
|
|
|
|
|
|
|
|
# Get relative imports to work when the package is not installed on the PYTHONPATH.
|
|
|
|
if __name__ == "__main__" and __package__ is None:
|
|
|
|
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
|
|
|
2018-03-27 20:30:46 +02:00
|
|
|
from buildscripts import resmoke # pylint: disable=wrong-import-position
|
|
|
|
from buildscripts import resmokelib # pylint: disable=wrong-import-position
|
2017-10-18 07:45:51 +02:00
|
|
|
|
|
|
|
_TagInfo = collections.namedtuple("_TagInfo", ["tag_name", "evergreen_aware", "suite_options"])
|
|
|
|
|
|
|
|
|
2018-04-11 19:49:29 +02:00
|
|
|
class Main(resmoke.Resmoke):
|
2018-03-27 20:30:46 +02:00
|
|
|
"""Execute Main class.
|
|
|
|
|
2017-10-18 07:45:51 +02:00
|
|
|
A class for executing potentially multiple resmoke.py test suites in a way that handles
|
|
|
|
additional options for running unreliable tests in Evergreen.
|
|
|
|
"""
|
|
|
|
|
2018-03-27 20:30:46 +02:00
|
|
|
UNRELIABLE_TAG = _TagInfo(
|
|
|
|
tag_name="unreliable",
|
|
|
|
evergreen_aware=True,
|
|
|
|
suite_options=resmokelib.config.SuiteOptions.ALL_INHERITED._replace( # type: ignore
|
|
|
|
report_failure_status="silentfail"))
|
2017-10-18 07:45:51 +02:00
|
|
|
|
|
|
|
RESOURCE_INTENSIVE_TAG = _TagInfo(
|
2018-03-27 20:30:46 +02:00
|
|
|
tag_name="resource_intensive",
|
|
|
|
evergreen_aware=False,
|
|
|
|
suite_options=resmokelib.config.SuiteOptions.ALL_INHERITED._replace( # type: ignore
|
|
|
|
num_jobs=1))
|
2017-10-18 07:45:51 +02:00
|
|
|
|
|
|
|
RETRY_ON_FAILURE_TAG = _TagInfo(
|
2018-03-27 20:30:46 +02:00
|
|
|
tag_name="retry_on_failure",
|
|
|
|
evergreen_aware=True,
|
|
|
|
suite_options=resmokelib.config.SuiteOptions.ALL_INHERITED._replace( # type: ignore
|
2018-08-29 16:35:33 +02:00
|
|
|
fail_fast=False, num_repeat_suites=2, num_repeat_tests=1,
|
|
|
|
report_failure_status="silentfail"))
|
2017-10-18 07:45:51 +02:00
|
|
|
|
2018-03-27 20:30:46 +02:00
|
|
|
@staticmethod
|
|
|
|
def _make_evergreen_aware_tags(tag_name):
|
|
|
|
"""Return a list of resmoke.py tags.
|
|
|
|
|
|
|
|
This list is for task, variant, and distro combinations in Evergreen.
|
2017-10-18 07:45:51 +02:00
|
|
|
"""
|
|
|
|
|
|
|
|
tags_format = ["{tag_name}"]
|
|
|
|
|
|
|
|
if resmokelib.config.EVERGREEN_TASK_NAME is not None:
|
|
|
|
tags_format.append("{tag_name}|{task_name}")
|
|
|
|
|
|
|
|
if resmokelib.config.EVERGREEN_VARIANT_NAME is not None:
|
|
|
|
tags_format.append("{tag_name}|{task_name}|{variant_name}")
|
|
|
|
|
|
|
|
if resmokelib.config.EVERGREEN_DISTRO_ID is not None:
|
|
|
|
tags_format.append("{tag_name}|{task_name}|{variant_name}|{distro_id}")
|
|
|
|
|
2018-03-26 17:25:04 +02:00
|
|
|
return [
|
|
|
|
tag.format(tag_name=tag_name, task_name=resmokelib.config.EVERGREEN_TASK_NAME,
|
|
|
|
variant_name=resmokelib.config.EVERGREEN_VARIANT_NAME,
|
|
|
|
distro_id=resmokelib.config.EVERGREEN_DISTRO_ID) for tag in tags_format
|
|
|
|
]
|
2017-10-18 07:45:51 +02:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def _make_tag_combinations(cls):
|
2018-03-27 20:30:46 +02:00
|
|
|
"""Return a list of (tag, enabled) pairs.
|
|
|
|
|
|
|
|
These pairs represent all possible combinations of all possible pairings
|
|
|
|
of whether the tags are enabled or disabled together.
|
2017-10-18 07:45:51 +02:00
|
|
|
"""
|
|
|
|
|
|
|
|
combinations = []
|
|
|
|
|
|
|
|
if resmokelib.config.EVERGREEN_PATCH_BUILD:
|
2018-03-26 17:25:04 +02:00
|
|
|
combinations.append(("unreliable and resource intensive",
|
|
|
|
((cls.UNRELIABLE_TAG, True), (cls.RESOURCE_INTENSIVE_TAG, True))))
|
|
|
|
combinations.append(("unreliable and not resource intensive",
|
|
|
|
((cls.UNRELIABLE_TAG, True), (cls.RESOURCE_INTENSIVE_TAG, False))))
|
|
|
|
combinations.append(("reliable and resource intensive",
|
|
|
|
((cls.UNRELIABLE_TAG, False), (cls.RESOURCE_INTENSIVE_TAG, True))))
|
|
|
|
combinations.append(("reliable and not resource intensive",
|
|
|
|
((cls.UNRELIABLE_TAG, False), (cls.RESOURCE_INTENSIVE_TAG,
|
|
|
|
False))))
|
2017-10-18 07:45:51 +02:00
|
|
|
else:
|
2018-03-26 17:25:04 +02:00
|
|
|
combinations.append(("retry on failure and resource intensive",
|
|
|
|
((cls.RETRY_ON_FAILURE_TAG, True), (cls.RESOURCE_INTENSIVE_TAG,
|
|
|
|
True))))
|
|
|
|
combinations.append(("retry on failure and not resource intensive",
|
|
|
|
((cls.RETRY_ON_FAILURE_TAG, True), (cls.RESOURCE_INTENSIVE_TAG,
|
|
|
|
False))))
|
|
|
|
combinations.append(("run once and resource intensive",
|
|
|
|
((cls.RETRY_ON_FAILURE_TAG, False), (cls.RESOURCE_INTENSIVE_TAG,
|
|
|
|
True))))
|
|
|
|
combinations.append(("run once and not resource intensive",
|
|
|
|
((cls.RETRY_ON_FAILURE_TAG, False), (cls.RESOURCE_INTENSIVE_TAG,
|
|
|
|
False))))
|
2017-10-18 07:45:51 +02:00
|
|
|
|
|
|
|
return combinations
|
|
|
|
|
|
|
|
def _get_suites(self):
|
2018-03-27 20:30:46 +02:00
|
|
|
"""Return a list of resmokelib.testing.suite.Suite instances to execute.
|
2017-10-18 07:45:51 +02:00
|
|
|
|
|
|
|
For every resmokelib.testing.suite.Suite instance returned by resmoke.Main._get_suites(),
|
|
|
|
multiple copies of that test suite are run using different resmokelib.config.SuiteOptions()
|
|
|
|
depending on whether each tag in the combination is enabled or not.
|
|
|
|
"""
|
|
|
|
|
|
|
|
suites = []
|
|
|
|
|
2018-04-11 19:49:29 +02:00
|
|
|
for suite in resmoke.Resmoke._get_suites(self):
|
2017-10-18 07:45:51 +02:00
|
|
|
if suite.test_kind != "js_test":
|
|
|
|
# Tags are only support for JavaScript tests, so we leave the test suite alone when
|
|
|
|
# running any other kind of test.
|
|
|
|
suites.append(suite)
|
|
|
|
continue
|
|
|
|
|
|
|
|
for (tag_desc, tag_combo) in self._make_tag_combinations():
|
|
|
|
suite_options_list = []
|
|
|
|
|
|
|
|
for (tag_info, enabled) in tag_combo:
|
|
|
|
if tag_info.evergreen_aware:
|
|
|
|
tags = self._make_evergreen_aware_tags(tag_info.tag_name)
|
|
|
|
include_tags = {"$anyOf": tags}
|
|
|
|
else:
|
|
|
|
include_tags = tag_info.tag_name
|
|
|
|
|
|
|
|
if enabled:
|
|
|
|
suite_options = tag_info.suite_options._replace(include_tags=include_tags)
|
|
|
|
else:
|
|
|
|
suite_options = resmokelib.config.SuiteOptions.ALL_INHERITED._replace(
|
|
|
|
include_tags={"$not": include_tags})
|
|
|
|
|
|
|
|
suite_options_list.append(suite_options)
|
|
|
|
|
|
|
|
suite_options = resmokelib.config.SuiteOptions.combine(*suite_options_list)
|
|
|
|
suite_options = suite_options._replace(description=tag_desc)
|
|
|
|
suites.append(suite.with_options(suite_options))
|
|
|
|
|
|
|
|
return suites
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
2018-04-11 22:20:54 +02:00
|
|
|
main = Main() # pylint: disable=invalid-name
|
2018-04-11 19:49:29 +02:00
|
|
|
main.configure_from_command_line()
|
|
|
|
main.run()
|