test: pin the sweep outcome per tool in a baseline, seed a GPG key, fail loudly when seeding finds no run

This commit is contained in:
Latte committed 2026-10-14 18:06:29 +02:00
1 parent 84b361962e
commit 9e51f72ec9
6 files changed
+761 -14

No files matched your search

+92 -1
View File
@@ -12,6 +12,9 @@ that is data or pure logic, so it can be checked without Docker
then deletes (leaf resources before their parents).
* :func:`classify` decides whether a result is acceptable: a 2xx, a status the swagger
documents for that operation, or an explicit entry of :data:`ALLOWANCES` with a reason.
* :func:`compare_baseline` pins the outcome class of every tool (``2xx`` or the exact
status of a documented non-2xx or an allowance) in ``sweep_baseline.json`` and reports
every downgrade at once; ``AEGIS_IT_WRITE_BASELINE=1`` regenerates the file.
* :func:`render_report` writes ``docs/integration-coverage.md``.
"""
@@ -27,12 +30,15 @@ from pathlib import Path
from typing import Any
from aegis_gitea_mcp.catalog import Catalog, Operation
from tests.integration.static_keys import GPG_PUBLIC_KEYS
from tests.integration.sweep_seed import PNG_1X1, Ctx, b64, ssh_public_key
REPO_ROOT = Path(__file__).resolve().parents[2]
SPEC_PATH = REPO_ROOT / "spec" / "gitea-swagger.v1.json"
REPORT_PATH = REPO_ROOT / "docs" / "integration-coverage.md"
REPORT_ENV = "AEGIS_IT_WRITE_REPORT"
BASELINE_PATH = Path(__file__).resolve().parent / "sweep_baseline.json"
BASELINE_ENV = "AEGIS_IT_WRITE_BASELINE"
RAW_TOOL = "gitea_api_request"
#: Tools the generic sweep never calls, with the test that covers them in isolation.
@@ -172,6 +178,7 @@ ID_RULES: list[tuple[str, str]] = [
(r"^/orgs/\{org\}/projects/\{id\}", "org_project"),
(r"^/user/hooks/\{id\}", "user_hook"),
(r"^/user/keys/\{id\}", "user_key"),
(r"^/user/gpg_keys/\{id\}", "gpg_key"),
(r"^/user/projects/\{id\}", "user_project"),
(r"^/user/applications/oauth2/\{id\}", "oauth_app"),
(r"^/admin/hooks/\{id\}", "admin_hook"),
@@ -605,7 +612,9 @@ OVERRIDES: dict[str, Override] = {
"gitea_user_current_post_key": lambda c: {
"body": {"title": fresh(c, "key"), "key": ssh_public_key()}
},
"gitea_user_current_post_gpg_key": lambda c: {"body": {"armored_public_key": "not a key"}},
"gitea_user_current_post_gpg_key": lambda c: {
"body": {"armored_public_key": GPG_PUBLIC_KEYS[1]}
},
"gitea_user_delete_access_token": lambda c: {
"username": c["admin"],
"token": c["throwaway_token"],
@@ -858,6 +867,88 @@ def write_report_if_enabled(catalog: Catalog, gitea_version: str) -> bool:
return True
# ---------------------------------------------------------------------------
# Baseline: the pinned outcome class per tool
# ---------------------------------------------------------------------------
SUCCESS = "2xx"
NO_STATUS = "no-status"
Outcome = str | int
def outcome_class(record: SweepRecord) -> Outcome:
"""``"2xx"`` for a success, else the HTTP status Gitea answered (or ``"no-status"``)."""
if record.status is not None and 200 <= record.status < 300 and not record.is_error:
return SUCCESS
return record.status if record.status is not None else NO_STATUS
def baseline_snapshot(records: Iterable[SweepRecord], gitea_version: str) -> dict[str, Any]:
"""The baseline document for ``records`` (what ``AEGIS_IT_WRITE_BASELINE=1`` writes)."""
return {
"gitea": gitea_version,
"comment": (
"Expected outcome class per tool in the sweep: 2xx, or the exact status of a "
"documented non-2xx or allowance. Regenerate with AEGIS_IT_WRITE_BASELINE=1."
),
"tools": {record.tool: outcome_class(record) for record in records},
}
def load_baseline(path: Path = BASELINE_PATH) -> dict[str, Outcome]:
"""Read the pinned outcome per tool."""
data = json.loads(path.read_text(encoding="utf-8"))
tools: dict[str, Outcome] = data["tools"]
return tools
def write_baseline(
records: Iterable[SweepRecord], gitea_version: str, path: Path = BASELINE_PATH
) -> None:
"""Write the baseline file (tools sorted by name, so diffs show only real changes)."""
document = baseline_snapshot(records, gitea_version)
document["tools"] = dict(sorted(document["tools"].items()))
path.write_text(json.dumps(document, indent=2) + "\n", encoding="utf-8")
@dataclass
class BaselineDiff:
"""Result of comparing a sweep with the pinned baseline."""
regressions: list[str] = field(default_factory=list)
upgrades: list[str] = field(default_factory=list)
def compare_baseline(records: Iterable[SweepRecord], baseline: dict[str, Outcome]) -> BaselineDiff:
"""Compare outcomes with the baseline.
A regression is a 2xx that is no longer a 2xx, a documented non-2xx that answers a
different status, a tool without a baseline entry or a baseline entry without a tool.
A non-2xx that became a 2xx is an upgrade: reported, but it does not fail the run.
"""
diff = BaselineDiff()
seen: set[str] = set()
for record in records:
seen.add(record.tool)
actual = outcome_class(record)
if record.tool not in baseline:
diff.regressions.append(f"{record.tool}: no baseline entry (got {actual})")
continue
expected = baseline[record.tool]
if actual == expected:
continue
if actual == SUCCESS:
diff.upgrades.append(f"{record.tool}: baseline {expected}, now 2xx")
continue
detail = f"{record.tool}: baseline {expected}, got {actual} ({record.method} {record.path}"
if record.message:
detail += f" :: {record.message}"
diff.regressions.append(detail + ")")
for tool in sorted(set(baseline) - seen):
diff.regressions.append(f"{tool}: in the baseline but not called by the sweep")
return diff
def failing(records: Iterable[SweepRecord]) -> list[SweepRecord]:
"""The records whose outcome is ``unexpected``."""
return [record for record in records if record.outcome == "unexpected"]