From 479a76f81bc56b315e32e123e2a71ff6138ed391 Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Sun, 4 Oct 2026 03:48:34 +0400 Subject: [PATCH] =?UTF-8?q?test:=20=D1=81=D1=82=D0=B0=D1=80=D1=82=20=D1=81?= =?UTF-8?q?=20=D0=BC=D0=B8=D0=BD=D0=B8=D0=BC=D0=B0=D0=BB=D1=8C=D0=BD=D1=8B?= =?UTF-8?q?=D0=BC=20=D0=BE=D0=BA=D1=80=D1=83=D0=B6=D0=B5=D0=BD=D0=B8=D0=B5?= =?UTF-8?q?=D0=BC=20=D0=B8=20=D1=81=D1=82=D1=80=D0=B0=D0=B6=20=C2=AB=D0=B1?= =?UTF-8?q?=D0=B5=D0=B7=20=D0=91=D0=94=20=D0=B8=20=D1=84=D1=80=D0=BE=D0=BD?= =?UTF-8?q?=D1=82=D0=B0=C2=BB=20(M-8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - test_app: приложение с Settings только из MinIO, адреса NATS и DEBUG стартует, /healthcheck отвечает 200 с uptime, version, nats. - test_layout: в requirements.txt нет asyncpg, SQLAlchemy, alembic, smbprotocol, argon2-cffi, raisa_fastapi_protected_api; нет каталогов web/, api/alembic/, api/src/{db,models,repositories}/. Co-Authored-By: Claude Fable 5.1 --- api/tests/unit/test_app.py | 14 ++++++++++++++ api/tests/unit/test_layout.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 api/tests/unit/test_layout.py diff --git a/api/tests/unit/test_app.py b/api/tests/unit/test_app.py index 48e34c3..77e214e 100644 --- a/api/tests/unit/test_app.py +++ b/api/tests/unit/test_app.py @@ -143,6 +143,20 @@ async def test_nats_disabled_starts_nothing_and_healthcheck_reports_off( assert events == ["s3.close"] +async def test_minimal_environment_starts_and_healthcheck_answers( + patched_app: Any, monkeypatch: pytest.MonkeyPatch, minimal_settings: Callable[..., Any] +) -> None: + """Старт с минимальным окружением: только MinIO, адрес NATS и DEBUG (без seed/jwt, БД и SMB).""" + monkeypatch.setattr(patched_app, "settings", minimal_settings()) + assert patched_app.settings.NATS_ENABLED is True + + async with running_app(patched_app) as client: + response = await client.get("/healthcheck") + + assert response.status_code == 200 # noqa: PLR2004 - HTTP 200 + assert set(response.json()) == {"uptime", "version", "nats"} + + async def test_nats_enabled_subscribes_worker_and_reports_ok( patched_app: Any, monkeypatch: pytest.MonkeyPatch, events: list[str] ) -> None: diff --git a/api/tests/unit/test_layout.py b/api/tests/unit/test_layout.py new file mode 100644 index 0000000..6a60a4b --- /dev/null +++ b/api/tests/unit/test_layout.py @@ -0,0 +1,32 @@ +"""Страж spec «Сервис не зависит от БД и фронта» (DECISION-4): ни зависимостей БД/SMB/шаблонной авторизации, ни +каталогов фронта, миграций, моделей и репозиториев.""" + +import re +from pathlib import Path + +import pytest + +REPO_ROOT = Path(__file__).resolve().parents[3] +REQUIREMENTS = REPO_ROOT / "api" / "requirements.txt" +FORBIDDEN_PACKAGES = ( + "asyncpg", + "sqlalchemy", + "alembic", + "smbprotocol", + "argon2-cffi", + "raisa_fastapi_protected_api", +) +FORBIDDEN_DIRS = ("web", "api/alembic", "api/src/db", "api/src/models", "api/src/repositories") + + +@pytest.mark.parametrize("package", FORBIDDEN_PACKAGES) +def test_requirements_have_no_database_or_template_auth_packages(package: str) -> None: + name = re.sub(r"[-_.]", "[-_.]", package) # имена пакетов сравниваются по PEP 503: -, _ и . равнозначны + pattern = re.compile(rf"^\s*{name}\s*(?:[=<>!~;\[]|$)", re.IGNORECASE) + lines = REQUIREMENTS.read_text(encoding="utf-8").splitlines() + assert not [line for line in lines if pattern.match(line)] + + +@pytest.mark.parametrize("directory", FORBIDDEN_DIRS) +def test_no_frontend_or_database_directories(directory: str) -> None: + assert not (REPO_ROOT / directory).exists()