Файлы вне папки app обновление не доставляло: чтобы изменить порядок запуска или конфигурацию Caddy, требовалась переустановка. Теперь .bat - заглушка из трёх строк, вызывающая app/launcher.py, а Caddyfile создаётся из настроек [https] в config.toml. Отредактированный вручную Caddyfile не затирается: новая версия откладывается рядом как Caddyfile.new. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
99 lines
4.5 KiB
Python
99 lines
4.5 KiB
Python
"""Проверки генерации Caddyfile и запуска."""
|
|
from app.launcher import MARK, ensure_caddyfile, render_caddyfile
|
|
|
|
|
|
class TestRender:
|
|
def test_domains_go_into_site_block(self):
|
|
text = render_caddyfile("a.example.com, b.example.com", 8756, 500)
|
|
assert "a.example.com, b.example.com {" in text
|
|
|
|
def test_extra_spaces_and_empty_entries_are_dropped(self):
|
|
text = render_caddyfile(" a.example.com ,, b.example.com ,", 8756, 500)
|
|
assert "a.example.com, b.example.com {" in text
|
|
|
|
def test_port_and_limit_come_from_settings(self):
|
|
text = render_caddyfile("a.example.com", 9000, 250)
|
|
assert "reverse_proxy 127.0.0.1:9000" in text
|
|
assert "max_size 250MB" in text
|
|
|
|
def test_real_client_address_is_forwarded(self):
|
|
"""Без этого заголовка список разрешённых адресов увидит localhost."""
|
|
text = render_caddyfile("a.example.com", 8756, 500)
|
|
assert "header_up X-Forwarded-For {remote_host}" in text
|
|
|
|
def test_caddy_log_goes_to_file(self):
|
|
"""Иначе Caddy забивает консоль сообщениями про сертификаты."""
|
|
text = render_caddyfile("a.example.com", 8756, 500)
|
|
assert "output file logs/caddy.log" in text
|
|
|
|
def test_generated_file_is_marked(self):
|
|
assert render_caddyfile("a.example.com", 8756, 500).startswith(MARK)
|
|
|
|
|
|
class TestEnsure:
|
|
def test_creates_file_when_missing(self, tmp_path):
|
|
content = render_caddyfile("a.example.com", 8756, 500)
|
|
written = ensure_caddyfile(tmp_path, content)
|
|
assert written == tmp_path / "Caddyfile"
|
|
assert written.read_text(encoding="utf-8") == content
|
|
|
|
def test_overwrites_own_previous_version(self, tmp_path):
|
|
ensure_caddyfile(tmp_path, render_caddyfile("old.example.com", 8756, 500))
|
|
fresh = render_caddyfile("new.example.com", 8756, 500)
|
|
ensure_caddyfile(tmp_path, fresh)
|
|
assert (tmp_path / "Caddyfile").read_text(encoding="utf-8") == fresh
|
|
assert not (tmp_path / "Caddyfile.new").exists()
|
|
|
|
def test_keeps_hand_written_file(self, tmp_path):
|
|
"""Чужой файл не трогаем: молча стереть настройку хуже, чем оставить старую."""
|
|
handmade = "site.example.com {\n\treverse_proxy 127.0.0.1:1234\n}\n"
|
|
(tmp_path / "Caddyfile").write_text(handmade, encoding="utf-8")
|
|
written = ensure_caddyfile(tmp_path, render_caddyfile("a.example.com", 8756, 500))
|
|
assert (tmp_path / "Caddyfile").read_text(encoding="utf-8") == handmade
|
|
assert written == tmp_path / "Caddyfile.new"
|
|
assert MARK in written.read_text(encoding="utf-8")
|
|
|
|
def test_no_rewrite_when_nothing_changed(self, tmp_path):
|
|
content = render_caddyfile("a.example.com", 8756, 500)
|
|
ensure_caddyfile(tmp_path, content)
|
|
before = (tmp_path / "Caddyfile").stat().st_mtime_ns
|
|
assert ensure_caddyfile(tmp_path, content) is None
|
|
assert (tmp_path / "Caddyfile").stat().st_mtime_ns == before
|
|
|
|
|
|
class TestStartupOrder:
|
|
def test_updater_runs_before_service(self, tmp_path, monkeypatch):
|
|
"""Обновиться нужно до запуска, иначе обновление бессмысленно."""
|
|
import app.launcher as launcher
|
|
|
|
calls: list[str] = []
|
|
|
|
class FakeSettings:
|
|
base_dir = tmp_path
|
|
port = 8756
|
|
max_upload_mb = 500
|
|
https_domains = ""
|
|
|
|
monkeypatch.setattr("app.config.load_settings", lambda: FakeSettings())
|
|
monkeypatch.setattr("app.updater.main", lambda: calls.append("updater"))
|
|
monkeypatch.setitem(
|
|
__import__("sys").modules, "app.main",
|
|
type("M", (), {"run": staticmethod(lambda: calls.append("run"))}))
|
|
|
|
assert launcher.main([]) == 0
|
|
assert calls == ["updater", "run"]
|
|
|
|
def test_https_without_domains_stops_with_explanation(self, tmp_path, monkeypatch):
|
|
"""Пустые домены - это ошибка настройки, а не повод падать внутри Caddy."""
|
|
import app.launcher as launcher
|
|
|
|
class FakeSettings:
|
|
base_dir = tmp_path
|
|
port = 8756
|
|
max_upload_mb = 500
|
|
https_domains = " "
|
|
|
|
monkeypatch.setattr("app.config.load_settings", lambda: FakeSettings())
|
|
monkeypatch.setattr("app.updater.main", lambda: None)
|
|
assert launcher.main(["https"]) == 1
|