139 lines
4.9 KiB
Python
139 lines
4.9 KiB
Python
"""Tests for app.utils.jail_config.ensure_jail_configs."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
from app.utils.jail_config import (
|
|
_BLOCKLIST_IMPORT_CONF,
|
|
_BLOCKLIST_IMPORT_LOCAL,
|
|
_MANUAL_JAIL_CONF,
|
|
_MANUAL_JAIL_LOCAL,
|
|
ensure_jail_configs,
|
|
)
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Expected filenames
|
|
# ---------------------------------------------------------------------------
|
|
|
|
_MANUAL_CONF = "manual-Jail.conf"
|
|
_MANUAL_LOCAL = "manual-Jail.local"
|
|
_BLOCKLIST_CONF = "blocklist-import.conf"
|
|
_BLOCKLIST_LOCAL = "blocklist-import.local"
|
|
|
|
_ALL_FILES = [_MANUAL_CONF, _MANUAL_LOCAL, _BLOCKLIST_CONF, _BLOCKLIST_LOCAL]
|
|
|
|
_CONTENT_MAP: dict[str, str] = {
|
|
_MANUAL_CONF: _MANUAL_JAIL_CONF,
|
|
_MANUAL_LOCAL: _MANUAL_JAIL_LOCAL,
|
|
_BLOCKLIST_CONF: _BLOCKLIST_IMPORT_CONF,
|
|
_BLOCKLIST_LOCAL: _BLOCKLIST_IMPORT_LOCAL,
|
|
}
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Helpers
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def _read(jail_d: Path, filename: str) -> str:
|
|
return (jail_d / filename).read_text(encoding="utf-8")
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Tests: ensure_jail_configs
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestEnsureJailConfigs:
|
|
def test_all_missing_creates_all_four(self, tmp_path: Path) -> None:
|
|
"""All four files are created when the directory is empty."""
|
|
jail_d = tmp_path / "jail.d"
|
|
ensure_jail_configs(jail_d)
|
|
|
|
for name in _ALL_FILES:
|
|
assert (jail_d / name).exists(), f"{name} should have been created"
|
|
assert _read(jail_d, name) == _CONTENT_MAP[name]
|
|
|
|
def test_all_missing_creates_correct_content(self, tmp_path: Path) -> None:
|
|
"""Each created file has exactly the expected default content."""
|
|
jail_d = tmp_path / "jail.d"
|
|
ensure_jail_configs(jail_d)
|
|
|
|
# .conf files must set enabled = false
|
|
for conf_file in (_MANUAL_CONF, _BLOCKLIST_CONF):
|
|
content = _read(jail_d, conf_file)
|
|
assert "enabled = false" in content
|
|
|
|
# Blocklist-import jail must have a 24-hour ban time
|
|
blocklist_conf = _read(jail_d, _BLOCKLIST_CONF)
|
|
assert "bantime = 86400" in blocklist_conf
|
|
|
|
# .local files must set enabled = true and nothing else
|
|
for local_file in (_MANUAL_LOCAL, _BLOCKLIST_LOCAL):
|
|
content = _read(jail_d, local_file)
|
|
assert "enabled = true" in content
|
|
|
|
def test_all_present_overwrites_nothing(self, tmp_path: Path) -> None:
|
|
"""Existing files are never overwritten."""
|
|
jail_d = tmp_path / "jail.d"
|
|
jail_d.mkdir()
|
|
|
|
sentinel = "# EXISTING CONTENT — must not be replaced\n"
|
|
for name in _ALL_FILES:
|
|
(jail_d / name).write_text(sentinel, encoding="utf-8")
|
|
|
|
ensure_jail_configs(jail_d)
|
|
|
|
for name in _ALL_FILES:
|
|
assert _read(jail_d, name) == sentinel, (
|
|
f"{name} should not have been overwritten"
|
|
)
|
|
|
|
def test_only_local_files_missing_creates_only_locals(
|
|
self, tmp_path: Path
|
|
) -> None:
|
|
"""Only the .local files are created when the .conf files already exist."""
|
|
jail_d = tmp_path / "jail.d"
|
|
jail_d.mkdir()
|
|
|
|
sentinel = "# pre-existing conf\n"
|
|
for conf_file in (_MANUAL_CONF, _BLOCKLIST_CONF):
|
|
(jail_d / conf_file).write_text(sentinel, encoding="utf-8")
|
|
|
|
ensure_jail_configs(jail_d)
|
|
|
|
# .conf files must remain unchanged
|
|
for conf_file in (_MANUAL_CONF, _BLOCKLIST_CONF):
|
|
assert _read(jail_d, conf_file) == sentinel
|
|
|
|
# .local files must have been created with correct content
|
|
for local_file, expected in (
|
|
(_MANUAL_LOCAL, _MANUAL_JAIL_LOCAL),
|
|
(_BLOCKLIST_LOCAL, _BLOCKLIST_IMPORT_LOCAL),
|
|
):
|
|
assert (jail_d / local_file).exists(), f"{local_file} should have been created"
|
|
assert _read(jail_d, local_file) == expected
|
|
|
|
def test_creates_jail_d_directory_if_missing(self, tmp_path: Path) -> None:
|
|
"""The jail.d directory is created automatically when absent."""
|
|
jail_d = tmp_path / "nested" / "jail.d"
|
|
assert not jail_d.exists()
|
|
ensure_jail_configs(jail_d)
|
|
assert jail_d.is_dir()
|
|
|
|
def test_idempotent_on_repeated_calls(self, tmp_path: Path) -> None:
|
|
"""Calling ensure_jail_configs twice does not alter any file."""
|
|
jail_d = tmp_path / "jail.d"
|
|
ensure_jail_configs(jail_d)
|
|
|
|
# Record content after first call
|
|
first_pass = {name: _read(jail_d, name) for name in _ALL_FILES}
|
|
|
|
ensure_jail_configs(jail_d)
|
|
|
|
for name in _ALL_FILES:
|
|
assert _read(jail_d, name) == first_pass[name], (
|
|
f"{name} changed on second call"
|
|
)
|