diff options
Diffstat (limited to 'buildscripts/evergreen_generate_resmoke_tasks.py')
-rwxr-xr-x | buildscripts/evergreen_generate_resmoke_tasks.py | 54 |
1 files changed, 15 insertions, 39 deletions
diff --git a/buildscripts/evergreen_generate_resmoke_tasks.py b/buildscripts/evergreen_generate_resmoke_tasks.py index 230de932764..9e66986cbf5 100755 --- a/buildscripts/evergreen_generate_resmoke_tasks.py +++ b/buildscripts/evergreen_generate_resmoke_tasks.py @@ -6,7 +6,6 @@ Analyze the evergreen history for tests run under the given task and create new to attempt to keep the task runtime under a specified amount. """ -import datetime from datetime import timedelta import logging import math @@ -15,10 +14,9 @@ import re import sys from collections import defaultdict from distutils.util import strtobool # pylint: disable=no-name-in-module -from typing import Set +from typing import Set, List import click -import requests import structlog import yaml @@ -30,7 +28,7 @@ from shrub.task import TaskDependency from shrub.variant import DisplayTaskDefinition from shrub.variant import TaskSpec -from evergreen.api import EvergreenApi, RetryingEvergreenApi +from evergreen.api import RetryingEvergreenApi # Get relative imports to work when the package is not installed on the PYTHONPATH. if __name__ == "__main__" and __package__ is None: @@ -41,6 +39,7 @@ import buildscripts.util.read_config as read_config # pylint: disable=wrong-imp import buildscripts.util.taskname as taskname # pylint: disable=wrong-import-position import buildscripts.util.testname as testname # pylint: disable=wrong-import-position from buildscripts.util.fileops import read_yaml_file # pylint: disable=wrong-import-position +from buildscripts.util.teststats import get_stats_from_s3, HistoricalTestInformation # pylint: disable=wrong-import-position LOGGER = structlog.getLogger(__name__) @@ -50,7 +49,6 @@ AVG_SETUP_TIME = int(timedelta(minutes=5).total_seconds()) EVG_CONFIG_FILE = "./.evergreen.yml" GENERATE_CONFIG_FILE = "etc/generate_subtasks_config.yml" MIN_TIMEOUT_SECONDS = int(timedelta(minutes=5).total_seconds()) -LOOKBACK_DURATION_DAYS = 14 GEN_SUFFIX = "_gen" HEADER_TEMPLATE = """# DO NOT EDIT THIS FILE. All manual edits will be lost. @@ -584,7 +582,7 @@ def normalize_test_name(test_name): class TestStats(object): """Represent the test statistics for the task that is being analyzed.""" - def __init__(self, evg_test_stats_results): + def __init__(self, evg_test_stats_results: List[HistoricalTestInformation]) -> None: """Initialize the TestStats with raw results from the Evergreen API.""" # Mapping from test_file to {"num_run": X, "duration": Y} for tests self._runtime_by_test = defaultdict(dict) @@ -595,9 +593,9 @@ class TestStats(object): for doc in evg_test_stats_results: self._add_stats(doc) - def _add_stats(self, test_stats): + def _add_stats(self, test_stats: HistoricalTestInformation) -> None: """Add the statistics found in a document returned by the Evergreen test_stats/ endpoint.""" - test_file = testname.normalize_test_file(test_stats.test_file) + test_file = testname.normalize_test_file(test_stats.test_name) duration = test_stats.avg_duration_pass num_run = test_stats.num_pass is_hook = testname.is_resmoke_hook(test_file) @@ -701,36 +699,17 @@ class GenerateSubSuites(object): self.generate_options = generate_config self.test_list = [] - def calculate_suites(self, start_date, end_date): + def calculate_suites(self) -> List[Suite]: """Divide tests into suites based on statistics for the provided period.""" - try: - evg_stats = self.get_evg_stats(self.config_options.project, start_date, end_date, - self.config_options.task, self.config_options.variant) - if not evg_stats: - # This is probably a new suite, since there is no test history, just use the - # fallback values. - return self.calculate_fallback_suites() + evg_stats = get_stats_from_s3(self.config_options.project, self.config_options.task, + self.config_options.variant) + + if evg_stats: target_execution_time_secs = self.config_options.target_resmoke_time * 60 return self.calculate_suites_from_evg_stats(evg_stats, target_execution_time_secs) - except requests.HTTPError as err: - if err.response.status_code == requests.codes.SERVICE_UNAVAILABLE: - # Evergreen may return a 503 when the service is degraded. - # We fall back to splitting the tests into a fixed number of suites. - LOGGER.warning("Received 503 from Evergreen, " - "dividing the tests evenly among suites") - return self.calculate_fallback_suites() - else: - raise - - def get_evg_stats(self, project, start_date, end_date, task, variant): - """Collect test execution statistics data from Evergreen.""" - # pylint: disable=too-many-arguments - - days = (end_date - start_date).days - return self.evergreen_api.test_stats_by_project( - project, after_date=start_date.strftime("%Y-%m-%d"), - before_date=end_date.strftime("%Y-%m-%d"), tasks=[task], variants=[variant], - group_by="test", group_num_days=days) + + # Since there is no test history this is probably a new suite, just use the fallback values. + return self.calculate_fallback_suites() def calculate_suites_from_evg_stats(self, data, execution_time_secs): """Divide tests into suites that can be run in less than the specified execution time.""" @@ -778,12 +757,9 @@ class GenerateSubSuites(object): LOGGER.info("Not generating configuration due to previous successful generation.") return - end_date = datetime.datetime.utcnow().replace(microsecond=0) - start_date = end_date - datetime.timedelta(days=LOOKBACK_DURATION_DAYS) - prepare_directory_for_suite(CONFIG_DIR) - suites = self.calculate_suites(start_date, end_date) + suites = self.calculate_suites() LOGGER.debug("Creating suites", num_suites=len(suites), task=self.config_options.task) |