mirror of
https://github.com/rustfs/rustfs.git
synced 2026-09-19 09:05:56 +00:00
eb96b402b1
* feat(ci): measure queue and execution time by run attempt * fix(ci): bound timing samples and recognize the old workspace lane * fix(ci): sample completed runs for stable timing comparisons
75 lines
4.2 KiB
Python
75 lines
4.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Timing reports must preserve missing evidence and non-successful runs."""
|
|
import copy
|
|
from datetime import datetime, timezone
|
|
import unittest
|
|
from unittest import mock
|
|
|
|
from ci_timing_report import collect, summarize
|
|
|
|
|
|
class TimingTests(unittest.TestCase):
|
|
def setUp(self):
|
|
self.job = {"id": 2, "name": "Workspace Test and Lint", "status": "completed", "conclusion": "success",
|
|
"created_at": "2026-09-01T00:10:00Z", "started_at": "2026-09-01T00:15:00Z", "completed_at": "2026-09-01T00:25:00Z",
|
|
"steps": [{"name": "Run nextest tests", "status": "completed", "conclusion": "success", "started_at": "2026-09-01T00:16:00Z", "completed_at": "2026-09-01T00:24:00Z"}]}
|
|
self.run = {"id": 1, "run_attempt": 2, "head_sha": "a" * 40, "status": "completed", "conclusion": "success",
|
|
"created_at": "2026-09-01T00:00:00Z", "run_started_at": "2026-09-01T00:00:00Z", "jobs": [self.job]}
|
|
|
|
def test_parallel_minutes_are_not_wall_time(self):
|
|
self.run["jobs"].append({**self.job, "id": 3, "name": "Other"})
|
|
result = summarize([self.run])
|
|
self.assertEqual(result["successful_code_wall"]["median_minutes"], 25)
|
|
self.assertEqual(result["successful_code_job_sum"]["median_minutes"], 20)
|
|
self.assertEqual(result["jobs"][self.job["name"]]["queue"]["median_minutes"], 5)
|
|
self.assertEqual(result["jobs"][self.job["name"]]["steps"]["Run nextest tests"]["median_minutes"], 8)
|
|
|
|
def test_cancelled_incomplete_and_docs_runs_are_not_success_samples(self):
|
|
cancelled = {**self.run, "status": "completed", "conclusion": "cancelled"}
|
|
pending = {**self.run, "status": "queued", "conclusion": None, "jobs": []}
|
|
docs = {**self.run, "jobs": [{**self.job, "name": "Quick Checks"}]}
|
|
result = summarize([self.run, cancelled, pending, docs])
|
|
self.assertEqual(result["successful_code_runs"], 1)
|
|
self.assertEqual(result["cancelled_fraction"], 0.25)
|
|
self.assertEqual(result["completed_fraction"], 0.75)
|
|
|
|
def test_rerun_wall_time_excludes_time_before_the_attempt(self):
|
|
self.run["created_at"] = "2026-08-01T00:00:00Z"
|
|
self.assertEqual(summarize([self.run])["successful_code_wall"]["median_minutes"], 25)
|
|
del self.run["run_started_at"]
|
|
self.assertIsNone(summarize([self.run])["successful_code_wall"]["median_minutes"])
|
|
|
|
def test_old_workspace_job_name_requires_an_executed_test_step(self):
|
|
self.job["name"] = "Test and Lint"
|
|
self.assertEqual(summarize([self.run])["successful_code_runs"], 1)
|
|
self.job["steps"] = []
|
|
self.assertEqual(summarize([self.run])["successful_code_runs"], 0)
|
|
|
|
def test_collection_rejects_out_of_range_api_results(self):
|
|
with mock.patch("ci_timing_report.api", return_value={"workflow_runs": [self.run]}):
|
|
with self.assertRaisesRegex(ValueError, "outside the requested date range"):
|
|
collect("owner/repo", 1, datetime(2026, 9, 2, tzinfo=timezone.utc))
|
|
|
|
def test_missing_times_are_unknown_not_zero(self):
|
|
self.job["created_at"] = None
|
|
self.job["completed_at"] = None
|
|
result = summarize([self.run])
|
|
self.assertIsNone(result["successful_code_wall"]["median_minutes"])
|
|
self.assertIsNone(result["successful_code_job_sum"]["median_minutes"])
|
|
self.assertEqual(result["jobs"][self.job["name"]]["queue"]["missing"], 1)
|
|
|
|
def test_collection_binds_the_attempt_and_rejects_reruns(self):
|
|
source = copy.deepcopy(self.run)
|
|
del source["jobs"]
|
|
with mock.patch("ci_timing_report.api", side_effect=[{"workflow_runs": [source]}, {"jobs": [self.job]}, source]) as api:
|
|
snapshot = collect("owner/repo", 1, datetime(2026, 8, 1, tzinfo=timezone.utc))
|
|
self.assertIn("/attempts/2/jobs?", api.call_args_list[1].args[0])
|
|
self.assertEqual(snapshot["runs"][0]["run_attempt"], 2)
|
|
with mock.patch("ci_timing_report.api", side_effect=[{"workflow_runs": [source]}, {"jobs": [self.job]}, {**source, "run_attempt": 3}]):
|
|
with self.assertRaisesRegex(ValueError, "changed during collection"):
|
|
collect("owner/repo", 1, datetime(2026, 8, 1, tzinfo=timezone.utc))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|