state-hub/tests/test_release_headroom_preflight.py
tegwick a6afb08d82
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Build and Publish Multi-Context Image / build-and-push (push) Successful in 28s
STATE-WP-0099: wave-1 node allocation — API 390m, state-hub-db 70m/416Mi, preflight surge derived from values
Receives the State Hub rows of the 2026-10-21 node allocation review
(CUST-WP-0071 T03/T04, RESOURCE-WP-0008). The release preflight now derives
the API surge from the values the release deploys instead of the stale 100m
STATE-WP-0091 constant, and reports the steady remainder after rollout.
Ordering: apply after rail-knative reductions, before forge/telemetry increases.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 8340@bnt-lap001
Assistant-Session: 2e192b3d-b3e8-4403-94d4-d55a2c8b476c
2026-10-21 08:44:32 +02:00

140 lines
5.1 KiB
Python

from __future__ import annotations
import json
from pathlib import Path
from scripts.release_headroom_preflight import (
DEFAULT_API_SURGE_CPU_M,
DEFAULT_API_SURGE_MEMORY,
DEFAULT_MCP_SURGE_CPU_M,
DEFAULT_MIGRATE_CPU_M,
DEFAULT_VALUES_FILES,
evaluate,
load_values,
main,
pod_effective_requests,
release_from_values,
)
FIXTURES = Path(__file__).parent / "fixtures" / "release_headroom"
HISTORICAL_100M = {"api_surge_cpu_m": 100}
def _load(name: str) -> dict:
return json.loads((FIXTURES / name).read_text())
def test_revision_61_65m_refuses_api_surge() -> None:
report = evaluate(_load("rev61-65m.json"))
assert report["ok"] is False
assert report["remaining_cpu_m"] == 65
assert any("65m remaining" in r or "needs 100m" in r for r in report["reasons"])
assert "not a kube-scheduler guarantee" in " ".join(report["notes"]).lower() or any(
"guarantee" in n.lower() for n in report["notes"]
)
def test_revision_63_105m_is_narrowly_sufficient() -> None:
report = evaluate(_load("rev63-105m.json"), HISTORICAL_100M)
assert report["ok"] is True
assert report["remaining_cpu_m"] == 105
assert report["reasons"] == []
assert any("105m" in n or "Not factory" in n for n in report["notes"])
def test_unrelated_pending_demand_refuses_105m() -> None:
report = evaluate(_load("rev63-105m-concurrent-pending.json"), HISTORICAL_100M)
assert report["ok"] is False
assert any("unrelated pending" in r for r in report["reasons"])
def test_stale_observation_refuses() -> None:
observation = _load("rev63-105m.json")
observation["freshness_seconds"] = 3600
report = evaluate(observation, HISTORICAL_100M)
assert report["ok"] is False
assert any("old" in r for r in report["reasons"])
def test_non_atomic_refuses() -> None:
report = evaluate(_load("rev63-105m.json"), {**HISTORICAL_100M, "atomic": False})
assert report["ok"] is False
assert any("atomic" in r for r in report["reasons"])
def test_init_overhead_uses_max_not_sum() -> None:
pod = {
"spec": {
"initContainers": [{"resources": {"requests": {"cpu": "80m", "memory": "64Mi"}}}],
"containers": [{"resources": {"requests": {"cpu": "100m", "memory": "512Mi"}}}],
}
}
cpu, _mem = pod_effective_requests(pod)
assert cpu == 100
def test_cli_fixture_exit_codes() -> None:
historical = str(FIXTURES / "historical-100m-release.json")
assert main(["--fixture", str(FIXTURES / "rev63-105m.json"), "--release", historical]) == 0
assert main(["--fixture", str(FIXTURES / "rev61-65m.json"), "--release", historical]) == 1
# Default surge now derives from the shipped values (390m): 105m refuses.
assert main(["--fixture", str(FIXTURES / "rev63-105m.json")]) == 1
# STATE-WP-0099: the surge follows the API request the release deploys.
def test_shipped_values_drive_surge_and_match_fallbacks() -> None:
release = release_from_values(load_values(DEFAULT_VALUES_FILES))
assert release["api_surge_cpu_m"] == 390
assert release["api_surge_cpu_m"] == DEFAULT_API_SURGE_CPU_M
assert release["api_surge_memory_bytes"] == DEFAULT_API_SURGE_MEMORY
assert release["mcp_surge_cpu_m"] == DEFAULT_MCP_SURGE_CPU_M
assert release["migrate_cpu_m"] == DEFAULT_MIGRATE_CPU_M
def test_values_override_order_and_disabled_sections() -> None:
chart = {"resources": {"requests": {"cpu": "250m", "memory": "512Mi"}},
"mcp": {"enabled": False, "resources": {"requests": {"cpu": "50m"}}},
"migrations": {"enabled": True, "resources": {"requests": {"cpu": "50m"}}}}
override = {"resources": {"requests": {"cpu": "0.39"}}, "migrations": {"enabled": False}}
from scripts.release_headroom_preflight import _deep_merge
release = release_from_values(_deep_merge(chart, override))
assert release["api_surge_cpu_m"] == 390
assert release["api_surge_memory_bytes"] == 512 * 1024**2
assert release["mcp_surge_cpu_m"] == 0
assert release["migrate_cpu_m"] == 0
def test_today_395m_fits_390m_surge_narrowly() -> None:
report = evaluate(_load("2026-10-21-395m-live250.json"))
assert report["ok"] is True
assert report["api_surge_cpu_m"] == 390
assert report["remaining_after_rollout_cpu_m"] == 255
notes = " ".join(report["notes"])
assert "250m -> 390m" in notes
assert "only 5m above" in notes
assert "next release will be refused" in notes
def test_after_knative_reduction_fits_with_margin() -> None:
report = evaluate(_load("2026-10-21-555m-after-knative.json"))
assert report["ok"] is True
assert report["remaining_after_rollout_cpu_m"] == 415
assert "next release will be refused" not in " ".join(report["notes"])
def test_forge_increase_before_state_hub_refuses() -> None:
report = evaluate(_load("2026-10-21-320m-forge-first.json"))
assert report["ok"] is False
assert any("needs 390m" in r for r in report["reasons"])
def test_after_full_wave1_routine_release_refuses() -> None:
report = evaluate(_load("2026-10-21-110m-after-wave1.json"))
assert report["ok"] is False
assert report["remaining_cpu_m"] == 110
assert any("needs 390m" in r for r in report["reasons"])