* HH-446: restore auditable quality gates * test(HH-446): restore help center smoke contract --------- Co-authored-by: Rogee <rogee@ipao.vip>
174 lines
6.4 KiB
Python
Executable File
174 lines
6.4 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Validate Go test coverage, execution evidence, and elapsed time."""
|
|
|
|
import argparse
|
|
import json
|
|
import sys
|
|
from collections import defaultdict
|
|
from pathlib import Path
|
|
|
|
|
|
def coverage(path):
|
|
files = defaultdict(lambda: [0, 0])
|
|
total = [0, 0]
|
|
for line in Path(path).read_text(encoding="utf-8").splitlines():
|
|
if not line or line.startswith("mode:"):
|
|
continue
|
|
fields = line.split()
|
|
if len(fields) != 3:
|
|
raise ValueError(f"invalid coverage line: {line}")
|
|
file_name = fields[0].split(":", 1)[0]
|
|
statements, count = int(fields[1]), int(fields[2])
|
|
total[0] += statements
|
|
total[1] += statements if count else 0
|
|
files[file_name][0] += statements
|
|
files[file_name][1] += statements if count else 0
|
|
if total[0] == 0:
|
|
raise ValueError("coverage profile has no statements")
|
|
return total, files
|
|
|
|
|
|
def test_evidence(path):
|
|
packages = defaultdict(lambda: {"pass": 0, "fail": 0, "skip": 0})
|
|
totals = {"pass": 0, "fail": 0, "skip": 0}
|
|
for line in Path(path).read_text(encoding="utf-8").splitlines():
|
|
try:
|
|
event = json.loads(line)
|
|
except json.JSONDecodeError:
|
|
continue
|
|
action = event.get("Action")
|
|
package = event.get("Package", "")
|
|
if not event.get("Test") or action not in totals:
|
|
continue
|
|
packages[package][action] += 1
|
|
totals[action] += 1
|
|
return totals, packages
|
|
|
|
|
|
def package_matches(name, spec):
|
|
recursive = spec.endswith("/...")
|
|
package = spec.removesuffix("/...")
|
|
return name == package or recursive and name.startswith(package + "/")
|
|
|
|
|
|
def run(argv=None):
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--coverage", required=True)
|
|
parser.add_argument("--test-json", required=True)
|
|
parser.add_argument("--duration", required=True)
|
|
parser.add_argument("--report", required=True)
|
|
parser.add_argument("--min-coverage", type=float, default=65.0)
|
|
parser.add_argument("--max-duration", type=float, required=True)
|
|
parser.add_argument("--test-exit-code", type=int, default=0)
|
|
parser.add_argument("--critical-package", action="append", default=[])
|
|
args = parser.parse_args(argv)
|
|
|
|
failures = []
|
|
try:
|
|
total, files = coverage(args.coverage)
|
|
total_tests, packages = test_evidence(args.test_json)
|
|
elapsed = float(Path(args.duration).read_text(encoding="utf-8").strip())
|
|
except (OSError, ValueError) as error:
|
|
failures.append(str(error))
|
|
total, files = [0, 0], {}
|
|
total_tests, packages, elapsed = {"pass": 0, "fail": 0, "skip": 0}, {}, None
|
|
|
|
percent = total[1] / total[0] * 100 if total[0] else 0.0
|
|
if percent < args.min_coverage:
|
|
failures.append(f"overall coverage {percent:.2f}% is below {args.min_coverage:.2f}%")
|
|
if args.test_exit_code:
|
|
failures.append(f"go test exited with {args.test_exit_code}")
|
|
if total_tests["fail"]:
|
|
failures.append(f"test evidence contains {total_tests['fail']} failed test events")
|
|
if elapsed is not None and elapsed > args.max_duration:
|
|
failures.append(f"test duration {elapsed:.2f}s exceeds {args.max_duration:.2f}s")
|
|
if sum(total_tests.values()) == 0:
|
|
failures.append("test evidence contains no test results")
|
|
|
|
critical, critical_coverage = [], []
|
|
for spec in args.critical_package:
|
|
matched = {
|
|
name: values for name, values in packages.items() if package_matches(name, spec)
|
|
}
|
|
item = {
|
|
"package": spec,
|
|
"matched": sorted(matched),
|
|
"passed": sum(values["pass"] for values in matched.values()),
|
|
"failed": sum(values["fail"] for values in matched.values()),
|
|
"skipped": sum(values["skip"] for values in matched.values()),
|
|
}
|
|
critical.append(item)
|
|
if not matched:
|
|
failures.append(f"critical suite {spec} produced no package evidence")
|
|
elif item["passed"] == 0:
|
|
failures.append(f"critical suite {spec} was entirely skipped")
|
|
|
|
matching = [
|
|
values
|
|
for name, values in files.items()
|
|
if package_matches(name.rsplit("/", 1)[0], spec)
|
|
]
|
|
statements = sum(values[0] for values in matching)
|
|
covered = sum(values[1] for values in matching)
|
|
coverage_item = {
|
|
"package": spec,
|
|
"covered_statements": covered,
|
|
"total_statements": statements,
|
|
"percent": round(covered / statements * 100, 2) if statements else 0.0,
|
|
}
|
|
critical_coverage.append(coverage_item)
|
|
if not statements:
|
|
failures.append(f"critical coverage {spec} has no statements")
|
|
elif coverage_item["percent"] < args.min_coverage:
|
|
failures.append(
|
|
f"critical coverage {spec} {coverage_item['percent']:.2f}% "
|
|
f"is below {args.min_coverage:.2f}%"
|
|
)
|
|
|
|
report = {
|
|
"schema_version": 1,
|
|
"status": "failed" if failures else "passed",
|
|
"thresholds": {
|
|
"min_coverage_percent": args.min_coverage,
|
|
"max_duration_seconds": args.max_duration,
|
|
},
|
|
"coverage": {
|
|
"covered_statements": total[1],
|
|
"total_statements": total[0],
|
|
"percent": round(percent, 2),
|
|
"critical": critical_coverage,
|
|
"files": {
|
|
name: {
|
|
"covered_statements": values[1],
|
|
"total_statements": values[0],
|
|
"percent": round(values[1] / values[0] * 100, 2) if values[0] else 0.0,
|
|
}
|
|
for name, values in sorted(files.items())
|
|
},
|
|
},
|
|
"tests": {**total_tests, "critical": critical},
|
|
"duration_seconds": elapsed,
|
|
"test_exit_code": args.test_exit_code,
|
|
"failures": failures,
|
|
}
|
|
report_path = Path(args.report)
|
|
report_path.parent.mkdir(parents=True, exist_ok=True)
|
|
report_path.write_text(json.dumps(report, indent=2, sort_keys=True) + "\n", encoding="utf-8")
|
|
print(
|
|
json.dumps(
|
|
{
|
|
"status": report["status"],
|
|
"coverage_percent": report["coverage"]["percent"],
|
|
"tests": report["tests"],
|
|
"duration_seconds": elapsed,
|
|
"failures": failures,
|
|
},
|
|
sort_keys=True,
|
|
)
|
|
)
|
|
return 1 if failures else 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(run())
|