82 lines
2.7 KiB
Python
82 lines
2.7 KiB
Python
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
from stat import S_IMODE
|
|
|
|
import pytest
|
|
|
|
from game_data_capture.config import ConfigError, ServerConfig, parse_config
|
|
from game_data_capture.paths import (
|
|
PathConfigurationError,
|
|
prepare_private_directories,
|
|
prepare_private_file,
|
|
resolve_runtime_paths,
|
|
)
|
|
|
|
|
|
def test_config_uses_typed_defaults() -> None:
|
|
config = parse_config({})
|
|
|
|
assert config.server == ServerConfig(host="127.0.0.1", port=8765)
|
|
assert config.lifecycle.instance_name == "shd-capture"
|
|
assert config.limits.max_queue_items == 64
|
|
|
|
|
|
@pytest.mark.parametrize("host", ["0.0.0.0", "192.168.1.2", "localhost", "example.test"])
|
|
def test_config_rejects_non_loopback_binding(host: str) -> None:
|
|
with pytest.raises(ConfigError, match="loopback IP literal"):
|
|
parse_config({"server": {"host": host}})
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("document", "message"),
|
|
[
|
|
({"server": {"port": 80}}, "server.port"),
|
|
({"limits": {"max_queue_items": 257}}, "limits.max_queue_items"),
|
|
({"lifecycle": {"instance_name": "SHD Capture"}}, "lifecycle.instance_name"),
|
|
({"openai": {"api_key_env": "openai-key"}}, "openai.api_key_env"),
|
|
],
|
|
)
|
|
def test_config_rejects_invalid_bounded_values(document: dict[str, object], message: str) -> None:
|
|
with pytest.raises(ConfigError, match=message):
|
|
parse_config(document)
|
|
|
|
|
|
def test_xdg_paths_are_resolved_without_writing(tmp_path: Path) -> None:
|
|
root = tmp_path / "xdg"
|
|
paths = resolve_runtime_paths(
|
|
{
|
|
"HOME": str(tmp_path / "home"),
|
|
"XDG_CONFIG_HOME": str(root / "config"),
|
|
"XDG_DATA_HOME": str(root / "data"),
|
|
"XDG_CACHE_HOME": str(root / "cache"),
|
|
"XDG_RUNTIME_DIR": str(root / "runtime"),
|
|
}
|
|
)
|
|
|
|
assert paths.runtime_dir == root / "runtime" / "shd-capture"
|
|
assert not root.exists()
|
|
|
|
|
|
def test_xdg_paths_reject_relative_runtime_path() -> None:
|
|
with pytest.raises(PathConfigurationError, match="XDG runtime"):
|
|
resolve_runtime_paths({"HOME": "/tmp/home", "XDG_RUNTIME_DIR": "relative"})
|
|
|
|
|
|
def test_runtime_directories_and_lock_file_are_owner_only(tmp_path: Path) -> None:
|
|
paths = resolve_runtime_paths(
|
|
{
|
|
"HOME": str(tmp_path),
|
|
"XDG_CONFIG_HOME": str(tmp_path / "config"),
|
|
"XDG_DATA_HOME": str(tmp_path / "data"),
|
|
"XDG_CACHE_HOME": str(tmp_path / "cache"),
|
|
"XDG_RUNTIME_DIR": str(tmp_path / "runtime"),
|
|
}
|
|
)
|
|
|
|
prepare_private_directories(paths)
|
|
prepare_private_file(paths.instance_lock_file)
|
|
|
|
assert S_IMODE(paths.runtime_dir.stat().st_mode) == 0o700
|
|
assert S_IMODE(paths.instance_lock_file.stat().st_mode) == 0o600
|