fix: SMB необязателен, остановка lifespan по независимым шагам (I-3, T4.5, M-3)
- OPENBAO__SMB__* необязательны (по умолчанию пусто); при пустом SMB_HOST сессия SMB не регистрируется (DEBUG «SMB не настроен»), в .env.example и .env.test SMB выключен — в логе dev-запуска больше нет трейсбэка SMB. - Задан SMB_HOST: register_session и reset_connection_cache вызываются через asyncio.to_thread и не блокируют цикл событий. - Остановка: задачи обмена -> NATS -> S3 -> SMB -> engine.dispose(); каждый шаг в своём try/except с логом step=..., ошибка одного шага не отменяет следующие. Пул соединений БД закрывается последним (M-3). - README: «что в логе при запуске», таблица настроек SMB, порядок остановки. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
6a6ffb54f4
commit
3d31c1eac5
30
README.md
30
README.md
@ -155,21 +155,23 @@ Dev-пользователи (`api/seed/dev/users.yaml`, создаются `mak
|
||||
|
||||
### Что вы увидите в логе при запуске
|
||||
|
||||
Старт занимает около секунды; в логе один трейсбэк — это ожидаемо в dev, приложение при этом работает:
|
||||
|
||||
- Трейсбэк SMB: `Ошибка при регистрации сессии SMB ... Failed to connect to 'localhost:445': Connection refused`.
|
||||
Настройки `OPENBAO__SMB__*` — заглушки, SMB в Срезе 0 не используется; игнорируйте. Пока на `localhost:445` ничего
|
||||
не слушает, отказ приходит сразу (старт не задерживается); если порт отвечает, но молчит, ожидание ограничено
|
||||
тайм-аутом `smbclient` (60 с).
|
||||
Старт занимает около секунды; трейсбэков в логе нет. SMB (горячие папки ИС Сканирование из шаблона) необязателен и по
|
||||
умолчанию выключен: в `.env.example` `OPENBAO__SMB__SMB_HOST` пуст, сессия SMB не регистрируется (сообщение об этом —
|
||||
только на уровне DEBUG). Если `SMB_HOST` задан, регистрация выполняется в отдельном потоке (цикл событий не
|
||||
блокируется; старт ждёт её завершения не дольше тайм-аута `smbclient`, 60 с); ошибка подключения логируется трейсбэком
|
||||
`Ошибка при регистрации сессии SMB`, приложение продолжает работу.
|
||||
|
||||
Строки `Бакет проверен`, `Подключение к NATS установлено` и `Подписка NATS активна. subject=recognition.result,
|
||||
queue=arm-core` означают, что S3 и NATS из compose подключены (MinIO из compose слушает `http`, поэтому в `.env`
|
||||
задано `OPENBAO__MINIO__MINIO_SECURE=false`).
|
||||
|
||||
Недоступность SMB, S3 или NATS при старте приложение не роняет и не задерживает: ошибка логируется, состояние NATS
|
||||
видно в `/healthcheck`. К NATS ядро подключается в фоне и повторяет попытки само (`nats=down`, пока связи нет; warning
|
||||
в логе — на первую ошибку и дальше не чаще раза в минуту); после разрыва nats-py переподключается и восстанавливает
|
||||
подписку.
|
||||
Недоступность S3 или NATS при старте приложение не роняет и не задерживает (недоступный SMB, если он настроен, — не
|
||||
роняет): ошибка логируется, состояние NATS видно в `/healthcheck`. К NATS ядро подключается в фоне и повторяет попытки
|
||||
само (`nats=down`, пока связи нет; warning в логе — на первую ошибку и дальше не чаще раза в минуту); после разрыва
|
||||
nats-py переподключается и восстанавливает подписку.
|
||||
|
||||
При остановке ресурсы закрываются по шагам: фоновые задачи обмена → NATS → S3 → SMB → пул соединений БД. Ошибка
|
||||
одного шага логируется (`Ошибка при остановке приложения. step=...`) и не отменяет следующие.
|
||||
|
||||
Предупреждение «Включён dev-эмитент токенов … только для разработки» появляется не при старте, а при первом
|
||||
запросе к защищённому эндпоинту (`/api/v1/me`): проверяющий токены создаётся лениво (штатно, см. «Безопасность
|
||||
@ -207,10 +209,10 @@ docker compose -f ../docs/dev/docker-compose.yml down -v # полный сб
|
||||
| `OPENBAO__NATS__NATS_URL` | — (обязательно) | адрес NATS (`nats://localhost:4222`) |
|
||||
| `OPENBAO__NATS__NATS_SEED` | пусто | nkey seed; пусто — подключение без учётных данных (compose, тесты). Задаётся вместе с `NATS_JWT` или не задаётся вовсе |
|
||||
| `OPENBAO__NATS__NATS_JWT` | пусто | JWT NATS; см. `NATS_SEED` |
|
||||
| `OPENBAO__SMB__SMB_HOST` | — (обязательно) | заглушка SMB (в Срезе 0 не используется, блок обязателен) |
|
||||
| `OPENBAO__SMB__SMB_PATH` | — (обязательно) | заглушка SMB |
|
||||
| `OPENBAO__SMB__SMB_LOGIN` | — (обязательно) | заглушка SMB |
|
||||
| `OPENBAO__SMB__SMB_PASSWORD` | — (обязательно) | заглушка SMB |
|
||||
| `OPENBAO__SMB__SMB_HOST` | пусто | SMB из шаблона, необязателен (ядру в Срезе 0 не нужен). Пусто — сессия SMB не регистрируется; задан — регистрация при старте (в отдельном потоке) и сброс кэша соединений при остановке |
|
||||
| `OPENBAO__SMB__SMB_PATH` | пусто | путь SMB (в Срезе 0 не используется) |
|
||||
| `OPENBAO__SMB__SMB_LOGIN` | пусто | логин SMB |
|
||||
| `OPENBAO__SMB__SMB_PASSWORD` | пусто | пароль SMB |
|
||||
| `NATS_ENABLED` | `false` | подключение к NATS и обмен через `recognition_job`: фоновые outbox-публикатор и вахтёр сроков ответа (период 30 с, `processing`/`published` с прошедшим `reply_deadline` → `timeout`); без него фоновых задач нет, `/healthcheck` показывает `nats=off` |
|
||||
| `OUTBOX_POLL_SECONDS` | `5` | период опроса outbox (`queued` → публикация → `published`) |
|
||||
| `ACK_TIMEOUT_SECONDS` | `30` | ожидание ack сервиса распознавания до повторной публикации |
|
||||
|
||||
@ -19,11 +19,11 @@ OPENBAO__NATS__NATS_URL=nats://localhost:4222
|
||||
OPENBAO__NATS__NATS_SEED=
|
||||
OPENBAO__NATS__NATS_JWT=
|
||||
|
||||
# SMB — заглушки (в Срезе 0 не используется)
|
||||
OPENBAO__SMB__SMB_HOST=localhost
|
||||
OPENBAO__SMB__SMB_PATH=share
|
||||
OPENBAO__SMB__SMB_LOGIN=user
|
||||
OPENBAO__SMB__SMB_PASSWORD=password
|
||||
# SMB необязателен (ядру в Срезе 0 не нужен): пустой SMB_HOST — сессия SMB не регистрируется
|
||||
OPENBAO__SMB__SMB_HOST=
|
||||
OPENBAO__SMB__SMB_PATH=
|
||||
OPENBAO__SMB__SMB_LOGIN=
|
||||
OPENBAO__SMB__SMB_PASSWORD=
|
||||
|
||||
# Аутентификация. Dev-эмитент работает только при AUTH_DEV_ISSUER=true И DEBUG=true.
|
||||
AUTH_DEV_ISSUER=true
|
||||
|
||||
@ -17,10 +17,11 @@ OPENBAO__NATS__NATS_URL=nats://localhost:4222
|
||||
OPENBAO__NATS__NATS_SEED=
|
||||
OPENBAO__NATS__NATS_JWT=
|
||||
|
||||
OPENBAO__SMB__SMB_HOST=localhost
|
||||
OPENBAO__SMB__SMB_PATH=share
|
||||
OPENBAO__SMB__SMB_LOGIN=user
|
||||
OPENBAO__SMB__SMB_PASSWORD=password
|
||||
# SMB необязателен: пустой SMB_HOST — сессия SMB не регистрируется
|
||||
OPENBAO__SMB__SMB_HOST=
|
||||
OPENBAO__SMB__SMB_PATH=
|
||||
OPENBAO__SMB__SMB_LOGIN=
|
||||
OPENBAO__SMB__SMB_PASSWORD=
|
||||
|
||||
AUTH_DEV_ISSUER=true
|
||||
AUTH_DEV_SECRET=test-only-secret-not-for-production-0123456789
|
||||
|
||||
@ -2,17 +2,21 @@
|
||||
|
||||
Что здесь есть: настройки, подключение S3 (MinIO; `MINIO_SECURE` — https или http), NATS (`src/core/nats.py`: core
|
||||
NATS без JetStream, подключение в фоне при NATS_ENABLED=true независимо от DEBUG, подписка `recognition.result` в queue
|
||||
group `arm-core`), SMB (горячие папки ИС Сканирование), middleware (gzip, proxy headers, CORS; при DEBUG=False пакет
|
||||
РАИСА лишь условно импортируется, middleware не подключается), healthcheck (uptime, version, nats: ok|down|off), раздача
|
||||
собранного SPA.
|
||||
group `arm-core`), SMB (горячие папки ИС Сканирование; необязателен — при пустом `SMB_HOST` не подключается),
|
||||
middleware (gzip, proxy headers, CORS; при DEBUG=False пакет РАИСА лишь условно импортируется, middleware не
|
||||
подключается), healthcheck (uptime, version, nats: ok|down|off), раздача собранного SPA.
|
||||
Недоступность S3 или NATS при старте не роняет и не задерживает приложение: ошибка логируется, healthcheck показывает
|
||||
состояние. При NATS_ENABLED=true lifespan запускает фоновые задачи обмена `recognition_job` — outbox-публикатор и
|
||||
вахтёр сроков (`src/services/recognition_exchange.py`, design D-6) — и останавливает их до закрытия NATS. Сообщения
|
||||
`recognition.result` (ack и результаты сервисов) обрабатывает inbox `handle_message` того же модуля с фабрикой сессий
|
||||
приложения и `NoopMapper` (маппинг результата в доменные таблицы — Срез 2).
|
||||
Остановка: фоновые задачи обмена → NATS → S3 → SMB → пул соединений БД; каждый шаг независим — ошибка одного
|
||||
логируется и не отменяет остальные.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
from collections.abc import Awaitable, Callable
|
||||
from contextlib import asynccontextmanager
|
||||
from datetime import UTC, datetime
|
||||
from functools import partial
|
||||
@ -33,7 +37,7 @@ from src.core.clients import S3Storage
|
||||
from src.core.config import get_settings
|
||||
from src.core.exception_handlers import register_exception_handlers
|
||||
from src.core.nats import MessageHandler, NatsConnection
|
||||
from src.db.db import async_session_maker
|
||||
from src.db.db import async_session_maker, engine
|
||||
from src.services.recognition_exchange import ExchangeTasks, NoopMapper, handle_message
|
||||
|
||||
settings = get_settings()
|
||||
@ -118,18 +122,57 @@ def _start_exchange(nats: NatsConnection) -> ExchangeTasks:
|
||||
return ExchangeTasks.start(async_session_maker, nats, settings)
|
||||
|
||||
|
||||
def _smb_configured() -> bool:
|
||||
return bool(settings.OPENBAO.SMB.SMB_HOST)
|
||||
|
||||
|
||||
async def _register_smb() -> None:
|
||||
"""Сессия SMB (шаблон) — только если задан `SMB_HOST`; вызов блокирующий, поэтому в отдельном потоке."""
|
||||
smb = settings.OPENBAO.SMB
|
||||
if not _smb_configured():
|
||||
logger.debug("SMB не настроен (OPENBAO__SMB__SMB_HOST пуст): сессия SMB не регистрируется")
|
||||
return
|
||||
try:
|
||||
await asyncio.to_thread(smbclient.register_session, smb.SMB_HOST, smb.SMB_LOGIN, smb.SMB_PASSWORD)
|
||||
except Exception:
|
||||
logger.exception("Ошибка при регистрации сессии SMB")
|
||||
|
||||
|
||||
async def _reset_smb() -> None:
|
||||
"""Закрывает кэш соединений SMB (блокирующий вызов — в отдельном потоке); без SMB ничего не делает."""
|
||||
if _smb_configured():
|
||||
await asyncio.to_thread(smbclient.reset_connection_cache)
|
||||
|
||||
|
||||
async def _cleanup_step(name: str, action: Callable[[], Awaitable[object]]) -> None:
|
||||
"""Один шаг остановки: исключение логируется и не мешает следующим шагам."""
|
||||
try:
|
||||
await action()
|
||||
except Exception:
|
||||
logger.exception("Ошибка при остановке приложения. step={step}", step=name)
|
||||
|
||||
|
||||
async def _shutdown(app: FastAPI) -> None:
|
||||
"""Остановка по шагам: задачи обмена (до NATS: публикатор не пишет в закрытое соединение) → NATS → S3 → SMB →
|
||||
пул соединений БД (последним: задачи обмена и inbox к этому моменту остановлены)."""
|
||||
exchange, nats, storage = app.state.exchange, app.state.nats, app.state.storage
|
||||
if exchange is not None:
|
||||
await _cleanup_step("exchange", exchange.stop)
|
||||
if nats is not None:
|
||||
await _cleanup_step("nats", nats.stop)
|
||||
if storage:
|
||||
await _cleanup_step("s3", storage.client.close_session)
|
||||
await _cleanup_step("smb", _reset_smb)
|
||||
await _cleanup_step("db", engine.dispose)
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
app.state.storage = None
|
||||
app.state.nats = None
|
||||
app.state.exchange = None
|
||||
|
||||
try:
|
||||
smbclient.register_session(
|
||||
settings.OPENBAO.SMB.SMB_HOST, settings.OPENBAO.SMB.SMB_LOGIN, settings.OPENBAO.SMB.SMB_PASSWORD
|
||||
)
|
||||
except Exception:
|
||||
logger.exception("Ошибка при регистрации сессии SMB")
|
||||
await _register_smb()
|
||||
|
||||
try:
|
||||
app.state.storage = await _connect_s3()
|
||||
@ -142,13 +185,7 @@ async def lifespan(app: FastAPI):
|
||||
yield
|
||||
finally:
|
||||
logger.info("Приложение закрывается")
|
||||
smbclient.reset_connection_cache()
|
||||
if app.state.exchange is not None: # до закрытия NATS: публикатор не должен писать в закрытое соединение
|
||||
await app.state.exchange.stop()
|
||||
if app.state.nats is not None:
|
||||
await app.state.nats.stop()
|
||||
if app.state.storage:
|
||||
await app.state.storage.client.close_session()
|
||||
await _shutdown(app)
|
||||
|
||||
|
||||
app = FastAPI(title="АРМ КА", version=VERSION, root_path=settings.ROOT_PATH, lifespan=lifespan)
|
||||
|
||||
@ -22,17 +22,20 @@ class NATSSettings(BaseSettings):
|
||||
|
||||
|
||||
class SMBSettings(BaseSettings):
|
||||
SMB_HOST: str
|
||||
SMB_PATH: str
|
||||
SMB_LOGIN: str
|
||||
SMB_PASSWORD: str
|
||||
"""SMB (горячие папки ИС Сканирование, шаблон). Необязательны: ядру в Срезе 0 SMB не нужен; пустой `SMB_HOST` —
|
||||
сессия SMB не регистрируется."""
|
||||
|
||||
SMB_HOST: str = ""
|
||||
SMB_PATH: str = ""
|
||||
SMB_LOGIN: str = ""
|
||||
SMB_PASSWORD: str = ""
|
||||
|
||||
|
||||
class OpenBAOSettings(BaseSettings):
|
||||
DATABASE: DBSettings
|
||||
MINIO: MinioSettings
|
||||
NATS: NATSSettings
|
||||
SMB: SMBSettings
|
||||
SMB: SMBSettings = SMBSettings() # все поля необязательны (см. SMBSettings)
|
||||
|
||||
|
||||
class ServerSettings(BaseSettings):
|
||||
|
||||
@ -5,12 +5,14 @@
|
||||
|
||||
import asyncio
|
||||
import importlib
|
||||
import threading
|
||||
from http import HTTPStatus
|
||||
from types import SimpleNamespace
|
||||
from typing import Any
|
||||
|
||||
import httpx
|
||||
import pytest
|
||||
from loguru import logger
|
||||
|
||||
from src.api.router import router
|
||||
from src.core.nats import NatsConnection
|
||||
@ -94,6 +96,27 @@ def _no_smb(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
monkeypatch.setattr(app_module.smbclient, "reset_connection_cache", lambda: None)
|
||||
|
||||
|
||||
class _FakeEngine:
|
||||
"""Подмена движка БД приложения: lifespan вызывает `dispose()` последним шагом остановки (финальное ревью M-3)."""
|
||||
|
||||
def __init__(self, events: list[str] | None = None) -> None:
|
||||
self.disposed = 0
|
||||
self.events = events
|
||||
|
||||
async def dispose(self) -> None:
|
||||
self.disposed += 1
|
||||
if self.events is not None:
|
||||
self.events.append("db")
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def fake_engine(monkeypatch: pytest.MonkeyPatch) -> _FakeEngine:
|
||||
"""Lifespan в быстрых тестах не трогает пул реального движка БД."""
|
||||
engine = _FakeEngine()
|
||||
monkeypatch.setattr(app_module, "engine", engine)
|
||||
return engine
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def exchange_loops(monkeypatch: pytest.MonkeyPatch) -> list[str]:
|
||||
"""Циклы публикатора и вахтёра подменены ожиданием: быстрые тесты lifespan не ходят в БД."""
|
||||
@ -300,3 +323,113 @@ async def test_lifespan_without_nats_starts_no_exchange_tasks(
|
||||
await asyncio.sleep(0)
|
||||
assert exchange_loops == []
|
||||
assert asyncio.all_tasks() - tasks_before == set()
|
||||
|
||||
|
||||
# --- SMB необязателен, остановка по независимым шагам (финальное ревью I-3, T4.5, M-3) -------------------------------
|
||||
|
||||
|
||||
async def _unavailable_s3() -> None:
|
||||
return None
|
||||
|
||||
|
||||
def test_env_files_leave_smb_off():
|
||||
"""В `.env.test` (и, значит, в тестах) SMB выключен: пустой SMB_HOST."""
|
||||
assert app_module.settings.OPENBAO.SMB.SMB_HOST == ""
|
||||
|
||||
|
||||
async def test_lifespan_skips_smb_when_host_empty(monkeypatch: pytest.MonkeyPatch, fake_engine: _FakeEngine):
|
||||
def forbidden(*args: Any, **kwargs: Any) -> None:
|
||||
raise AssertionError("SMB не настроен — вызова быть не должно")
|
||||
|
||||
records: list[Any] = []
|
||||
handler_id = logger.add(lambda message: records.append(message.record), level="DEBUG")
|
||||
monkeypatch.setattr(app_module.settings.OPENBAO.SMB, "SMB_HOST", "")
|
||||
monkeypatch.setattr(app_module.smbclient, "register_session", forbidden)
|
||||
monkeypatch.setattr(app_module.smbclient, "reset_connection_cache", forbidden)
|
||||
monkeypatch.setattr(app_module, "_connect_s3", _unavailable_s3)
|
||||
monkeypatch.setattr(app_module, "_create_nats", lambda: None)
|
||||
try:
|
||||
async with app_module.lifespan(app_module.app):
|
||||
pass
|
||||
finally:
|
||||
logger.remove(handler_id)
|
||||
|
||||
assert [r for r in records if "SMB не настроен" in r["message"] and r["level"].name == "DEBUG"]
|
||||
assert not [r for r in records if r["level"].name == "ERROR"]
|
||||
assert fake_engine.disposed == 1
|
||||
|
||||
|
||||
async def test_lifespan_registers_smb_in_worker_thread_when_configured(monkeypatch: pytest.MonkeyPatch):
|
||||
"""Задан SMB_HOST: `register_session` и `reset_connection_cache` — вне потока цикла событий (`to_thread`)."""
|
||||
loop_thread = threading.get_ident()
|
||||
calls: list[tuple[str, Any, bool]] = []
|
||||
|
||||
def register_session(*args: Any, **kwargs: Any) -> None:
|
||||
calls.append(("register", args, threading.get_ident() != loop_thread))
|
||||
|
||||
def reset_connection_cache() -> None:
|
||||
calls.append(("reset", (), threading.get_ident() != loop_thread))
|
||||
|
||||
smb = app_module.settings.OPENBAO.SMB
|
||||
monkeypatch.setattr(smb, "SMB_HOST", "smb.local")
|
||||
monkeypatch.setattr(smb, "SMB_LOGIN", "user")
|
||||
monkeypatch.setattr(smb, "SMB_PASSWORD", "password")
|
||||
monkeypatch.setattr(app_module.smbclient, "register_session", register_session)
|
||||
monkeypatch.setattr(app_module.smbclient, "reset_connection_cache", reset_connection_cache)
|
||||
monkeypatch.setattr(app_module, "_connect_s3", _unavailable_s3)
|
||||
monkeypatch.setattr(app_module, "_create_nats", lambda: None)
|
||||
|
||||
async with app_module.lifespan(app_module.app):
|
||||
assert calls == [("register", ("smb.local", "user", "password"), True)]
|
||||
|
||||
assert calls[-1] == ("reset", (), True)
|
||||
|
||||
|
||||
class _FailingNats(_FakeNats):
|
||||
def __init__(self, events: list[str]) -> None:
|
||||
super().__init__()
|
||||
self.events = events
|
||||
|
||||
async def stop(self) -> None:
|
||||
self.events.append("nats")
|
||||
raise RuntimeError("подставная ошибка остановки NATS")
|
||||
|
||||
|
||||
class _FailingS3Client:
|
||||
def __init__(self, events: list[str]) -> None:
|
||||
self.events = events
|
||||
|
||||
async def close_session(self) -> None:
|
||||
self.events.append("s3")
|
||||
raise RuntimeError("подставная ошибка закрытия S3")
|
||||
|
||||
|
||||
async def test_shutdown_steps_are_independent_and_engine_disposed_last(
|
||||
monkeypatch: pytest.MonkeyPatch, exchange_loops: list[str]
|
||||
):
|
||||
"""Ошибки `nats.stop()` и закрытия S3 не отменяют сброс SMB и `engine.dispose()`; порядок шагов сохраняется."""
|
||||
events: list[str] = []
|
||||
monkeypatch.setattr(app_module, "engine", _FakeEngine(events))
|
||||
monkeypatch.setattr(app_module.settings.OPENBAO.SMB, "SMB_HOST", "smb.local")
|
||||
monkeypatch.setattr(app_module.smbclient, "register_session", lambda *args, **kwargs: None)
|
||||
monkeypatch.setattr(app_module.smbclient, "reset_connection_cache", lambda: events.append("smb"))
|
||||
storage = SimpleNamespace(client=_FailingS3Client(events))
|
||||
|
||||
async def connect_s3() -> SimpleNamespace:
|
||||
return storage
|
||||
|
||||
monkeypatch.setattr(app_module, "_connect_s3", connect_s3)
|
||||
monkeypatch.setattr(app_module, "_create_nats", lambda: _FailingNats(events))
|
||||
records: list[Any] = []
|
||||
handler_id = logger.add(lambda message: records.append(message.record), level="ERROR")
|
||||
try:
|
||||
async with app_module.lifespan(app_module.app):
|
||||
exchange = app_module.app.state.exchange
|
||||
assert exchange is not None
|
||||
finally:
|
||||
logger.remove(handler_id)
|
||||
|
||||
assert all(task.done() for task in exchange.tasks)
|
||||
assert events == ["nats", "s3", "smb", "db"]
|
||||
failed_steps = sorted(r["extra"].get("step") for r in records)
|
||||
assert failed_steps == ["nats", "s3"]
|
||||
|
||||
@ -27,10 +27,11 @@ def test_env_test_is_read(clean_env: pytest.MonkeyPatch) -> None:
|
||||
assert s.AUTH_DEV_ISSUER is True
|
||||
assert s.NATS_ENABLED is False
|
||||
assert s.OPENBAO.MINIO.MINIO_SECURE is False
|
||||
assert s.OPENBAO.SMB.SMB_HOST == "" # SMB выключен: в логе запуска нет трейсбэка SMB
|
||||
|
||||
|
||||
def test_defaults(clean_env: pytest.MonkeyPatch) -> None:
|
||||
"""Значения по умолчанию классов настроек: env-файла нет, заданы только обязательные OPENBAO__*."""
|
||||
"""Значения по умолчанию классов настроек: env-файла нет, заданы только обязательные OPENBAO__* (SMB не нужен)."""
|
||||
required = {
|
||||
"OPENBAO__DATABASE__DATABASE_URL": "postgresql+asyncpg://u:p@localhost:5432/d",
|
||||
"OPENBAO__MINIO__MINIO_URL": "localhost:9000",
|
||||
@ -38,10 +39,6 @@ def test_defaults(clean_env: pytest.MonkeyPatch) -> None:
|
||||
"OPENBAO__MINIO__MINIO_ADMIN_PASSWORD": "password",
|
||||
"OPENBAO__MINIO__MINIO_BUCKET": "bucket",
|
||||
"OPENBAO__NATS__NATS_URL": "nats://localhost:4222",
|
||||
"OPENBAO__SMB__SMB_HOST": "host",
|
||||
"OPENBAO__SMB__SMB_PATH": "path",
|
||||
"OPENBAO__SMB__SMB_LOGIN": "login",
|
||||
"OPENBAO__SMB__SMB_PASSWORD": "password",
|
||||
}
|
||||
for key, value in required.items():
|
||||
clean_env.setenv(key, value)
|
||||
@ -59,6 +56,8 @@ def test_defaults(clean_env: pytest.MonkeyPatch) -> None:
|
||||
assert s.OPENBAO.NATS.NATS_SEED == ""
|
||||
assert s.OPENBAO.NATS.NATS_JWT == ""
|
||||
assert s.OPENBAO.MINIO.MINIO_SECURE is True
|
||||
smb = s.OPENBAO.SMB
|
||||
assert (smb.SMB_HOST, smb.SMB_PATH, smb.SMB_LOGIN, smb.SMB_PASSWORD) == ("", "", "", "")
|
||||
|
||||
|
||||
def test_empty_nats_seed_and_jwt_allowed(clean_env: pytest.MonkeyPatch) -> None:
|
||||
@ -67,3 +66,4 @@ def test_empty_nats_seed_and_jwt_allowed(clean_env: pytest.MonkeyPatch) -> None:
|
||||
assert s.OPENBAO.NATS.NATS_SEED == ""
|
||||
assert s.OPENBAO.NATS.NATS_JWT == ""
|
||||
assert s.NATS_ENABLED is True
|
||||
assert s.OPENBAO.SMB.SMB_HOST == ""
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user