left4me/l4d2host/tests/test_spec.py
mwiegand 985df970f8
feat(l4d2-web): per-overlay server.cfg aliases — expose checkbox + auto-exec
Each linked overlay gets a checkbox on the blueprint detail page that opts
its server.cfg in as exec server_overlay_<id>. The web app builds the
spec with {path, alias} per overlay and prepends exec server_overlay_<id>
lines to the blueprint config in lowest-overlay-first order. The host
stages those copies in the overlayfs upper layer before mounting (avoids
copy-up writes against a sandbox-uid file). A live preview block above the
Config textarea shows what gets auto-executed.

Schema:
- alembic 0007: BlueprintOverlay.expose_server_cfg BOOLEAN

Spec contract:
- l4d2host OverlayRef(path, alias?). load_spec accepts both bare-string
  and {path, alias} entries.

Side effects folded in (same file in l4d2_facade):
- start_server auto-initializes; the manual Initialize step is no longer
  needed before Start.
- initialize_server no longer runs blueprint builders — builds happen on
  overlay save, not on every server Start.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 01:26:31 +02:00

58 lines
1.6 KiB
Python

from pathlib import Path
import pytest
from l4d2host.spec import OverlayRef, load_spec
def test_minimal_spec_parses_string_shorthand(tmp_path: Path) -> None:
path = tmp_path / "server.yaml"
path.write_text("port: 27015\noverlays: [standard]\n")
spec = load_spec(path)
assert spec.port == 27015
assert spec.overlays == [OverlayRef(path="standard")]
def test_overlay_dict_with_alias(tmp_path: Path) -> None:
path = tmp_path / "server.yaml"
path.write_text(
"port: 27015\n"
"overlays:\n"
" - {path: '6', alias: overlay_6}\n"
" - path: '7'\n"
)
spec = load_spec(path)
assert spec.overlays == [
OverlayRef(path="6", alias="overlay_6"),
OverlayRef(path="7", alias=None),
]
def test_defaults_are_empty_lists(tmp_path: Path) -> None:
path = tmp_path / "server.yaml"
path.write_text("port: 27015\n")
spec = load_spec(path)
assert spec.overlays == []
assert spec.arguments == []
assert spec.config == []
def test_missing_port_fails(tmp_path: Path) -> None:
path = tmp_path / "server.yaml"
path.write_text("overlays: [standard]\n")
with pytest.raises((KeyError, ValueError, TypeError)):
load_spec(path)
def test_unknown_keys_ignored(tmp_path: Path) -> None:
path = tmp_path / "server.yaml"
path.write_text("port: 27015\nfoo: bar\n")
spec = load_spec(path)
assert spec.port == 27015
def test_overlay_dict_missing_path_rejected(tmp_path: Path) -> None:
path = tmp_path / "server.yaml"
path.write_text("port: 27015\noverlays:\n - {alias: overlay_6}\n")
with pytest.raises(ValueError):
load_spec(path)