92 lines
3.7 KiB
Python
92 lines
3.7 KiB
Python
"""Regression coverage for explicit legacy PR root migration."""
|
|
from __future__ import annotations
|
|
|
|
from contextlib import nullcontext
|
|
import json
|
|
from pathlib import Path
|
|
import sys
|
|
|
|
import yaml
|
|
|
|
from testing.tests.test_hermes_cli_support import HERMES, _load
|
|
|
|
|
|
ROOT = Path(__file__).parents[2]
|
|
sys.path.insert(0, str(HERMES / "scm-common/scripts"))
|
|
state = _load("supervisor_state")
|
|
seed = _load("seed_legacy_scm_roots")
|
|
|
|
|
|
class NativeKanban:
|
|
"""Minimal native task lookup surface used by the operator seed."""
|
|
|
|
def __init__(self, task_ids: set[str]) -> None:
|
|
self.task_ids = task_ids
|
|
|
|
def scoped_current_board(self, _board: str):
|
|
return nullcontext()
|
|
|
|
def connect(self, *, board: str):
|
|
return type("Connection", (), {"close": lambda self: None})()
|
|
|
|
def get_task(self, _connection, task_id: str):
|
|
return {"id": task_id} if task_id in self.task_ids else None
|
|
|
|
|
|
def _pull(root, head: str | None = None) -> bytes:
|
|
"""Build only the canonical open PR shape the seed accepts."""
|
|
return json.dumps({
|
|
"state": "open",
|
|
"head": {"ref": root.ref, "sha": head or root.head,
|
|
"repo": {"full_name": f"titan/{root.project}"}},
|
|
"base": {"ref": root.base, "repo": {"full_name": f"titan/{root.project}"}},
|
|
}).encode()
|
|
|
|
|
|
def test_seed_registry_exactly_matches_flux_broker_adoptions():
|
|
"""The board integrity table and broker ledger share one reviewed scope."""
|
|
document = yaml.safe_load(
|
|
(ROOT / "services/hermes-scm-broker/task-branch-adoptions-configmap.yaml").read_text()
|
|
)
|
|
deployed = json.loads(document["data"]["task-branch-adoptions.json"])
|
|
expected = {f"{root.project}/{root.ref}": root.adoption() for root in seed.ROOTS}
|
|
assert deployed == expected
|
|
assert "t_cf89a2ec" in {root.root_task_id for root in seed.ROOTS}
|
|
assert deployed["atlas-iac/feature/hermes-next-hux"]["latest_head"] == (
|
|
"98c7c6184f6edfe3cdac228529c2287584db3006"
|
|
)
|
|
|
|
|
|
def test_seed_requires_native_root_and_matching_live_canonical_pr(tmp_path, monkeypatch):
|
|
"""A stale PR or fabricated root leaves the board-local integrity DB untouched."""
|
|
root = seed.ROOTS[1]
|
|
monkeypatch.setattr(state, "KANBAN_ROOT", tmp_path / "boards")
|
|
missing = NativeKanban(set())
|
|
assert seed.seed_root(missing, root, lambda _path: (_ for _ in ()).throw(AssertionError)) == "missing-task"
|
|
|
|
native = NativeKanban({root.root_task_id})
|
|
assert seed.seed_root(native, root, lambda _path: _pull(root, "a" * 40)) == "live-pr-mismatch"
|
|
assert state.get_root(root.board, root.root_task_id) is None
|
|
|
|
assert seed.seed_root(native, root, lambda _path: _pull(root)) == "seeded"
|
|
assert state.get_root(root.board, root.root_task_id) == root.lineage
|
|
assert state.get_live_head(root.board, root.root_task_id) == root.head
|
|
|
|
|
|
def test_seed_rerun_preserves_same_owned_newer_state_and_approval(tmp_path, monkeypatch):
|
|
"""A static migration record never rewinds a later verified continuation head."""
|
|
root = seed.ROOTS[1]
|
|
monkeypatch.setattr(state, "KANBAN_ROOT", tmp_path / "boards")
|
|
native = NativeKanban({root.root_task_id})
|
|
assert seed.seed_root(native, root, lambda _path: _pull(root)) == "seeded"
|
|
newer = "b" * 40
|
|
state.record_submission(root.board, root.root_task_id, root.lineage, newer)
|
|
state.set_ready(root.board, root.root_task_id, newer)
|
|
|
|
assert seed.seed_root(native, root, lambda _path: (_ for _ in ()).throw(AssertionError)) == "already-seeded"
|
|
assert state.get_live_head(root.board, root.root_task_id) == newer
|
|
with state._connect(root.board) as connection:
|
|
assert connection.execute(
|
|
"SELECT ready_for_human_merge,ready_commit FROM supervisor_roots"
|
|
).fetchone() == (1, newer)
|