89 lines
2.5 KiB
Python
89 lines
2.5 KiB
Python
from __future__ import annotations
|
|
|
|
import re
|
|
import shutil
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parents[1]
|
|
ENTRYPOINT = REPO_ROOT / "entrypoint.sh"
|
|
|
|
|
|
def _has_bash() -> bool:
|
|
return shutil.which("bash") is not None
|
|
|
|
|
|
def _minimal_path() -> str:
|
|
parts = ["/usr/bin", "/bin", "/usr/sbin", "/sbin"]
|
|
for p in parts:
|
|
if Path(p).exists():
|
|
return ":".join(parts)
|
|
return os.environ.get("PATH", "")
|
|
|
|
|
|
def _clean_env() -> dict[str, str]:
|
|
env = {
|
|
"PATH": _minimal_path(),
|
|
"DEBIAN_FRONTEND": "noninteractive",
|
|
"HOME": "/tmp",
|
|
"LANG": "C.UTF-8",
|
|
}
|
|
return env
|
|
|
|
|
|
@pytest.mark.skipif(not _has_bash(), reason="bash not available")
|
|
def test_entrypoint_rejects_bad_run_at(tmp_path: Path, monkeypatch) -> None:
|
|
"""The entrypoint must exit non-zero with a clear message on a bad RUN_AT."""
|
|
env = _clean_env()
|
|
env["MASTODON_BASE_URL"] = "https://mastodon.example"
|
|
env["MASTODON_ACCESS_TOKEN"] = "x"
|
|
env["SITE_URL"] = "https://blog.example.com"
|
|
env["HASHTAGS"] = "#throwback"
|
|
env["RUN_AT"] = "25:99"
|
|
env["TZ"] = "Europe/Berlin"
|
|
|
|
proc = subprocess.run(
|
|
["/bin/bash", str(ENTRYPOINT)],
|
|
capture_output=True,
|
|
text=True,
|
|
env=env,
|
|
timeout=10,
|
|
check=False,
|
|
)
|
|
assert proc.returncode != 0
|
|
assert "RUN_AT" in (proc.stdout + proc.stderr)
|
|
|
|
|
|
@pytest.mark.skipif(not _has_bash(), reason="bash not available")
|
|
def test_entrypoint_fails_fast_when_token_missing(tmp_path: Path, monkeypatch) -> None:
|
|
"""A missing required var must abort before cron is started."""
|
|
env = _clean_env()
|
|
env["MASTODON_BASE_URL"] = "https://mastodon.example"
|
|
env["SITE_URL"] = "https://blog.example.com"
|
|
env["HASHTAGS"] = "#throwback"
|
|
env["RUN_AT"] = "09:00"
|
|
env["TZ"] = "Europe/Berlin"
|
|
env.pop("MASTODON_ACCESS_TOKEN", None)
|
|
|
|
proc = subprocess.run(
|
|
["/bin/bash", str(ENTRYPOINT)],
|
|
capture_output=True,
|
|
text=True,
|
|
env=env,
|
|
timeout=10,
|
|
check=False,
|
|
)
|
|
assert proc.returncode != 0
|
|
combined = (proc.stdout + proc.stderr).lower()
|
|
assert "missing" in combined
|
|
assert "mastodon_access_token" in combined.lower()
|
|
|
|
|
|
def test_entrypoint_references_cron_in_foreground() -> None:
|
|
text = ENTRYPOINT.read_text()
|
|
assert re.search(r"exec\s+cron\s+-f", text), "entrypoint must exec cron in the foreground"
|
|
cron = (REPO_ROOT / "crontab" / "tenbackward.cron").read_text()
|
|
assert "SHELL=/bin/bash" in cron
|