Тот же источник настроек, что в arm-core#44: приоритет обычный env -> OPENBAO__APP__* -> .env -> умолчание; неизвестное имя — ошибка при старте; ключ APP не ломает OpenBAOSettings. Режим smb из OPENBAO__APP__ включает проверку обязательных OPENBAO__SMB__*. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EAKRDNzXtRrwmWz9z6PZu3
140 lines
5.0 KiB
Python
140 lines
5.0 KiB
Python
"""Несекретные настройки из OpenBao: `OPENBAO__APP__<ИМЯ>` (issue #11).
|
||
|
||
Приоритет: обычный env -> `OPENBAO__APP__*` -> `.env` -> значение по умолчанию.
|
||
"""
|
||
|
||
import os
|
||
from pathlib import Path
|
||
|
||
import pytest
|
||
from pydantic import ValidationError
|
||
|
||
from src.core.config import Settings
|
||
|
||
REQUIRED_ENV = {
|
||
"OPENBAO__MINIO__MINIO_URL": "localhost:9000",
|
||
"OPENBAO__MINIO__MINIO_ADMIN_LOGIN": "login",
|
||
"OPENBAO__MINIO__MINIO_ADMIN_PASSWORD": "password",
|
||
"OPENBAO__MINIO__MINIO_BUCKET": "bucket",
|
||
"OPENBAO__NATS__NATS_URL": "nats://localhost:4222",
|
||
}
|
||
SMB_ENV = {
|
||
"OPENBAO__SMB__SMB_HOST": "smb.example",
|
||
"OPENBAO__SMB__SMB_PATH": "share/dir",
|
||
"OPENBAO__SMB__SMB_LOGIN": "user",
|
||
"OPENBAO__SMB__SMB_PASSWORD": "secret",
|
||
}
|
||
FLAT_KEYS = {
|
||
"DEBUG",
|
||
"NATS_ENABLED",
|
||
"SCAN_HOTFOLDER_MODE",
|
||
"SCAN_HOTFOLDER_PATH",
|
||
"SCAN_POLL_SECONDS",
|
||
"PUBLISH_RETRIES",
|
||
}
|
||
RETRIES = 7
|
||
POLL = 2.5
|
||
PORT = 9000
|
||
|
||
|
||
@pytest.fixture
|
||
def env(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> pytest.MonkeyPatch:
|
||
"""Чистое окружение с обязательными OPENBAO__* и горячей папкой local."""
|
||
for key in list(os.environ):
|
||
if key.startswith(("OPENBAO__", "SERVER__")) or key in FLAT_KEYS:
|
||
monkeypatch.delenv(key)
|
||
for key, value in REQUIRED_ENV.items():
|
||
monkeypatch.setenv(key, value)
|
||
monkeypatch.setenv("SCAN_HOTFOLDER_PATH", str(tmp_path))
|
||
return monkeypatch
|
||
|
||
|
||
def _settings(env_file: Path | None = None) -> Settings:
|
||
return Settings(_env_file=env_file) # type: ignore[call-arg]
|
||
|
||
|
||
def test_app_value_applied(env: pytest.MonkeyPatch) -> None:
|
||
env.setenv("OPENBAO__APP__NATS_ENABLED", "false")
|
||
env.setenv("OPENBAO__APP__DEBUG", "true")
|
||
s = _settings()
|
||
assert s.NATS_ENABLED is False
|
||
assert s.DEBUG is True
|
||
assert s.OPENBAO.NATS.NATS_URL == "nats://localhost:4222"
|
||
|
||
|
||
def test_default_without_app(env: pytest.MonkeyPatch) -> None:
|
||
assert _settings().SCAN_HOTFOLDER_MODE == "local"
|
||
|
||
|
||
def test_plain_env_overrides_app(env: pytest.MonkeyPatch) -> None:
|
||
env.setenv("OPENBAO__APP__NATS_ENABLED", "false")
|
||
env.setenv("NATS_ENABLED", "true")
|
||
assert _settings().NATS_ENABLED is True
|
||
|
||
|
||
def test_app_overrides_dotenv(env: pytest.MonkeyPatch, tmp_path: Path) -> None:
|
||
dotenv = tmp_path / ".env"
|
||
dotenv.write_text("NATS_ENABLED=true\nPUBLISH_RETRIES=5\n", encoding="utf-8")
|
||
env.setenv("OPENBAO__APP__NATS_ENABLED", "false")
|
||
s = _settings(dotenv)
|
||
assert s.NATS_ENABLED is False # OPENBAO__APP__ сильнее .env
|
||
assert s.PUBLISH_RETRIES == 5 # noqa: PLR2004 - значение из .env
|
||
|
||
|
||
def test_types_parsed_like_plain_env(env: pytest.MonkeyPatch) -> None:
|
||
env.setenv("OPENBAO__APP__PUBLISH_RETRIES", str(RETRIES))
|
||
env.setenv("OPENBAO__APP__SCAN_POLL_SECONDS", str(POLL))
|
||
env.setenv("OPENBAO__APP__NATS_ENABLED", "0")
|
||
s = _settings()
|
||
assert s.PUBLISH_RETRIES == RETRIES
|
||
assert s.SCAN_POLL_SECONDS == POLL
|
||
assert s.NATS_ENABLED is False
|
||
|
||
|
||
def test_invalid_value_rejected(env: pytest.MonkeyPatch) -> None:
|
||
env.setenv("OPENBAO__APP__PUBLISH_RETRIES", "0")
|
||
with pytest.raises(ValidationError, match="PUBLISH_RETRIES"):
|
||
_settings()
|
||
|
||
|
||
def test_unknown_name_is_config_error(env: pytest.MonkeyPatch) -> None:
|
||
env.setenv("OPENBAO__APP__SCAN_HOTFOLDER_MOD", "smb")
|
||
with pytest.raises(ValueError, match="SCAN_HOTFOLDER_MOD"):
|
||
_settings()
|
||
|
||
|
||
def test_openbao_group_not_settable_via_app(env: pytest.MonkeyPatch) -> None:
|
||
env.setenv("OPENBAO__APP__OPENBAO__NATS__NATS_URL", "nats://x:4222")
|
||
with pytest.raises(ValueError, match="OPENBAO"):
|
||
_settings()
|
||
|
||
|
||
def test_app_key_does_not_break_openbao_validation(env: pytest.MonkeyPatch, tmp_path: Path) -> None:
|
||
"""Ключ APP не попадает в OpenBAOSettings (там extra=forbid) — ни из env, ни из env-файла."""
|
||
dotenv = tmp_path / ".env"
|
||
dotenv.write_text("OPENBAO__APP__NATS_ENABLED=false\n", encoding="utf-8")
|
||
env.setenv("OPENBAO__APP__DEBUG", "true")
|
||
s = _settings(dotenv)
|
||
assert s.DEBUG is True
|
||
assert not hasattr(s.OPENBAO, "APP")
|
||
|
||
|
||
def test_nested_group_still_works(env: pytest.MonkeyPatch) -> None:
|
||
env.setenv("OPENBAO__MINIO__MINIO_SECURE", "false")
|
||
env.setenv("OPENBAO__APP__SERVER__PORT", str(PORT))
|
||
s = _settings()
|
||
assert s.OPENBAO.MINIO.MINIO_SECURE is False
|
||
assert s.server.PORT == PORT
|
||
|
||
|
||
def test_smb_mode_from_app_applies_and_requires_smb_secrets(env: pytest.MonkeyPatch) -> None:
|
||
"""Режим из OPENBAO__APP__ включает проверку «при smb обязательны OPENBAO__SMB__*» и работает с ними."""
|
||
env.setenv("OPENBAO__APP__SCAN_HOTFOLDER_MODE", "smb")
|
||
with pytest.raises(ValidationError, match="OPENBAO__SMB"):
|
||
_settings()
|
||
for key, value in SMB_ENV.items():
|
||
env.setenv(key, value)
|
||
s = _settings()
|
||
assert s.SCAN_HOTFOLDER_MODE == "smb"
|
||
assert s.OPENBAO.SMB.SMB_PATH == "share/dir"
|