summaryrefslogtreecommitdiff
path: root/buildscripts/util
diff options
context:
space:
mode:
authorLucas de Castro Borges <lucas@gnuabordo.com.br>2025-02-11 15:07:35 -0300
committerLucas de Castro Borges <lucas@gnuabordo.com.br>2025-02-11 15:07:35 -0300
commit4cb8841196d0625dfa3825aa326f071cd27c7b8b (patch)
tree1682a647d4463397c119183369ae6f750d5fdcff /buildscripts/util
parentaa03c6362cbaa767638e6eed9b031d86dd2643d1 (diff)
parent8f0827553e09872941945a093b647a4211a9db7f (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')
-rw-r--r--buildscripts/util/teststats.py89
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]: