mirror of
https://github.com/rustfs/rustfs.git
synced 2026-10-04 20:43:04 +00:00
a88225d208
* fix(ci): reduce duplicate work and preserve reliable test failures * fix(ci): retain protocol evidence and repair stale test fixtures * test(connect): honor parent deadline during API fixture readiness * fix(ci): reserve IO capacity for state writer proofs * test(connect): align RPC fixtures with service capture contracts * test(connect): cover pinned service capture failures
91 lines
3.9 KiB
Python
91 lines
3.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Verify migration proofs already passed in the workspace nextest run."""
|
|
|
|
import json
|
|
from pathlib import Path
|
|
import sys
|
|
import xml.etree.ElementTree as ET
|
|
|
|
|
|
SUITE = "rustfs-ecstore"
|
|
NAME_PARTS = ("data_movement", "rebalance", "decommission", "source_cleanup", "delete_marker")
|
|
|
|
|
|
def unique_object(pairs):
|
|
result = {}
|
|
for key, value in pairs:
|
|
if key in result:
|
|
raise ValueError(f"duplicate JSON key: {key}")
|
|
result[key] = value
|
|
return result
|
|
|
|
|
|
def library_suite(path):
|
|
listing = json.loads(Path(path).read_text(), object_pairs_hook=unique_object)
|
|
suite = listing["rust-suites"][SUITE]
|
|
if any(suite.get(key) != value for key, value in {
|
|
"package-name": SUITE, "binary-id": SUITE, "kind": "lib", "status": "listed",
|
|
}.items()) or not isinstance(suite.get("testcases"), dict):
|
|
raise ValueError(f"{path}: expected the listed {SUITE} library test binary")
|
|
return suite["testcases"]
|
|
|
|
|
|
def verify(core_path, junit_path, floor_path):
|
|
floor_lines = [line.strip() for line in Path(floor_path).read_text().splitlines()
|
|
if line.strip() and not line.lstrip().startswith("#")]
|
|
if len(floor_lines) != 1 or not floor_lines[0].isdigit() or int(floor_lines[0]) <= 0:
|
|
raise ValueError("migration floor must contain one positive integer")
|
|
floor = int(floor_lines[0])
|
|
expected = set()
|
|
for name, case in library_suite(core_path).items():
|
|
if not any(part in name for part in NAME_PARTS) or case.get("ignored") is True:
|
|
continue
|
|
if (case.get("kind") != "test" or case.get("ignored") is not False
|
|
or case.get("filter-match", {}).get("status") != "matches"):
|
|
raise ValueError(f"{name}: migration test is malformed or filtered from the core run")
|
|
expected.add(name)
|
|
if len(expected) < floor:
|
|
raise ValueError(f"migration selection has {len(expected)} tests, below the committed floor {floor}")
|
|
|
|
report = ET.parse(junit_path).getroot()
|
|
if (report.tag != "testsuites" or int(report.get("tests", "0")) < len(expected)
|
|
or report.get("failures") != "0" or report.get("errors") != "0"):
|
|
raise ValueError("core JUnit must report a successful nonempty nextest run")
|
|
suites = [suite for suite in report.findall("testsuite") if suite.get("name") == SUITE]
|
|
if len(suites) != 1:
|
|
raise ValueError("core JUnit must contain exactly one migration library suite")
|
|
suite_cases = set(suites[0].findall("testcase"))
|
|
executions = {}
|
|
for case in report.iter("testcase"):
|
|
if case.get("classname") == SUITE:
|
|
executions.setdefault(case.get("name"), []).append(case)
|
|
for name in sorted(expected):
|
|
cases = executions.get(name, [])
|
|
if len(cases) != 1 or cases[0] not in suite_cases:
|
|
raise ValueError(f"{name}: expected exactly one core JUnit execution in the migration library suite")
|
|
case = cases[0]
|
|
if (case.get("status", "passed") != "passed"
|
|
or any(child.tag not in ("system-out", "system-err", "properties") for child in case)):
|
|
raise ValueError(f"{name}: migration proof failed, skipped, or required a retry")
|
|
return len(expected), floor
|
|
|
|
|
|
def main():
|
|
if sys.argv[1:] == ["--filter"]:
|
|
print(" or ".join(f"test({part})" for part in NAME_PARTS))
|
|
return 0
|
|
if len(sys.argv) != 4:
|
|
print("usage: check_migration_gate_evidence.py CORE_LISTING JUNIT FLOOR | --filter", file=sys.stderr)
|
|
return 2
|
|
try:
|
|
count, floor = verify(*sys.argv[1:])
|
|
except (OSError, ValueError, TypeError, KeyError, AttributeError, ET.ParseError) as error:
|
|
print(f"migration gate evidence failed: {error}", file=sys.stderr)
|
|
return 1
|
|
print(f"migration gate evidence OK: {count} proofs passed without retries (floor: {floor})")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|