Add a stateful Proxmox API console and broad handler coverage beyond the
initial QEMU slice, backed by imported contracts for majors 6–9. - Implement durable handlers for access/auth, cluster, LXC, storage, HA, firewall, Ceph, SDN, ACME, notifications, pools, mapping, and node ops - Serve an interactive Web UI with catalog browsing, demo seed controls, and OpenAPI/help surfaces - Bundle PVE 6.4-15, 7.4-16, and 8.4.5 contract revisions alongside 9.2.3 - Support in-memory runtime contract Apply (POST /ui/api/contract/apply) so /version and /api2 routes follow the selected major until restart - Expand seed profiles (including demo-cluster), migrations 007–008, TLS gateway config, Compose/Makefile tooling, and compatibility evidence - Tighten .gitignore for macOS, hidden directories (.*/), and local secrets
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
"""Contract catalog helpers."""
|
||||
|
||||
from datetime import UTC, datetime
|
||||
from pathlib import Path
|
||||
from typing import Any, cast
|
||||
|
||||
import pytest
|
||||
|
||||
from app.config import Settings
|
||||
from app.contracts.model import Method, Parameter, PathContract, Schema, Snapshot
|
||||
from app.web.contract_catalog import catalog_payload, list_majors, method_payload
|
||||
|
||||
|
||||
def _snapshot() -> Snapshot:
|
||||
method = Method(
|
||||
verb="POST",
|
||||
name="create",
|
||||
description="Create a VM.",
|
||||
parameters=(
|
||||
Parameter(name="node", definition=Schema(type="string")),
|
||||
Parameter(name="vmid", definition=Schema(type="integer", minimum=100)),
|
||||
Parameter(name="name", definition=Schema(type="string")),
|
||||
Parameter(name="memory", definition=Schema(type="integer", optional=True)),
|
||||
Parameter(name="scsi[n]", definition=Schema(type="string", optional=True)),
|
||||
),
|
||||
returns=Schema(type="string"),
|
||||
checksum="a" * 64,
|
||||
)
|
||||
return Snapshot(
|
||||
source_version="9.2.3",
|
||||
retrieved_at=datetime(2026, 1, 1, tzinfo=UTC),
|
||||
raw_sha256="b" * 64,
|
||||
paths=(PathContract(path="/nodes/{node}/qemu", methods=(method,)),),
|
||||
path_count=1,
|
||||
method_count=1,
|
||||
)
|
||||
|
||||
|
||||
def test_list_majors_includes_latest_releases() -> None:
|
||||
payload = list_majors(runtime_version="9.2.3")
|
||||
majors_list = cast(list[dict[str, Any]], payload["majors"])
|
||||
majors = {item["major"] for item in majors_list}
|
||||
assert majors == {6, 7, 8, 9}
|
||||
assert payload["runtime_version"] == "9.2.3"
|
||||
|
||||
|
||||
def test_list_majors_includes_artifact_urls() -> None:
|
||||
payload = list_majors(runtime_version="9.2.3")
|
||||
majors_list = cast(list[dict[str, Any]], payload["majors"])
|
||||
pve9 = next(item for item in majors_list if item["major"] == 9)
|
||||
assert pve9["artifact_url"] == "https://pve.proxmox.com/pve-docs/api-viewer/apidoc.js"
|
||||
assert pve9["bundled"] is True
|
||||
|
||||
|
||||
def test_list_majors_honors_settings_overrides() -> None:
|
||||
settings = Settings(catalog_artifact_url_9="https://example.test/pve9/apidoc.js")
|
||||
payload = list_majors(runtime_version=None, settings=settings)
|
||||
majors_list = cast(list[dict[str, Any]], payload["majors"])
|
||||
pve9 = next(item for item in majors_list if item["major"] == 9)
|
||||
assert pve9["artifact_url"] == "https://example.test/pve9/apidoc.js"
|
||||
|
||||
|
||||
def test_catalog_payload_groups_paths_by_tag() -> None:
|
||||
payload = catalog_payload(
|
||||
_snapshot(),
|
||||
9,
|
||||
implemented_methods=frozenset({("/nodes/{node}/qemu", "POST")}),
|
||||
)
|
||||
assert payload["source_version"] == "9.2.3"
|
||||
assert cast(str, payload["artifact_url"]).endswith("apidoc.js")
|
||||
assert payload["latest_version"] == "9.2.3"
|
||||
assert payload["path_count"] == 1
|
||||
categories = cast(list[dict[str, Any]], payload["categories"])
|
||||
method = categories[0]["paths"][0]["methods"][0]
|
||||
assert method["verb"] == "POST"
|
||||
assert method["implemented"] is True
|
||||
|
||||
|
||||
def test_method_payload_builds_examples() -> None:
|
||||
payload = method_payload(
|
||||
_snapshot(),
|
||||
major=9,
|
||||
path="/nodes/{node}/qemu",
|
||||
verb="POST",
|
||||
runtime_version="9.2.3",
|
||||
implemented_methods=frozenset({("/nodes/{node}/qemu", "POST")}),
|
||||
)
|
||||
assert payload["resolved_path"] == "/nodes/pve01/qemu"
|
||||
assert payload["body_example"] == {"vmid": 100, "name": "example"}
|
||||
assert payload["implemented"] is True
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_load_snapshot_uses_bundled_revision() -> None:
|
||||
from app.web import contract_catalog
|
||||
|
||||
contract_catalog._SNAPSHOT_CACHE.clear()
|
||||
root = Path("contracts")
|
||||
snapshot = await contract_catalog.load_snapshot(9, root)
|
||||
assert snapshot.source_version == "9.2.3"
|
||||
Reference in New Issue
Block a user