arm-scan-gateway/api/tests/unit/test_config_openbao_app.py
Andrey Epifancev 0ad8858d6f feat(config): несекретные настройки из OpenBao через OPENBAO__APP__<ИМЯ> (#11)
Тот же источник настроек, что в 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
2026-10-07 18:35:39 +04:00

140 lines
5.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Несекретные настройки из 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"