diff options
| author | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2025-02-11 15:07:35 -0300 |
|---|---|---|
| committer | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2025-02-11 15:07:35 -0300 |
| commit | 4cb8841196d0625dfa3825aa326f071cd27c7b8b (patch) | |
| tree | 1682a647d4463397c119183369ae6f750d5fdcff /buildscripts/util/teststats.py | |
| parent | aa03c6362cbaa767638e6eed9b031d86dd2643d1 (diff) | |
| parent | 8f0827553e09872941945a093b647a4211a9db7f (diff) | |
Update upstream source from tag 'upstream/6.0.0'master
Update to upstream version '6.0.0'
with Debian dir 5604a80ec1c96ca76f25f40d78e6ef855abec322
Diffstat (limited to 'buildscripts/util/teststats.py')
| -rw-r--r-- | buildscripts/util/teststats.py | 89 |
1 files changed, 27 insertions, 62 deletions
diff --git a/buildscripts/util/teststats.py b/buildscripts/util/teststats.py index 74ef9c5ab3e..a52fa3c79a4 100644 --- a/buildscripts/util/teststats.py +++ b/buildscripts/util/teststats.py @@ -1,35 +1,15 @@ """Utility to support parsing a TestStat.""" from collections import defaultdict from dataclasses import dataclass +from datetime import datetime from itertools import chain -from json import JSONDecodeError - from typing import NamedTuple, List, Callable, Optional -import requests -from requests.adapters import HTTPAdapter, Retry + +from evergreen import EvergreenApi, TestStats from buildscripts.util.testname import split_test_hook_name, is_resmoke_hook, get_short_name_from_test_file TASK_LEVEL_HOOKS = {"CleanEveryN"} -TESTS_STATS_S3_LOCATION = "https://mongo-test-stats.s3.amazonaws.com" - - -class HistoricalTestInformation(NamedTuple): - """ - Container for information about the historical runtime of a test. - - test_name: Name of test. - avg_duration_pass: Average of runtime of test that passed. - num_pass: Number of times the test has passed. - num_fail: Number of times the test has failed. - max_duration_pass: Maximum runtime of the test when it passed. - """ - - test_name: str - num_pass: int - num_fail: int - avg_duration_pass: float - max_duration_pass: Optional[float] = None class TestRuntime(NamedTuple): @@ -94,9 +74,9 @@ class HistoricHookInfo(NamedTuple): avg_duration: float @classmethod - def from_test_stats(cls, test_stats: HistoricalTestInformation) -> "HistoricHookInfo": + def from_test_stats(cls, test_stats: TestStats) -> "HistoricHookInfo": """Create an instance from a test_stats object.""" - return cls(hook_id=test_stats.test_name, num_pass=test_stats.num_pass, + return cls(hook_id=test_stats.test_file, num_pass=test_stats.num_pass, avg_duration=test_stats.avg_duration_pass) def test_name(self) -> str: @@ -121,10 +101,10 @@ class HistoricTestInfo(NamedTuple): hooks: List[HistoricHookInfo] @classmethod - def from_test_stats(cls, test_stats: HistoricalTestInformation, + def from_test_stats(cls, test_stats: TestStats, hooks: List[HistoricHookInfo]) -> "HistoricTestInfo": """Create an instance from a test_stats object.""" - return cls(test_name=test_stats.test_name, num_pass=test_stats.num_pass, + return cls(test_name=test_stats.test_file, num_pass=test_stats.num_pass, avg_duration=test_stats.avg_duration_pass, hooks=hooks) def normalized_test_name(self) -> str: @@ -143,9 +123,7 @@ class HistoricTestInfo(NamedTuple): def total_test_runtime(self) -> float: """Get the average runtime of this test and it's non-task level hooks.""" - if self.num_pass > 0: - return self.avg_duration + self.total_hook_runtime(lambda h: not h.is_task_level_hook()) - return 0.0 + return self.avg_duration + self.total_hook_runtime(lambda h: not h.is_task_level_hook()) def get_hook_overhead(self) -> float: """Get the average runtime of this test and it's non-task level hooks.""" @@ -159,59 +137,46 @@ class HistoricTaskData(object): """Initialize the TestStats with raw results from the Evergreen API.""" self.historic_test_results = historic_test_results - @staticmethod - def get_stats_from_s3(project: str, task: str, variant: str) -> List[HistoricalTestInformation]: - """ - Retrieve test stats from s3 for a given task. - - :param project: Project to query. - :param task: Task to query. - :param variant: Build variant to query. - :return: A list of the Test stats for the specified task. - """ - session = requests.Session() - retries = Retry(total=5, backoff_factor=1, status_forcelist=[502, 503, 504]) - session.mount('https://', HTTPAdapter(max_retries=retries)) - - response = session.get(f"{TESTS_STATS_S3_LOCATION}/{project}/{variant}/{task}") - - try: - data = response.json() - return [HistoricalTestInformation(**item) for item in data] - except JSONDecodeError: - return [] - + # pylint: disable=too-many-arguments @classmethod - def from_s3(cls, project: str, task: str, variant: str) -> "HistoricTaskData": + def from_evg(cls, evg_api: EvergreenApi, project: str, start_date: datetime, end_date: datetime, + task: str, variant: str) -> "HistoricTaskData": """ - Retrieve test stats from s3 for a given task. + Retrieve test stats from evergreen for a given task. + :param evg_api: Evergreen API client. :param project: Project to query. + :param start_date: Start date to query. + :param end_date: End date to query. :param task: Task to query. :param variant: Build variant to query. :return: Test stats for the specified task. """ - historical_test_data = cls.get_stats_from_s3(project, task, variant) - return cls.from_stats_list(historical_test_data) + days = (end_date - start_date).days + historic_stats = evg_api.test_stats_by_project( + project, after_date=start_date, before_date=end_date, tasks=[task], variants=[variant], + group_by="test", group_num_days=days) + + return cls.from_stats_list(historic_stats) @classmethod - def from_stats_list( - cls, historical_test_data: List[HistoricalTestInformation]) -> "HistoricTaskData": + def from_stats_list(cls, historic_stats: List[TestStats]) -> "HistoricTaskData": """ Build historic task data from a list of historic stats. - :param historical_test_data: A list of information about the runtime of a test. + :param historic_stats: List of historic stats to build from. :return: Historic task data from the list of stats. """ + hooks = defaultdict(list) - for hook in [stat for stat in historical_test_data if is_resmoke_hook(stat.test_name)]: + for hook in [stat for stat in historic_stats if is_resmoke_hook(stat.test_file)]: historical_hook = HistoricHookInfo.from_test_stats(hook) hooks[historical_hook.test_name()].append(historical_hook) return cls([ HistoricTestInfo.from_test_stats(stat, - hooks[get_short_name_from_test_file(stat.test_name)]) - for stat in historical_test_data if not is_resmoke_hook(stat.test_name) + hooks[get_short_name_from_test_file(stat.test_file)]) + for stat in historic_stats if not is_resmoke_hook(stat.test_file) ]) def get_tests_runtimes(self) -> List[TestRuntime]: |
