Files
inecs f8d3cbdd59 Initial commit: VMware vSphere API simulator scaffold.
Add the FastAPI app, PostgreSQL migrations, Docker/Helm packaging, API
contracts, docs, client examples, and the unit/integration/compatibility
test suite for local client and tooling labs without a real vCenter.
2026-07-18 04:42:11 +03:00

70 lines
2.9 KiB
Python

"""Version matrix and hot-swap gating."""
from httpx import ASGITransport, AsyncClient
from app.config import Settings
from app.main import create_app
from app.vsphere.contracts.matrix import (
VERSIONS,
available_for_request,
catalog_entries_for_major,
methods_for_major,
)
from tests.unit.test_health import FakeDatabase
def test_major_6_smaller_than_major_9() -> None:
assert len(methods_for_major(6)) < len(methods_for_major(9))
assert len(methods_for_major(7)) <= len(methods_for_major(8))
assert len(methods_for_major(8)) <= len(methods_for_major(9))
def test_runtime_serves_all_registered_regardless_of_major() -> None:
"""Catalog floors remain for browse; runtime never 501s known paths."""
assert available_for_request("POST", "/api/cis/tagging/category", 6) is True
assert available_for_request("GET", "/api/content/library", 6) is True
assert available_for_request("POST", "/api/appliance/networking/dns/hostname", 6) is True
def test_catalog_floor_still_shrinks_browse_list() -> None:
from app.vsphere.contracts.matrix import methods_for_major
assert ("POST", "/api/cis/tagging/category") not in methods_for_major(6)
assert ("POST", "/api/cis/tagging/category") in methods_for_major(7)
assert ("GET", "/api/content/library") not in methods_for_major(7)
assert ("GET", "/api/content/library") in methods_for_major(8)
def test_literal_path_beats_param_template() -> None:
"""`/api/content/library/item` must not resolve as `/{library_id}`."""
from app.vsphere.contracts.matrix import resolve_template
assert resolve_template("GET", "/api/content/library/item") == "/api/content/library/item"
assert available_for_request("GET", "/api/content/library/item", 8) is True
def test_catalog_entries_match_version() -> None:
for major in VERSIONS:
entries = catalog_entries_for_major(major)
assert all(e["status"] in {"implemented", "stub"} for e in entries)
assert len(entries) == len(methods_for_major(major))
async def test_hot_swap_does_not_501_registered_paths() -> None:
app = create_app(
settings=Settings(enable_pve_stub=False),
database_factory=lambda _settings: FakeDatabase(True),
worker_factories=(),
)
async with app.router.lifespan_context(app):
async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as client:
apply = await client.post("/ui/api/contract/apply", params={"major": 6})
assert apply.status_code == 200
assert apply.json()["runtime_version"] == "7.0.0"
# Session required for library — but must not be version-gated 501.
library = await client.get("/api/content/library")
assert library.status_code != 501
restore = await client.post("/ui/api/contract/apply", params={"major": 9})
assert restore.status_code == 200