"""Tests for register_from_classification CLI (STATE-WP-0065 P3).""" from __future__ import annotations import json import subprocess import sys from pathlib import Path import pytest from api.classification import ClassificationData REPO_ROOT = Path(__file__).resolve().parent.parent SCRIPT = REPO_ROOT / "scripts" / "register_from_classification.py" def test_cli_help(): result = subprocess.run( [sys.executable, str(SCRIPT), "--help"], capture_output=True, text=True, cwd=REPO_ROOT, ) assert result.returncode == 0 assert "--repo-path" in result.stdout assert "--bulk" in result.stdout assert "--dry-run" in result.stdout @pytest.mark.asyncio async def test_dry_run_repo_path_state_hub(): sys.path.insert(0, str(REPO_ROOT)) from scripts.register_from_classification import run_registration import argparse args = argparse.Namespace( repo_path=str(REPO_ROOT), slug=None, bulk=False, dry_run=True, api=False, db=False, api_base="http://127.0.0.1:8000", json=False, ) report = await run_registration(args) counts = report.counts() assert counts["invalid"] == 0 assert counts["registered"] + counts["updated"] + counts["skipped"] >= 1 assert any(r.slug == "state-hub" for r in report.results) # Valid classification file is always parsed even when DB domains are absent. assert not any("repo_classification block" in r.detail for r in report.results) def test_json_report_shape(): result = subprocess.run( [ sys.executable, str(SCRIPT), "--repo-path", str(REPO_ROOT), "--dry-run", "--json", ], capture_output=True, text=True, cwd=REPO_ROOT, ) payload = json.loads(result.stdout) assert payload["summary"]["invalid"] == 0 assert "summary" in payload assert "results" in payload assert set(payload["summary"]) == {"registered", "updated", "skipped", "invalid"} def test_git_fingerprint_uses_one_root(monkeypatch, tmp_path): from scripts import register_from_classification as registration first = "a" * 40 second = "b" * 40 monkeypatch.setattr( registration, "_git_value", lambda _path, _args: f"{first}\n{second}", ) assert registration._git_fingerprint(tmp_path) == first @pytest.mark.asyncio async def test_api_update_separates_classification_from_identity(monkeypatch, tmp_path): from scripts import register_from_classification as registration calls = [] def fake_api_request(method, path, *, api_base, body=None): calls.append((method, path, body)) if method == "GET": return 200, {"slug": "example"} return 200, {"slug": "example"} monkeypatch.setattr(registration, "_api_request", fake_api_request) monkeypatch.setattr(registration, "_git_root", lambda path: path) monkeypatch.setattr(registration, "_git_value", lambda _path, _args: "origin") monkeypatch.setattr(registration, "_git_fingerprint", lambda _path: "a" * 40) report = registration.RegistrationReport() data = ClassificationData( category="infrastructure", domain="infotech", capability_tags=["infrastructure.state"], ) await registration._upsert_via_api( slug="example", repo_path=tmp_path, data=data, dry_run=False, api_base="http://state-hub.test", report=report, ) patch = next(call for call in calls if call[:2] == ("PATCH", "/repos/example")) assert patch[2]["domain_slug"] == "infotech" assert "local_path" not in patch[2] assert "remote_url" not in patch[2] assert "git_fingerprint" not in patch[2] assert ("POST", "/repos/example/paths") in [call[:2] for call in calls]