"""HTTP contract: golden request fixtures go in, schema-valid responses come out.""" from __future__ import annotations import json from decimal import Decimal from pathlib import Path from fastapi.testclient import TestClient from vpp_contracts.bid_optimization_result import BidOptimizationResult from vpp_contracts.forecast_bundle import ForecastBundle from vpp_contracts.skill_report import SkillReport from vpp_skills.app import app from .conftest import forecast_request FIXTURES = Path(__file__).resolve().parents[2] / "contracts" / "fixtures" client = TestClient(app) def test_registry_lists_versions(): r = client.get("/v1/skills") assert r.status_code == 200 ids = {s["id"]: s for s in r.json()} assert ids["bid-optimization-milp"]["endpoint"] == "/v1/optimize/bid" assert ids["load-forecast"]["version"] == "1.0.0" def test_price_forecast_from_golden_fixture(): req = json.loads((FIXTURES / "forecast_request" / "price-da.json").read_text()) r = client.post("/v1/forecast/price", json=req) assert r.status_code == 200, r.text ForecastBundle.model_validate(r.json()) def test_kind_endpoint_mismatch_is_422(dataset): r = client.post("/v1/forecast/pv", json=forecast_request(dataset, "LOAD", 30)) assert r.status_code == 422 def test_bid_optimization_from_golden_fixture(): req = json.loads((FIXTURES / "bid_optimization_request" / "da-basic.json").read_text()) r = client.post("/v1/optimize/bid", json=req) assert r.status_code == 200, r.text out = BidOptimizationResult.model_validate(r.json()) assert out.solver.status.value == "OPTIMAL" assert Decimal("1140") <= Decimal(out.daily_energy_mwh) <= Decimal("1260") def test_report_from_golden_fixture(): req = json.loads((FIXTURES / "report_request" / "da-bid-summary.json").read_text()) r = client.post("/v1/report", json=req) assert r.status_code == 200, r.text SkillReport.model_validate(r.json()) def test_schema_violation_is_422(): r = client.post("/v1/optimize/bid", json={"market_date": "2026-03-15"}) assert r.status_code == 422