221 lines
6.8 KiB
Python
221 lines
6.8 KiB
Python
from __future__ import annotations
|
|
|
|
import os
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from tenbackward.config import ConfigError, load_config, validate_config, validate_required
|
|
|
|
|
|
def _populate(env_setup) -> dict[str, str]:
|
|
return {k: os.environ[k] for k in os.environ if k.startswith(("MASTODON_", "SITE_", "HASHTAGS", "THROWBACK_", "MAX_RETRIES", "RUN_AT", "TZ"))}
|
|
|
|
|
|
def _full_values() -> dict[str, str]:
|
|
return {
|
|
"MASTODON_BASE_URL": "https://mastodon.example",
|
|
"MASTODON_ACCESS_TOKEN": "x",
|
|
"MASTODON_VISIBILITY": "public",
|
|
"SITE_URL": "https://blog.example.com",
|
|
"HASHTAGS": "#throwback",
|
|
"THROWBACK_PREFIX": "Throwback:",
|
|
"MAX_RETRIES": "3",
|
|
"RUN_AT": "09:00",
|
|
"TZ": "Europe/Berlin",
|
|
}
|
|
|
|
|
|
def test_load_config_succeeds_with_complete_env(env_setup) -> None:
|
|
config = load_config()
|
|
assert config.mastodon_base_url == "https://mastodon.example"
|
|
assert config.run_at == "09:00"
|
|
assert config.max_retries == 3
|
|
assert config.throwback_prefix == "Throwback:"
|
|
assert config.mastodon_visibility == "public"
|
|
|
|
|
|
def test_load_config_blog_defaults(env_setup) -> None:
|
|
config = load_config()
|
|
assert config.blog_repo_url == "https://git.chaospott.de/Chaospott/site"
|
|
assert config.blog_dir.name == "blog"
|
|
|
|
|
|
def test_load_config_blog_repo_url_override(env_setup, monkeypatch) -> None:
|
|
monkeypatch.setenv("BLOG_REPO_URL", "https://example.com/repo.git")
|
|
config = load_config()
|
|
assert config.blog_repo_url == "https://example.com/repo.git"
|
|
|
|
|
|
def test_validate_config_rejects_bad_blog_repo_url(env_setup) -> None:
|
|
values = {
|
|
"MASTODON_BASE_URL": "https://mastodon.example",
|
|
"MASTODON_ACCESS_TOKEN": "x",
|
|
"MASTODON_VISIBILITY": "public",
|
|
"SITE_URL": "https://blog.example.com",
|
|
"HASHTAGS": "#throwback",
|
|
"THROWBACK_PREFIX": "Throwback:",
|
|
"MAX_RETRIES": "3",
|
|
"RUN_AT": "09:00",
|
|
"TZ": "Europe/Berlin",
|
|
"BLOG_REPO_URL": "ftp://bad",
|
|
}
|
|
with pytest.raises(ConfigError, match="BLOG_REPO_URL"):
|
|
validate_config(values)
|
|
|
|
|
|
def test_validate_config_lists_every_missing_key(env_setup, monkeypatch) -> None:
|
|
monkeypatch.delenv("MASTODON_ACCESS_TOKEN")
|
|
monkeypatch.delenv("SITE_URL")
|
|
|
|
values = {k: os.environ.get(k, "") for k in [
|
|
"MASTODON_BASE_URL",
|
|
"MASTODON_ACCESS_TOKEN",
|
|
"MASTODON_VISIBILITY",
|
|
"SITE_URL",
|
|
"HASHTAGS",
|
|
"THROWBACK_PREFIX",
|
|
"MAX_RETRIES",
|
|
"RUN_AT",
|
|
"TZ",
|
|
]}
|
|
|
|
with pytest.raises(ConfigError) as excinfo:
|
|
validate_required(values)
|
|
|
|
message = str(excinfo.value)
|
|
assert "MASTODON_ACCESS_TOKEN" in message
|
|
assert "SITE_URL" in message
|
|
|
|
|
|
def test_load_config_fails_fast_on_missing_required(env_setup, monkeypatch) -> None:
|
|
monkeypatch.delenv("MASTODON_ACCESS_TOKEN", raising=False)
|
|
|
|
with pytest.raises(ConfigError, match="MASTODON_ACCESS_TOKEN"):
|
|
load_config()
|
|
|
|
|
|
def test_validate_config_rejects_bad_run_at() -> None:
|
|
values = _full_values()
|
|
values["RUN_AT"] = "25:99"
|
|
with pytest.raises(ConfigError):
|
|
validate_config(values)
|
|
|
|
|
|
def test_validate_config_rejects_invalid_url() -> None:
|
|
values = _full_values()
|
|
values["SITE_URL"] = "not-a-url"
|
|
with pytest.raises(ConfigError, match="SITE_URL"):
|
|
validate_config(values)
|
|
|
|
values = _full_values()
|
|
values["MASTODON_BASE_URL"] = "ftp://mastodon.example"
|
|
with pytest.raises(ConfigError, match="MASTODON_BASE_URL"):
|
|
validate_config(values)
|
|
|
|
|
|
def test_validate_config_rejects_invalid_visibility() -> None:
|
|
for bad in ("private", "direct", "PUBLIC"):
|
|
values = _full_values()
|
|
values["MASTODON_VISIBILITY"] = bad
|
|
with pytest.raises(ConfigError, match="MASTODON_VISIBILITY"):
|
|
validate_config(values)
|
|
|
|
|
|
def test_validate_required_rejects_empty_visibility() -> None:
|
|
values = _full_values()
|
|
values["MASTODON_VISIBILITY"] = ""
|
|
with pytest.raises(ConfigError, match="MASTODON_VISIBILITY"):
|
|
validate_required(values)
|
|
|
|
|
|
def test_validate_config_rejects_invalid_tz() -> None:
|
|
values = _full_values()
|
|
values["TZ"] = "Not/AZone"
|
|
with pytest.raises(ConfigError, match="TZ"):
|
|
validate_config(values)
|
|
|
|
|
|
def test_validate_config_rejects_negative_max_retries() -> None:
|
|
values = _full_values()
|
|
values["MAX_RETRIES"] = "-1"
|
|
with pytest.raises(ConfigError, match="MAX_RETRIES"):
|
|
validate_config(values)
|
|
|
|
|
|
def test_validate_config_accepts_zero_max_retries() -> None:
|
|
values = _full_values()
|
|
values["MAX_RETRIES"] = "0"
|
|
validate_config(values)
|
|
|
|
|
|
def test_load_config_applies_optional_defaults(env_setup, monkeypatch) -> None:
|
|
monkeypatch.delenv("MAX_RETRIES", raising=False)
|
|
|
|
config = load_config()
|
|
assert config.max_retries == 5
|
|
assert config.blog_repo_url == "https://git.chaospott.de/Chaospott/site"
|
|
assert config.blog_dir.name == "blog"
|
|
|
|
|
|
def test_load_config_reads_dotenv_file(tmp_path: Path, monkeypatch) -> None:
|
|
dotenv = tmp_path / ".env"
|
|
dotenv.write_text(
|
|
"MASTODON_BASE_URL=https://from-file.example\n"
|
|
"MASTODON_ACCESS_TOKEN=file-token\n"
|
|
"MASTODON_VISIBILITY=unlisted\n"
|
|
"SITE_URL=https://blog.example.com\n"
|
|
"HASHTAGS=#throwback\n"
|
|
"THROWBACK_PREFIX=Werferückblick:\n"
|
|
"MAX_RETRIES=5\n"
|
|
"RUN_AT=12:34\n"
|
|
"TZ=Europe/Berlin\n"
|
|
)
|
|
|
|
for key in (
|
|
"MASTODON_BASE_URL",
|
|
"MASTODON_ACCESS_TOKEN",
|
|
"MASTODON_VISIBILITY",
|
|
"SITE_URL",
|
|
"HASHTAGS",
|
|
"THROWBACK_PREFIX",
|
|
"MAX_RETRIES",
|
|
"RUN_AT",
|
|
"TZ",
|
|
):
|
|
monkeypatch.delenv(key, raising=False)
|
|
|
|
config = load_config(dotenv_path=dotenv)
|
|
assert config.mastodon_base_url == "https://from-file.example"
|
|
assert config.mastodon_access_token == "file-token"
|
|
assert config.run_at == "12:34"
|
|
assert config.mastodon_visibility == "unlisted"
|
|
assert config.throwback_prefix == "Werferückblick:"
|
|
assert config.max_retries == 5
|
|
|
|
|
|
def test_env_overrides_dotenv(tmp_path: Path, monkeypatch) -> None:
|
|
dotenv = tmp_path / ".env"
|
|
dotenv.write_text("RUN_AT=01:00\n")
|
|
|
|
monkeypatch.setenv("RUN_AT", "23:00")
|
|
for key in (
|
|
"MASTODON_BASE_URL",
|
|
"MASTODON_ACCESS_TOKEN",
|
|
"MASTODON_VISIBILITY",
|
|
"SITE_URL",
|
|
"HASHTAGS",
|
|
"THROWBACK_PREFIX",
|
|
"MAX_RETRIES",
|
|
"TZ",
|
|
):
|
|
monkeypatch.setenv(key, "x")
|
|
monkeypatch.setenv("MASTODON_BASE_URL", "https://mastodon.example")
|
|
monkeypatch.setenv("SITE_URL", "https://blog.example.com")
|
|
monkeypatch.setenv("MASTODON_VISIBILITY", "public")
|
|
monkeypatch.setenv("TZ", "Europe/Berlin")
|
|
monkeypatch.setenv("MAX_RETRIES", "3")
|
|
|
|
config = load_config(dotenv_path=dotenv)
|
|
assert config.run_at == "23:00"
|