From 3e58ab4895169d07b629c02099fb6935ce3d8b0c Mon Sep 17 00:00:00 2001 From: Stanislav Roslavtsev Date: Wed, 9 Oct 2024 13:26:57 +0300 Subject: [PATCH 01/11] Typo fix --- aciniformes_backend/receiver.py | 43 +++++++++++++++++++ aciniformes_backend/routes/alert.py | 4 +- aciniformes_backend/routes/fetcher.py | 6 +-- aciniformes_backend/routes/mectric.py | 6 +-- aciniformes_backend/routes/receiver.py | 6 +-- .../{serivce => service}/__init__.py | 0 .../{serivce => service}/alert.py | 2 +- .../{serivce => service}/base.py | 0 .../{serivce => service}/bootstrap.py | 0 .../{serivce => service}/exceptions.py | 0 .../{serivce => service}/fetcher.py | 2 +- .../{serivce => service}/metric.py | 2 +- .../{serivce => service}/receiver.py | 2 +- tests/backend/api/test_alert.py | 2 +- tests/backend/api/test_fetcher.py | 2 +- tests/backend/api/test_metric.py | 2 +- tests/backend/api/test_reciever.py | 2 +- tests/backend/service/test_alert_serivce.py | 6 +-- tests/backend/service/test_fetcher_service.py | 2 +- tests/backend/service/test_metric_service.py | 2 +- 20 files changed, 67 insertions(+), 24 deletions(-) create mode 100644 aciniformes_backend/receiver.py rename aciniformes_backend/{serivce => service}/__init__.py (100%) rename aciniformes_backend/{serivce => service}/alert.py (96%) rename aciniformes_backend/{serivce => service}/base.py (100%) rename aciniformes_backend/{serivce => service}/bootstrap.py (100%) rename aciniformes_backend/{serivce => service}/exceptions.py (100%) rename aciniformes_backend/{serivce => service}/fetcher.py (96%) rename aciniformes_backend/{serivce => service}/metric.py (93%) rename aciniformes_backend/{serivce => service}/receiver.py (96%) diff --git a/aciniformes_backend/receiver.py b/aciniformes_backend/receiver.py new file mode 100644 index 0000000..ed01051 --- /dev/null +++ b/aciniformes_backend/receiver.py @@ -0,0 +1,43 @@ +from typing import Type + +import sqlalchemy as sa + +import aciniformes_backend.models as db_models +import aciniformes_backend.service.exceptions as exc + +from .base import BaseService + + +class PgReceiverService(BaseService): + async def create(self, item: dict) -> int: + q = sa.insert(db_models.Receiver).values(**item).returning(db_models.Receiver) + receiver = self.session.execute(q).scalar() + self.session.flush() + return receiver.id_ + + async def get_by_id(self, id_: int) -> Type[db_models.Receiver]: + q = sa.select(db_models.Receiver).where(db_models.Receiver.id_ == id_) + res = self.session.scalar(q) + if not res: + raise exc.ObjectNotFound(id_) + return res + + async def delete(self, id_: int) -> None: + q = sa.delete(db_models.Receiver).where(db_models.Receiver.id_ == id_) + self.session.execute(q) + self.session.flush() + + async def update(self, id_: int, item: dict) -> Type[db_models.Receiver]: + q = ( + sa.update(db_models.Receiver) + .where(db_models.Receiver.id_ == id_) + .values(**item) + .returning(db_models.Receiver) + ) + if not await self.get_by_id(id_): + raise exc.ObjectNotFound(id_) + res = self.session.execute(q).scalar() + return res + + async def get_all(self) -> list[db_models.BaseModel]: + return list(self.session.scalars(sa.select(db_models.Receiver)).all()) diff --git a/aciniformes_backend/routes/alert.py b/aciniformes_backend/routes/alert.py index 77cda16..dc182fe 100644 --- a/aciniformes_backend/routes/alert.py +++ b/aciniformes_backend/routes/alert.py @@ -8,8 +8,8 @@ from pydantic import BaseModel from starlette import status -from aciniformes_backend.serivce import AlertServiceInterface, alert_service -from aciniformes_backend.serivce import exceptions as exc +from aciniformes_backend.service import AlertServiceInterface, alert_service +from aciniformes_backend.service import exceptions as exc logger = logging.getLogger(__name__) diff --git a/aciniformes_backend/routes/fetcher.py b/aciniformes_backend/routes/fetcher.py index c0fa904..1feb694 100644 --- a/aciniformes_backend/routes/fetcher.py +++ b/aciniformes_backend/routes/fetcher.py @@ -9,9 +9,9 @@ from typing_extensions import Annotated from aciniformes_backend.models.fetcher import FetcherType -from aciniformes_backend.serivce import FetcherServiceInterface -from aciniformes_backend.serivce import exceptions as exc -from aciniformes_backend.serivce import fetcher_service +from aciniformes_backend.service import FetcherServiceInterface +from aciniformes_backend.service import exceptions as exc +from aciniformes_backend.service import fetcher_service logger = logging.getLogger(__name__) diff --git a/aciniformes_backend/routes/mectric.py b/aciniformes_backend/routes/mectric.py index 6469981..13d1e7f 100644 --- a/aciniformes_backend/routes/mectric.py +++ b/aciniformes_backend/routes/mectric.py @@ -4,9 +4,9 @@ from pydantic import BaseModel from starlette import status -from aciniformes_backend.serivce import MetricServiceInterface -from aciniformes_backend.serivce import exceptions as exc -from aciniformes_backend.serivce import metric_service +from aciniformes_backend.service import MetricServiceInterface +from aciniformes_backend.service import exceptions as exc +from aciniformes_backend.service import metric_service class CreateSchema(BaseModel): diff --git a/aciniformes_backend/routes/receiver.py b/aciniformes_backend/routes/receiver.py index 5c08821..2087b6a 100644 --- a/aciniformes_backend/routes/receiver.py +++ b/aciniformes_backend/routes/receiver.py @@ -7,9 +7,9 @@ from pydantic import BaseModel from starlette import status -from aciniformes_backend.serivce import ReceiverServiceInterface -from aciniformes_backend.serivce import exceptions as exc -from aciniformes_backend.serivce import receiver_service +from aciniformes_backend.service import ReceiverServiceInterface +from aciniformes_backend.service import exceptions as exc +from aciniformes_backend.service import receiver_service logger = logging.getLogger(__name__) diff --git a/aciniformes_backend/serivce/__init__.py b/aciniformes_backend/service/__init__.py similarity index 100% rename from aciniformes_backend/serivce/__init__.py rename to aciniformes_backend/service/__init__.py diff --git a/aciniformes_backend/serivce/alert.py b/aciniformes_backend/service/alert.py similarity index 96% rename from aciniformes_backend/serivce/alert.py rename to aciniformes_backend/service/alert.py index e300b5b..e8e9c68 100644 --- a/aciniformes_backend/serivce/alert.py +++ b/aciniformes_backend/service/alert.py @@ -1,7 +1,7 @@ import sqlalchemy as sa import aciniformes_backend.models as db_models -import aciniformes_backend.serivce.exceptions as exc +import aciniformes_backend.service.exceptions as exc from .base import AlertServiceInterface diff --git a/aciniformes_backend/serivce/base.py b/aciniformes_backend/service/base.py similarity index 100% rename from aciniformes_backend/serivce/base.py rename to aciniformes_backend/service/base.py diff --git a/aciniformes_backend/serivce/bootstrap.py b/aciniformes_backend/service/bootstrap.py similarity index 100% rename from aciniformes_backend/serivce/bootstrap.py rename to aciniformes_backend/service/bootstrap.py diff --git a/aciniformes_backend/serivce/exceptions.py b/aciniformes_backend/service/exceptions.py similarity index 100% rename from aciniformes_backend/serivce/exceptions.py rename to aciniformes_backend/service/exceptions.py diff --git a/aciniformes_backend/serivce/fetcher.py b/aciniformes_backend/service/fetcher.py similarity index 96% rename from aciniformes_backend/serivce/fetcher.py rename to aciniformes_backend/service/fetcher.py index fbb1cf6..32e5caf 100644 --- a/aciniformes_backend/serivce/fetcher.py +++ b/aciniformes_backend/service/fetcher.py @@ -1,7 +1,7 @@ import sqlalchemy as sa import aciniformes_backend.models as db_models -import aciniformes_backend.serivce.exceptions as exc +import aciniformes_backend.service.exceptions as exc from .base import FetcherServiceInterface diff --git a/aciniformes_backend/serivce/metric.py b/aciniformes_backend/service/metric.py similarity index 93% rename from aciniformes_backend/serivce/metric.py rename to aciniformes_backend/service/metric.py index 95527b8..3551a72 100644 --- a/aciniformes_backend/serivce/metric.py +++ b/aciniformes_backend/service/metric.py @@ -1,7 +1,7 @@ import sqlalchemy as sa import aciniformes_backend.models as db_models -import aciniformes_backend.serivce.exceptions as exc +import aciniformes_backend.service.exceptions as exc from .base import MetricServiceInterface diff --git a/aciniformes_backend/serivce/receiver.py b/aciniformes_backend/service/receiver.py similarity index 96% rename from aciniformes_backend/serivce/receiver.py rename to aciniformes_backend/service/receiver.py index ac52723..b1250cb 100644 --- a/aciniformes_backend/serivce/receiver.py +++ b/aciniformes_backend/service/receiver.py @@ -3,7 +3,7 @@ import sqlalchemy as sa import aciniformes_backend.models as db_models -import aciniformes_backend.serivce.exceptions as exc +import aciniformes_backend.service.exceptions as exc from .base import ReceiverServiceInterface diff --git a/tests/backend/api/test_alert.py b/tests/backend/api/test_alert.py index ece8224..a88f9a3 100644 --- a/tests/backend/api/test_alert.py +++ b/tests/backend/api/test_alert.py @@ -4,7 +4,7 @@ import pytest_asyncio from starlette import status -from aciniformes_backend.serivce.alert import PgAlertService +from aciniformes_backend.service.alert import PgAlertService from aciniformes_backend.settings import get_settings diff --git a/tests/backend/api/test_fetcher.py b/tests/backend/api/test_fetcher.py index 07084c3..23f2d9e 100644 --- a/tests/backend/api/test_fetcher.py +++ b/tests/backend/api/test_fetcher.py @@ -5,7 +5,7 @@ import pytest_asyncio from starlette import status -from aciniformes_backend.serivce.fetcher import PgFetcherService +from aciniformes_backend.service.fetcher import PgFetcherService fetcher = { diff --git a/tests/backend/api/test_metric.py b/tests/backend/api/test_metric.py index f47d9d1..b8f16e4 100644 --- a/tests/backend/api/test_metric.py +++ b/tests/backend/api/test_metric.py @@ -2,7 +2,7 @@ import pytest_asyncio from starlette import status -from aciniformes_backend.serivce.metric import PgMetricService +from aciniformes_backend.service.metric import PgMetricService metric = {"name": "string", "ok": True, "time_delta": 0} diff --git a/tests/backend/api/test_reciever.py b/tests/backend/api/test_reciever.py index 28efc39..d9fbae3 100644 --- a/tests/backend/api/test_reciever.py +++ b/tests/backend/api/test_reciever.py @@ -4,7 +4,7 @@ import pytest_asyncio from starlette import status -from aciniformes_backend.serivce.receiver import PgReceiverService +from aciniformes_backend.service.receiver import PgReceiverService receiver = {"url": "https://google.com", "method": "post", "receiver_body": {}} diff --git a/tests/backend/service/test_alert_serivce.py b/tests/backend/service/test_alert_serivce.py index 4bd28a7..911b0c8 100644 --- a/tests/backend/service/test_alert_serivce.py +++ b/tests/backend/service/test_alert_serivce.py @@ -1,12 +1,12 @@ import pytest import sqlalchemy -import aciniformes_backend.serivce.exceptions as exc +import aciniformes_backend.service.exceptions as exc from aciniformes_backend.models import Alert, Receiver from aciniformes_backend.routes.alert import CreateSchema as AlertCreateSchema from aciniformes_backend.routes.receiver import CreateSchema as ReceiverCreateSchema -from aciniformes_backend.serivce.alert import PgAlertService -from aciniformes_backend.serivce.receiver import PgReceiverService +from aciniformes_backend.service.alert import PgAlertService +from aciniformes_backend.service.receiver import PgReceiverService @pytest.fixture diff --git a/tests/backend/service/test_fetcher_service.py b/tests/backend/service/test_fetcher_service.py index 0d968b4..b5c49fa 100644 --- a/tests/backend/service/test_fetcher_service.py +++ b/tests/backend/service/test_fetcher_service.py @@ -3,7 +3,7 @@ from aciniformes_backend.models import Fetcher from aciniformes_backend.routes.fetcher import CreateSchema as FetcherCreateSchema -from aciniformes_backend.serivce.fetcher import PgFetcherService +from aciniformes_backend.service.fetcher import PgFetcherService @pytest.fixture diff --git a/tests/backend/service/test_metric_service.py b/tests/backend/service/test_metric_service.py index c9a37ee..60a3fbe 100644 --- a/tests/backend/service/test_metric_service.py +++ b/tests/backend/service/test_metric_service.py @@ -3,7 +3,7 @@ from aciniformes_backend.models import Metric from aciniformes_backend.routes.mectric import CreateSchema as MetricCreateSchema -from aciniformes_backend.serivce.metric import PgMetricService +from aciniformes_backend.service.metric import PgMetricService @pytest.fixture From 696c9636345409cf048fe59e9901797b33596b5a Mon Sep 17 00:00:00 2001 From: Stanislav Roslavtsev Date: Wed, 9 Oct 2024 13:29:14 +0300 Subject: [PATCH 02/11] delete strange file --- aciniformes_backend/receiver.py | 43 --------------------------------- 1 file changed, 43 deletions(-) delete mode 100644 aciniformes_backend/receiver.py diff --git a/aciniformes_backend/receiver.py b/aciniformes_backend/receiver.py deleted file mode 100644 index ed01051..0000000 --- a/aciniformes_backend/receiver.py +++ /dev/null @@ -1,43 +0,0 @@ -from typing import Type - -import sqlalchemy as sa - -import aciniformes_backend.models as db_models -import aciniformes_backend.service.exceptions as exc - -from .base import BaseService - - -class PgReceiverService(BaseService): - async def create(self, item: dict) -> int: - q = sa.insert(db_models.Receiver).values(**item).returning(db_models.Receiver) - receiver = self.session.execute(q).scalar() - self.session.flush() - return receiver.id_ - - async def get_by_id(self, id_: int) -> Type[db_models.Receiver]: - q = sa.select(db_models.Receiver).where(db_models.Receiver.id_ == id_) - res = self.session.scalar(q) - if not res: - raise exc.ObjectNotFound(id_) - return res - - async def delete(self, id_: int) -> None: - q = sa.delete(db_models.Receiver).where(db_models.Receiver.id_ == id_) - self.session.execute(q) - self.session.flush() - - async def update(self, id_: int, item: dict) -> Type[db_models.Receiver]: - q = ( - sa.update(db_models.Receiver) - .where(db_models.Receiver.id_ == id_) - .values(**item) - .returning(db_models.Receiver) - ) - if not await self.get_by_id(id_): - raise exc.ObjectNotFound(id_) - res = self.session.execute(q).scalar() - return res - - async def get_all(self) -> list[db_models.BaseModel]: - return list(self.session.scalars(sa.select(db_models.Receiver)).all()) From 8e13f8fd7c3867e1ab3a97a257d369099f3bbcbd Mon Sep 17 00:00:00 2001 From: Stanislav Roslavtsev Date: Wed, 9 Oct 2024 13:30:53 +0300 Subject: [PATCH 03/11] Remove alerts --- aciniformes_backend/routes/alert.py | 96 ------------------------- aciniformes_backend/service/__init__.py | 3 +- aciniformes_backend/service/alert.py | 36 ---------- aciniformes_backend/service/base.py | 15 ---- 4 files changed, 1 insertion(+), 149 deletions(-) delete mode 100644 aciniformes_backend/routes/alert.py delete mode 100644 aciniformes_backend/service/alert.py diff --git a/aciniformes_backend/routes/alert.py b/aciniformes_backend/routes/alert.py deleted file mode 100644 index dc182fe..0000000 --- a/aciniformes_backend/routes/alert.py +++ /dev/null @@ -1,96 +0,0 @@ -from __future__ import annotations - -import logging - -from auth_lib.fastapi import UnionAuth -from fastapi import APIRouter, Depends -from fastapi.exceptions import HTTPException -from pydantic import BaseModel -from starlette import status - -from aciniformes_backend.service import AlertServiceInterface, alert_service -from aciniformes_backend.service import exceptions as exc - - -logger = logging.getLogger(__name__) - - -class CreateSchema(BaseModel): - data: dict[str, str | list | dict | bool | int | float] - filter: str - - -class PostResponseSchema(CreateSchema): - id: int | None = None - - -class UpdateSchema(BaseModel): - data: dict[str, str | list | dict] | None = None - filter: str | None = None - - -class GetSchema(BaseModel): - id: int - - -router = APIRouter() - - -@router.post("") -async def create( - create_schema: CreateSchema, - alert: AlertServiceInterface = Depends(alert_service), - _: dict[str] = Depends(UnionAuth(['pinger.alert.create'])), -) -> PostResponseSchema: - """Создание уведомления.""" - id_ = await alert.create(create_schema.model_dump(exclude_unset=True)) - return PostResponseSchema(**create_schema.model_dump(), id=id_) - - -@router.get("") -async def get_all( - alert: AlertServiceInterface = Depends(alert_service), - _: dict[str] = Depends(UnionAuth(['pinger.alert.read'])), -): - """Возвращает все уведомления.""" - res = await alert.get_all() - return res - - -@router.get("/{id}") -async def get( - id: int, - alert: AlertServiceInterface = Depends(alert_service), - _: dict[str] = Depends(UnionAuth(['pinger.alert.read'])), -): - """Возвращает одно уведомление.""" - try: - res = await alert.get_by_id(id) - except exc.ObjectNotFound: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) - return res - - -@router.patch("/{id}") -async def update( - id: int, - update_schema: UpdateSchema, - alert: AlertServiceInterface = Depends(alert_service), - _: dict[str] = Depends(UnionAuth(['pinger.alert.update'])), -): - """Обновление уведомления по id.""" - try: - res = await alert.update(id, update_schema.model_dump(exclude_unset=True)) - except exc.ObjectNotFound: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) - return res - - -@router.delete("/{id}") -async def delete( - id: int, - alert: AlertServiceInterface = Depends(alert_service), - _: dict[str] = Depends(UnionAuth(['pinger.alert.delete'])), -): - """Удаление уведомления по id.""" - await alert.delete(id) diff --git a/aciniformes_backend/service/__init__.py b/aciniformes_backend/service/__init__.py index 547f6a6..2add4c4 100644 --- a/aciniformes_backend/service/__init__.py +++ b/aciniformes_backend/service/__init__.py @@ -1,9 +1,8 @@ -from .base import AlertServiceInterface, FetcherServiceInterface, MetricServiceInterface, ReceiverServiceInterface +from .base import FetcherServiceInterface, MetricServiceInterface, ReceiverServiceInterface from .bootstrap import alert_service, fetcher_service, metric_service, receiver_service __all__ = [ - "AlertServiceInterface", "FetcherServiceInterface", "MetricServiceInterface", "ReceiverServiceInterface", diff --git a/aciniformes_backend/service/alert.py b/aciniformes_backend/service/alert.py deleted file mode 100644 index e8e9c68..0000000 --- a/aciniformes_backend/service/alert.py +++ /dev/null @@ -1,36 +0,0 @@ -import sqlalchemy as sa - -import aciniformes_backend.models as db_models -import aciniformes_backend.service.exceptions as exc - -from .base import AlertServiceInterface - - -class PgAlertService(AlertServiceInterface): - async def create(self, item: dict) -> int: - q = sa.insert(db_models.Alert).values(**item).returning(db_models.Alert) - alert = self.session.execute(q).scalar() - self.session.flush() - return alert.id_ - - async def get_by_id(self, id_: int) -> db_models.Alert: - q = sa.select(db_models.Alert).where(db_models.Alert.id_ == id_) - res = self.session.execute(q).scalar() - if not res: - raise exc.ObjectNotFound(id_) - return res - - async def delete(self, id_: int) -> None: - q = sa.delete(db_models.Alert).where(db_models.Alert.id_ == id_) - self.session.execute(q) - self.session.flush() - - async def update(self, id_: int, item: dict) -> db_models.Alert: - q = sa.update(db_models.Alert).where(db_models.Alert.id_ == id_).values(**item).returning(db_models.Alert) - if not await self.get_by_id(id_): - raise exc.ObjectNotFound(id_) - res = self.session.execute(q).scalar() - return res - - async def get_all(self) -> list[db_models.BaseModel]: - return list(self.session.scalars(sa.select(db_models.Alert)).all()) diff --git a/aciniformes_backend/service/base.py b/aciniformes_backend/service/base.py index b353a27..3ba337d 100644 --- a/aciniformes_backend/service/base.py +++ b/aciniformes_backend/service/base.py @@ -17,21 +17,6 @@ async def get_all(self) -> list[db_models.BaseModel]: async def create(self, item: dict) -> int: raise NotImplementedError - -class AlertServiceInterface(BaseService, metaclass=ABCMeta): - @abstractmethod - async def get_by_id(self, id_: int) -> db_models.Alert: - raise NotImplementedError - - @abstractmethod - async def delete(self, id_: int) -> None: - raise NotImplementedError - - @abstractmethod - async def update(self, id_: int, item: dict) -> db_models.Alert: - raise NotImplementedError - - class ReceiverServiceInterface(BaseService, metaclass=ABCMeta): @abstractmethod async def get_by_id(self, id_: int) -> db_models.Receiver: From ca4b10cb9406506455401765bb9ee122bc30204d Mon Sep 17 00:00:00 2001 From: Stanislav Roslavtsev Date: Wed, 9 Oct 2024 13:31:46 +0300 Subject: [PATCH 04/11] Remove alert tests --- tests/backend/api/test_alert.py | 95 ---------------- tests/backend/service/test_alert_serivce.py | 119 -------------------- 2 files changed, 214 deletions(-) delete mode 100644 tests/backend/api/test_alert.py delete mode 100644 tests/backend/service/test_alert_serivce.py diff --git a/tests/backend/api/test_alert.py b/tests/backend/api/test_alert.py deleted file mode 100644 index a88f9a3..0000000 --- a/tests/backend/api/test_alert.py +++ /dev/null @@ -1,95 +0,0 @@ -import json - -import pytest -import pytest_asyncio -from starlette import status - -from aciniformes_backend.service.alert import PgAlertService -from aciniformes_backend.settings import get_settings - - -settings = get_settings() - - -alert = { - "data": {"type": "string", "name": "string"}, - "filter": "string", -} - - -@pytest_asyncio.fixture -async def this_alert(dbsession): - global alert - _alert = await PgAlertService(dbsession).create(item=alert) - yield _alert - - -@pytest.mark.authenticated("pinger.alert.create") -def test_post_success(crud_client): - body = { - "data": {"type": "string", "name": "string"}, - "filter": "string", - } - res = crud_client.post("/alert", json=body) - res_body = res.json() - assert res.status_code == status.HTTP_200_OK - assert res_body["data"] == body["data"] - assert res_body["filter"] == body["filter"] - - -@pytest.mark.authenticated("pinger.alert.read") -def test_get_by_id_success(crud_client, this_alert): - res = crud_client.get(f"/alert/{this_alert}") - assert res.status_code == status.HTTP_200_OK - res_body = res.json() - assert res_body["data"] == alert["data"] - assert res_body["filter"] == alert["filter"] - - -@pytest.mark.authenticated("pinger.alert.read", "pinger.alert.delete") -def test_delete_by_id_success(crud_client, this_alert): - res = crud_client.delete(f"/alert/{this_alert}") - assert res.status_code == status.HTTP_200_OK - get = crud_client.get(f"/alert/{this_alert}") - assert get.status_code == status.HTTP_404_NOT_FOUND - - -@pytest.mark.authenticated("pinger.alert.read") -def test_get_success(crud_client, this_alert): - res = crud_client.get("/alert") - assert res.status_code == status.HTTP_200_OK - res_body = res.json() - assert len(res_body) - get = crud_client.get(f"/alert/{this_alert}") - assert get.json() in res_body - - -@pytest.mark.authenticated("pinger.alert.read", "pinger.alert.update") -def test_patch_by_id_success(crud_client, this_alert): - body = { - "data": {"type": "string", "name": "string"}, - "filter": "string", - } - res = crud_client.patch(f"/alert/{this_alert}", data=json.dumps(body)) - assert res.status_code == status.HTTP_200_OK - res_body = res.json() - assert res_body["data"] == body["data"] - get = crud_client.get(f"/alert/{this_alert}") - assert get.status_code == status.HTTP_200_OK - assert get.json() == res_body - - -@pytest.mark.authenticated("pinger.alert.read") -def test_get_by_id_not_found(crud_client, this_alert): - res = crud_client.get(f"/alert/{this_alert+2}") - assert res.status_code == status.HTTP_404_NOT_FOUND - - -@pytest.mark.authenticated("pinger.alert.read", "pinger.alert.update") -def test_patch_by_id_not_found(crud_client, this_alert): - body = { - "data": {"type": "string", "name": "string"}, - "filter": "string", - } - res = crud_client.patch(f"/alert/{888}", data=json.dumps(body)) - assert res.status_code == status.HTTP_404_NOT_FOUND diff --git a/tests/backend/service/test_alert_serivce.py b/tests/backend/service/test_alert_serivce.py deleted file mode 100644 index 911b0c8..0000000 --- a/tests/backend/service/test_alert_serivce.py +++ /dev/null @@ -1,119 +0,0 @@ -import pytest -import sqlalchemy - -import aciniformes_backend.service.exceptions as exc -from aciniformes_backend.models import Alert, Receiver -from aciniformes_backend.routes.alert import CreateSchema as AlertCreateSchema -from aciniformes_backend.routes.receiver import CreateSchema as ReceiverCreateSchema -from aciniformes_backend.service.alert import PgAlertService -from aciniformes_backend.service.receiver import PgReceiverService - - -@pytest.fixture -def receiver_schema(): - body = {"url": "https://google.com", "method": "post", "receiver_body": {}} - schema = ReceiverCreateSchema(**body) - return schema - - -@pytest.fixture -def db_receiver(dbsession, receiver_schema): - q = sqlalchemy.insert(Receiver).values(**receiver_schema.model_dump(exclude_unset=True)).returning(Receiver) - receiver = dbsession.execute(q).scalar() - dbsession.flush() - yield receiver - if dbsession.get(Receiver, receiver.id_): - dbsession.delete(receiver) - dbsession.flush() - - -@pytest.fixture -def alert_schema(receiver_schema): - body = { - "data": {"type": "string", "name": "string"}, - "filter": "string", - } - schema = AlertCreateSchema(**body) - return schema - - -@pytest.fixture -def db_alert(db_receiver, dbsession, alert_schema): - q = sqlalchemy.insert(Alert).values(**alert_schema.model_dump(exclude_unset=True)).returning(Alert) - alert = dbsession.execute(q).scalar() - dbsession.flush() - yield alert - if dbsession.get(Alert, alert.id_): - dbsession.delete(alert) - dbsession.flush() - - -class TestReceiverService: - @pytest.mark.asyncio - async def test_create(self, receiver_schema, dbsession): - res = await PgReceiverService(dbsession).create(item=receiver_schema.model_dump()) - assert res is not None - assert type(res) == int - q = dbsession.query(Receiver).filter(Receiver.id_ == res).one_or_none() - assert q is not None - - @pytest.mark.asyncio - async def test_get_all(self, db_receiver, dbsession): - res = await PgReceiverService(dbsession).get_all() - assert len(res) - assert type(res) is list - assert type(res[0]) is Receiver - - @pytest.mark.asyncio - async def test_get_by_id(self, db_receiver, dbsession): - res = await PgReceiverService(dbsession).get_by_id(db_receiver.id_) - assert res is not None - assert res.url == db_receiver.url - with pytest.raises(exc.ObjectNotFound): - await PgReceiverService(dbsession).get_by_id(db_receiver.id_ + 1000) - - @pytest.mark.asyncio - async def test_delete(self, db_receiver, dbsession): - await PgReceiverService(dbsession).delete(db_receiver.id_) - - @pytest.mark.asyncio - async def test_update(self, db_receiver, dbsession): - res = await PgReceiverService(dbsession).update( - db_receiver.id_, {"url": "Alex", "method": "post", "receiver_body": {}} - ) - assert res.url == "Alex" - assert res.receiver_body == {} - - -class TestAlertService: - @pytest.mark.asyncio - async def test_create(self, alert_schema, db_receiver, dbsession): - res = await PgAlertService(dbsession).create( - alert_schema.model_dump(exclude_unset=True), - ) - assert type(res) == int - - @pytest.mark.asyncio - async def test_get_all(self, db_alert, dbsession): - res = await PgAlertService(dbsession).get_all() - assert len(res) - assert type(res) is list - assert type(res[0]) is Alert - - @pytest.mark.asyncio - async def test_get_by_id(self, dbsession, db_alert): - res = await PgAlertService(dbsession).get_by_id(db_alert.id_) - assert res is not None - assert res.data == db_alert.data - assert res.filter == db_alert.filter - with pytest.raises(exc.ObjectNotFound): - await PgAlertService(dbsession).get_by_id(db_alert.id_ + 1000) - - @pytest.mark.asyncio - async def test_delete(self, dbsession, db_alert): - await PgAlertService(dbsession).delete(db_alert.id_) - - @pytest.mark.asyncio - async def test_update(self, dbsession, db_alert): - res = await PgAlertService(dbsession).update(db_alert.id_, {"data": {"type": "stig", "name": "stig"}}) - assert res.data == {"type": "stig", "name": "stig"} From b947ae93cd856cc683420e338992098c1cbc03a7 Mon Sep 17 00:00:00 2001 From: Stanislav Roslavtsev Date: Wed, 9 Oct 2024 14:48:44 +0300 Subject: [PATCH 05/11] Remove all services --- .../{service => routes}/exceptions.py | 0 aciniformes_backend/routes/fetcher.py | 38 +++++++------- aciniformes_backend/routes/mectric.py | 27 +++++----- aciniformes_backend/routes/receiver.py | 44 +++++++++------- aciniformes_backend/service/__init__.py | 14 ----- aciniformes_backend/service/base.py | 51 ------------------- aciniformes_backend/service/bootstrap.py | 22 -------- aciniformes_backend/service/fetcher.py | 36 ------------- aciniformes_backend/service/metric.py | 24 --------- aciniformes_backend/service/receiver.py | 43 ---------------- tests/backend/api/test_fetcher.py | 14 +++-- tests/backend/api/test_metric.py | 14 +++-- tests/backend/api/test_reciever.py | 18 +++++-- 13 files changed, 97 insertions(+), 248 deletions(-) rename aciniformes_backend/{service => routes}/exceptions.py (100%) delete mode 100644 aciniformes_backend/service/__init__.py delete mode 100644 aciniformes_backend/service/base.py delete mode 100644 aciniformes_backend/service/bootstrap.py delete mode 100644 aciniformes_backend/service/fetcher.py delete mode 100644 aciniformes_backend/service/metric.py delete mode 100644 aciniformes_backend/service/receiver.py diff --git a/aciniformes_backend/service/exceptions.py b/aciniformes_backend/routes/exceptions.py similarity index 100% rename from aciniformes_backend/service/exceptions.py rename to aciniformes_backend/routes/exceptions.py diff --git a/aciniformes_backend/routes/fetcher.py b/aciniformes_backend/routes/fetcher.py index 1feb694..2a287d1 100644 --- a/aciniformes_backend/routes/fetcher.py +++ b/aciniformes_backend/routes/fetcher.py @@ -7,11 +7,11 @@ from pydantic.functional_serializers import PlainSerializer from starlette import status from typing_extensions import Annotated - +import sqlalchemy as sa +import aciniformes_backend.models as db_models from aciniformes_backend.models.fetcher import FetcherType -from aciniformes_backend.service import FetcherServiceInterface -from aciniformes_backend.service import exceptions as exc -from aciniformes_backend.service import fetcher_service +from fastapi_sqlalchemy import db +from aciniformes_backend.routes import exceptions as exc logger = logging.getLogger(__name__) @@ -45,52 +45,55 @@ class GetSchema(BaseModel): @router.post("", response_model=ResponsePostSchema) async def create( create_schema: CreateSchema, - fetcher: FetcherServiceInterface = Depends(fetcher_service), _: dict[str] = Depends(UnionAuth(['pinger.fetcher.create'])), ): """ Создает новый сборщик метрик. """ - id_ = await fetcher.create(create_schema.model_dump()) - return ResponsePostSchema(**create_schema.model_dump(), id=id_) + q = sa.insert(db_models.Fetcher).values(**create_schema.model_dump()).returning(db_models.Fetcher) + fetcher = db.session.scalar(q) + db.session.flush() + return ResponsePostSchema(**create_schema.model_dump(), id=fetcher.id_) @router.get("") async def get_all( - fetcher: FetcherServiceInterface = Depends(fetcher_service), _: dict[str] = Depends(UnionAuth(['pinger.fetcher.read'])), ): """ Возвращает все сборщики метрик. """ - res = await fetcher.get_all() - return res + return list(db.session.scalars(sa.select(db_models.Fetcher)).all()) @router.get("/{id}") async def get( id: int, - fetcher: FetcherServiceInterface = Depends(fetcher_service), _: dict[str] = Depends(UnionAuth(['pinger.fetcher.read'])), ): """Получение одного сборщика метрик по id""" try: - res = await fetcher.get_by_id(id) + q = sa.select(db_models.Fetcher).where(db_models.Fetcher.id_ == id) + res = db.session.scalar(q) + if not res: + raise exc.ObjectNotFound(id) + return res except exc.ObjectNotFound: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) - return res @router.patch("/{id}") async def update( id: int, update_schema: UpdateSchema, - fetcher: FetcherServiceInterface = Depends(fetcher_service), _: dict[str] = Depends(UnionAuth(['pinger.fetcher.update'])), ): """Обновление одного сборщика метрик по id""" try: - res = await fetcher.update(id, update_schema.model_dump(exclude_unset=True)) + q = sa.update(db_models.Fetcher).where(db_models.Fetcher.id_ == id).values(**update_schema).returning(db_models.Fetcher) + if not await db.get_by_id(id): + raise exc.ObjectNotFound(id) + res = db.session.execute(q).scalar() except exc.ObjectNotFound: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) return res @@ -99,8 +102,9 @@ async def update( @router.delete("/{id}") async def delete( id: int, - fetcher: FetcherServiceInterface = Depends(fetcher_service), _: dict[str] = Depends(UnionAuth(['pinger.fetcher.delete'])), ): """Удаление одного сборщика метрик по id""" - await fetcher.delete(id) + q = sa.delete(db_models.Fetcher).where(db_models.Fetcher.id_ == id) + db.session.execute(q) + db.session.flush() diff --git a/aciniformes_backend/routes/mectric.py b/aciniformes_backend/routes/mectric.py index 13d1e7f..4e7037a 100644 --- a/aciniformes_backend/routes/mectric.py +++ b/aciniformes_backend/routes/mectric.py @@ -3,10 +3,10 @@ from fastapi.exceptions import HTTPException from pydantic import BaseModel from starlette import status - -from aciniformes_backend.service import MetricServiceInterface -from aciniformes_backend.service import exceptions as exc -from aciniformes_backend.service import metric_service +from fastapi_sqlalchemy import db +import sqlalchemy as sa +import aciniformes_backend.models as db_models +from aciniformes_backend.routes import exceptions as exc class CreateSchema(BaseModel): @@ -32,33 +32,34 @@ class GetSchema(BaseModel): @router.post("", response_model=ResponsePostSchema) async def create( metric_schema: CreateSchema, - metric: MetricServiceInterface = Depends(metric_service), _: dict[str] = Depends(UnionAuth(['pinger.metric.create'])), ): """Создание метрики.""" - id_ = await metric.create(metric_schema.model_dump()) - return ResponsePostSchema(**metric_schema.model_dump(), id=id_) + q = sa.insert(db_models.Metric).values(**metric_schema.model_dump()).returning(db_models.Metric) + metric = db.session.scalar(q) + db.session.flush() + return ResponsePostSchema(**metric_schema.model_dump(), id=metric.id_) @router.get("") async def get_all( - metric: MetricServiceInterface = Depends(metric_service), _: dict[str] = Depends(UnionAuth(['pinger.metric.read'])), ): """Получение всех метрик.""" - res = await metric.get_all() - return res + return list(db.session.scalars(sa.select(db_models.Fetcher)).all()) @router.get("/{id}") async def get( id: int, - metric: MetricServiceInterface = Depends(metric_service), _: dict[str] = Depends(UnionAuth(['pinger.metric.read'])), ): """Получение одной метрики по id.""" try: - res = await metric.get_by_id(id) + q = sa.select(db_models.Fetcher).where(db_models.Fetcher.id_ == id) + res = db.session.scalar(q) + if not res: + raise exc.ObjectNotFound(id) + return res except exc.ObjectNotFound: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) - return res diff --git a/aciniformes_backend/routes/receiver.py b/aciniformes_backend/routes/receiver.py index 2087b6a..db39922 100644 --- a/aciniformes_backend/routes/receiver.py +++ b/aciniformes_backend/routes/receiver.py @@ -6,10 +6,10 @@ from fastapi.exceptions import HTTPException from pydantic import BaseModel from starlette import status - -from aciniformes_backend.service import ReceiverServiceInterface -from aciniformes_backend.service import exceptions as exc -from aciniformes_backend.service import receiver_service +from aciniformes_backend.routes import exceptions as exc +import aciniformes_backend.models as db_models +from fastapi_sqlalchemy import db +import sqlalchemy as sa logger = logging.getLogger(__name__) @@ -50,34 +50,34 @@ class GetSchema(BaseModel): @router.post("", response_model=PostResponseSchema) async def create( create_schema: CreateSchema, - receiver: ReceiverServiceInterface = Depends(receiver_service), _: dict[str] = Depends(UnionAuth(['pinger.receiver.create'])), ): """Создание получателя уведомлений.""" - id_ = await receiver.create(create_schema.model_dump()) - return PostResponseSchema(**create_schema.model_dump(), id=id_) + q = sa.insert(db_models.Receiver).values(**create_schema.model_dump()).returning(db_models.Receiver) + receiver = db.session.execute(q).scalar() + db.session.flush() + return PostResponseSchema(**create_schema.model_dump(), id=receiver.id_) @router.get("") async def get_all( - receiver: ReceiverServiceInterface = Depends(receiver_service), _: dict[str] = Depends(UnionAuth(['pinger.receiver.read'])), ): """Получить всех получателей уведомлений.""" - res = await receiver.get_all() - return res + return list(db.session.scalars(sa.select(db_models.Receiver)).all()) @router.get("/{id}") async def get( id: int, - receiver: ReceiverServiceInterface = Depends(receiver_service), _: dict[str] = Depends(UnionAuth(['pinger.receiver.read'])), ): """Получение получателя уведомлений.""" try: - res = await receiver.get_by_id(id) - return res + q = sa.select(db_models.Receiver).where(db_models.Receiver.id_ == id) + res = db.session.scalar(q) + if not res: + raise exc.ObjectNotFound(id) except exc.ObjectNotFound: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) @@ -86,12 +86,21 @@ async def get( async def update( id: int, update_schema: UpdateSchema, - receiver: ReceiverServiceInterface = Depends(receiver_service), _: dict[str] = Depends(UnionAuth(['pinger.receiver.update'])), ): """Обновление получателя уведомлений по id.""" try: - res = await receiver.update(id, update_schema.model_dump(exclude_unset=True)) + q = sa.select(db_models.Receiver).where(db_models.Receiver.id_ == id) + res = db.session.scalar(q) + if not res: + raise exc.ObjectNotFound(id) + q = ( + sa.update(db_models.Receiver) + .where(db_models.Receiver.id_ == id) + .values(**update_schema.model_dump()) + .returning(db_models.Receiver) + ) + res = db.session.execute(q).scalar() except exc.ObjectNotFound: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) return res @@ -100,8 +109,9 @@ async def update( @router.delete("/{id}") async def delete( id: int, - receiver: ReceiverServiceInterface = Depends(receiver_service), _: dict[str] = Depends(UnionAuth(['pinger.receiver.delete'])), ): """Удаление получателя уведомлений по id.""" - await receiver.delete(id) + q = sa.delete(db_models.Receiver).where(db_models.Receiver.id_ == id) + db.session.execute(q) + db.session.flush() diff --git a/aciniformes_backend/service/__init__.py b/aciniformes_backend/service/__init__.py deleted file mode 100644 index 2add4c4..0000000 --- a/aciniformes_backend/service/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -from .base import FetcherServiceInterface, MetricServiceInterface, ReceiverServiceInterface -from .bootstrap import alert_service, fetcher_service, metric_service, receiver_service - - -__all__ = [ - "FetcherServiceInterface", - "MetricServiceInterface", - "ReceiverServiceInterface", - "metric_service", - "receiver_service", - "alert_service", - "fetcher_service", - "exceptions", -] diff --git a/aciniformes_backend/service/base.py b/aciniformes_backend/service/base.py deleted file mode 100644 index 3ba337d..0000000 --- a/aciniformes_backend/service/base.py +++ /dev/null @@ -1,51 +0,0 @@ -from abc import ABCMeta, abstractmethod - -import sqlalchemy.orm - -import aciniformes_backend.models as db_models - - -class BaseService(metaclass=ABCMeta): - def __init__(self, session: sqlalchemy.orm.Session | None): - self.session = session - - @abstractmethod - async def get_all(self) -> list[db_models.BaseModel]: - raise NotImplementedError - - @abstractmethod - async def create(self, item: dict) -> int: - raise NotImplementedError - -class ReceiverServiceInterface(BaseService, metaclass=ABCMeta): - @abstractmethod - async def get_by_id(self, id_: int) -> db_models.Receiver: - raise NotImplementedError - - @abstractmethod - async def delete(self, id_: int) -> None: - raise NotImplementedError - - @abstractmethod - async def update(self, id_: int, item: dict) -> db_models.Receiver: - raise NotImplementedError - - -class FetcherServiceInterface(BaseService, metaclass=ABCMeta): - @abstractmethod - async def get_by_id(self, id_: int) -> db_models.Fetcher: - raise NotImplementedError - - @abstractmethod - async def delete(self, id_: int) -> None: - raise NotImplementedError - - @abstractmethod - async def update(self, id_: int, item: dict) -> db_models.Fetcher: - raise NotImplementedError - - -class MetricServiceInterface(BaseService, metaclass=ABCMeta): - @abstractmethod - async def get_by_id(self, id_: int) -> db_models.Metric: - raise NotImplementedError diff --git a/aciniformes_backend/service/bootstrap.py b/aciniformes_backend/service/bootstrap.py deleted file mode 100644 index 7d1febe..0000000 --- a/aciniformes_backend/service/bootstrap.py +++ /dev/null @@ -1,22 +0,0 @@ -from fastapi_sqlalchemy import db - -from .alert import PgAlertService -from .fetcher import PgFetcherService -from .metric import PgMetricService -from .receiver import PgReceiverService - - -def metric_service(): - return PgMetricService(db.session) - - -def alert_service(): - return PgAlertService(db.session) - - -def receiver_service(): - return PgReceiverService(db.session) - - -def fetcher_service(): - return PgFetcherService(db.session) diff --git a/aciniformes_backend/service/fetcher.py b/aciniformes_backend/service/fetcher.py deleted file mode 100644 index 32e5caf..0000000 --- a/aciniformes_backend/service/fetcher.py +++ /dev/null @@ -1,36 +0,0 @@ -import sqlalchemy as sa - -import aciniformes_backend.models as db_models -import aciniformes_backend.service.exceptions as exc - -from .base import FetcherServiceInterface - - -class PgFetcherService(FetcherServiceInterface): - async def create(self, item: dict) -> int: - q = sa.insert(db_models.Fetcher).values(**item).returning(db_models.Fetcher) - fetcher = self.session.scalar(q) - self.session.flush() - return fetcher.id_ - - async def get_by_id(self, id_: int) -> db_models.Fetcher: - q = sa.select(db_models.Fetcher).where(db_models.Fetcher.id_ == id_) - res = self.session.scalar(q) - if not res: - raise exc.ObjectNotFound(id_) - return res - - async def delete(self, id_: int) -> None: - q = sa.delete(db_models.Fetcher).where(db_models.Fetcher.id_ == id_) - self.session.execute(q) - self.session.flush() - - async def update(self, id_: int, item: dict) -> db_models.Fetcher: - q = sa.update(db_models.Fetcher).where(db_models.Fetcher.id_ == id_).values(**item).returning(db_models.Fetcher) - if not await self.get_by_id(id_): - raise exc.ObjectNotFound(id_) - res = self.session.execute(q).scalar() - return res - - async def get_all(self) -> list[db_models.BaseModel]: - return list(self.session.scalars(sa.select(db_models.Fetcher)).all()) diff --git a/aciniformes_backend/service/metric.py b/aciniformes_backend/service/metric.py deleted file mode 100644 index 3551a72..0000000 --- a/aciniformes_backend/service/metric.py +++ /dev/null @@ -1,24 +0,0 @@ -import sqlalchemy as sa - -import aciniformes_backend.models as db_models -import aciniformes_backend.service.exceptions as exc - -from .base import MetricServiceInterface - - -class PgMetricService(MetricServiceInterface): - async def create(self, item: dict) -> int: - q = sa.insert(db_models.Metric).values(**item).returning(db_models.Metric) - metric = self.session.scalar(q) - self.session.flush() - return metric.id_ - - async def get_by_id(self, id_: int) -> db_models.Metric: - q = sa.select(db_models.Metric).where(db_models.Metric.id_ == id_) - res = self.session.scalar(q) - if not res: - raise exc.ObjectNotFound(id_) - return res - - async def get_all(self) -> list[db_models.BaseModel]: - return list(self.session.scalars(sa.select(db_models.Metric)).all()) diff --git a/aciniformes_backend/service/receiver.py b/aciniformes_backend/service/receiver.py deleted file mode 100644 index b1250cb..0000000 --- a/aciniformes_backend/service/receiver.py +++ /dev/null @@ -1,43 +0,0 @@ -from typing import Type - -import sqlalchemy as sa - -import aciniformes_backend.models as db_models -import aciniformes_backend.service.exceptions as exc - -from .base import ReceiverServiceInterface - - -class PgReceiverService(ReceiverServiceInterface): - async def create(self, item: dict) -> int: - q = sa.insert(db_models.Receiver).values(**item).returning(db_models.Receiver) - receiver = self.session.execute(q).scalar() - self.session.flush() - return receiver.id_ - - async def get_by_id(self, id_: int) -> Type[db_models.Receiver]: - q = sa.select(db_models.Receiver).where(db_models.Receiver.id_ == id_) - res = self.session.scalar(q) - if not res: - raise exc.ObjectNotFound(id_) - return res - - async def delete(self, id_: int) -> None: - q = sa.delete(db_models.Receiver).where(db_models.Receiver.id_ == id_) - self.session.execute(q) - self.session.flush() - - async def update(self, id_: int, item: dict) -> Type[db_models.Receiver]: - q = ( - sa.update(db_models.Receiver) - .where(db_models.Receiver.id_ == id_) - .values(**item) - .returning(db_models.Receiver) - ) - if not await self.get_by_id(id_): - raise exc.ObjectNotFound(id_) - res = self.session.execute(q).scalar() - return res - - async def get_all(self) -> list[db_models.BaseModel]: - return list(self.session.scalars(sa.select(db_models.Receiver)).all()) diff --git a/tests/backend/api/test_fetcher.py b/tests/backend/api/test_fetcher.py index 23f2d9e..3a2e3b0 100644 --- a/tests/backend/api/test_fetcher.py +++ b/tests/backend/api/test_fetcher.py @@ -4,8 +4,8 @@ import pytest import pytest_asyncio from starlette import status - -from aciniformes_backend.service.fetcher import PgFetcherService +import sqlalchemy as sa +import aciniformes_backend.models as db_models fetcher = { @@ -19,7 +19,15 @@ @pytest_asyncio.fixture async def this_fetcher(dbsession): - yield await PgFetcherService(dbsession).create(item=fetcher) + q = sa.insert(db_models.Fetcher).values(**fetcher).returning(db_models.Fetcher) + fetcher = dbsession.scalar(q) + dbsession.flush() + + yield fetcher.id_ + + q = sa.delete(db_models.Fetcher).where(db_models.Fetcher.id_ == id) + dbsession.execute(q) + dbsession.flush() @pytest.mark.authenticated("pinger.fetcher.create") diff --git a/tests/backend/api/test_metric.py b/tests/backend/api/test_metric.py index b8f16e4..1733ecb 100644 --- a/tests/backend/api/test_metric.py +++ b/tests/backend/api/test_metric.py @@ -1,8 +1,8 @@ import pytest import pytest_asyncio from starlette import status - -from aciniformes_backend.service.metric import PgMetricService +import aciniformes_backend.models as db_models +import sqlalchemy as sa metric = {"name": "string", "ok": True, "time_delta": 0} @@ -10,7 +10,15 @@ @pytest_asyncio.fixture async def this_metric(dbsession): - yield await PgMetricService(dbsession).create(item=metric) + q = sa.insert(db_models.Metric).values(**metric).returning(db_models.Metric) + metric = dbsession.scalar(q) + dbsession.flush() + + yield metric.id_ + + q = sa.delete(db_models.Metric).where(db_models.Metric.id_ == id) + dbsession.execute(q) + dbsession.flush() @pytest.mark.authenticated("pinger.metric.create") diff --git a/tests/backend/api/test_reciever.py b/tests/backend/api/test_reciever.py index d9fbae3..d280b89 100644 --- a/tests/backend/api/test_reciever.py +++ b/tests/backend/api/test_reciever.py @@ -3,8 +3,9 @@ import pytest import pytest_asyncio from starlette import status - -from aciniformes_backend.service.receiver import PgReceiverService +from fastapi_sqlalchemy import db +import sqlalchemy as sa +import aciniformes_backend.models as db_models receiver = {"url": "https://google.com", "method": "post", "receiver_body": {}} @@ -12,9 +13,16 @@ @pytest_asyncio.fixture async def this_receiver(dbsession): - global receiver - _receiver = await PgReceiverService(dbsession).create(item=receiver) - yield _receiver + q = sa.insert(db_models.Receiver).values(**receiver.model_dump()).returning(db_models.Receiver) + receiver = dbsession.execute(q).scalar() + dbsession.flush() + + yield receiver.id_ + + q = sa.delete(db_models.Receiver).where(db_models.Receiver.id_ == id) + dbsession.execute(q) + dbsession.flush() + @pytest.mark.authenticated("pinger.receiver.create") From 5cb0ce03501c4285c0aaee3f2a166113a67a478b Mon Sep 17 00:00:00 2001 From: Stanislav Roslavtsev Date: Wed, 9 Oct 2024 14:50:08 +0300 Subject: [PATCH 06/11] Black + isort --- aciniformes_backend/routes/fetcher.py | 12 +++++++++--- aciniformes_backend/routes/mectric.py | 5 +++-- aciniformes_backend/routes/receiver.py | 7 ++++--- tests/backend/api/test_fetcher.py | 3 ++- tests/backend/api/test_metric.py | 3 ++- tests/backend/api/test_reciever.py | 8 ++++---- 6 files changed, 24 insertions(+), 14 deletions(-) diff --git a/aciniformes_backend/routes/fetcher.py b/aciniformes_backend/routes/fetcher.py index 2a287d1..65f2aec 100644 --- a/aciniformes_backend/routes/fetcher.py +++ b/aciniformes_backend/routes/fetcher.py @@ -1,16 +1,17 @@ import logging +import sqlalchemy as sa from auth_lib.fastapi import UnionAuth from fastapi import APIRouter, Depends from fastapi.exceptions import HTTPException +from fastapi_sqlalchemy import db from pydantic import BaseModel, HttpUrl from pydantic.functional_serializers import PlainSerializer from starlette import status from typing_extensions import Annotated -import sqlalchemy as sa + import aciniformes_backend.models as db_models from aciniformes_backend.models.fetcher import FetcherType -from fastapi_sqlalchemy import db from aciniformes_backend.routes import exceptions as exc @@ -90,7 +91,12 @@ async def update( ): """Обновление одного сборщика метрик по id""" try: - q = sa.update(db_models.Fetcher).where(db_models.Fetcher.id_ == id).values(**update_schema).returning(db_models.Fetcher) + q = ( + sa.update(db_models.Fetcher) + .where(db_models.Fetcher.id_ == id) + .values(**update_schema) + .returning(db_models.Fetcher) + ) if not await db.get_by_id(id): raise exc.ObjectNotFound(id) res = db.session.execute(q).scalar() diff --git a/aciniformes_backend/routes/mectric.py b/aciniformes_backend/routes/mectric.py index 4e7037a..05dce87 100644 --- a/aciniformes_backend/routes/mectric.py +++ b/aciniformes_backend/routes/mectric.py @@ -1,10 +1,11 @@ +import sqlalchemy as sa from auth_lib.fastapi import UnionAuth from fastapi import APIRouter, Depends from fastapi.exceptions import HTTPException +from fastapi_sqlalchemy import db from pydantic import BaseModel from starlette import status -from fastapi_sqlalchemy import db -import sqlalchemy as sa + import aciniformes_backend.models as db_models from aciniformes_backend.routes import exceptions as exc diff --git a/aciniformes_backend/routes/receiver.py b/aciniformes_backend/routes/receiver.py index db39922..d66afe5 100644 --- a/aciniformes_backend/routes/receiver.py +++ b/aciniformes_backend/routes/receiver.py @@ -1,15 +1,16 @@ import logging from enum import Enum +import sqlalchemy as sa from auth_lib.fastapi import UnionAuth from fastapi import APIRouter, Depends from fastapi.exceptions import HTTPException +from fastapi_sqlalchemy import db from pydantic import BaseModel from starlette import status -from aciniformes_backend.routes import exceptions as exc + import aciniformes_backend.models as db_models -from fastapi_sqlalchemy import db -import sqlalchemy as sa +from aciniformes_backend.routes import exceptions as exc logger = logging.getLogger(__name__) diff --git a/tests/backend/api/test_fetcher.py b/tests/backend/api/test_fetcher.py index 3a2e3b0..fea60cb 100644 --- a/tests/backend/api/test_fetcher.py +++ b/tests/backend/api/test_fetcher.py @@ -3,8 +3,9 @@ import pytest import pytest_asyncio -from starlette import status import sqlalchemy as sa +from starlette import status + import aciniformes_backend.models as db_models diff --git a/tests/backend/api/test_metric.py b/tests/backend/api/test_metric.py index 1733ecb..22519fb 100644 --- a/tests/backend/api/test_metric.py +++ b/tests/backend/api/test_metric.py @@ -1,8 +1,9 @@ import pytest import pytest_asyncio +import sqlalchemy as sa from starlette import status + import aciniformes_backend.models as db_models -import sqlalchemy as sa metric = {"name": "string", "ok": True, "time_delta": 0} diff --git a/tests/backend/api/test_reciever.py b/tests/backend/api/test_reciever.py index d280b89..cff4451 100644 --- a/tests/backend/api/test_reciever.py +++ b/tests/backend/api/test_reciever.py @@ -2,9 +2,10 @@ import pytest import pytest_asyncio -from starlette import status -from fastapi_sqlalchemy import db import sqlalchemy as sa +from fastapi_sqlalchemy import db +from starlette import status + import aciniformes_backend.models as db_models @@ -16,7 +17,7 @@ async def this_receiver(dbsession): q = sa.insert(db_models.Receiver).values(**receiver.model_dump()).returning(db_models.Receiver) receiver = dbsession.execute(q).scalar() dbsession.flush() - + yield receiver.id_ q = sa.delete(db_models.Receiver).where(db_models.Receiver.id_ == id) @@ -24,7 +25,6 @@ async def this_receiver(dbsession): dbsession.flush() - @pytest.mark.authenticated("pinger.receiver.create") def test_post_success(crud_client): body = {"url": "https://google.com", "method": "post", "receiver_body": {}} From ee1ed4759c30a748bb35c46b11b0180d5ea8a8f3 Mon Sep 17 00:00:00 2001 From: Stanislav Roslavtsev Date: Wed, 9 Oct 2024 15:01:26 +0300 Subject: [PATCH 07/11] Change tests --- aciniformes_backend/routes/base.py | 2 -- aciniformes_backend/routes/fetcher.py | 16 +++++++++------- aciniformes_backend/routes/mectric.py | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/aciniformes_backend/routes/base.py b/aciniformes_backend/routes/base.py index 394025c..8fda466 100644 --- a/aciniformes_backend/routes/base.py +++ b/aciniformes_backend/routes/base.py @@ -5,7 +5,6 @@ from aciniformes_backend import __version__ from aciniformes_backend.settings import get_settings -from .alert import router as alert_router from .fetcher import router as fetcher_router from .mectric import router as metric_router from .receiver import router as receiver_router @@ -34,7 +33,6 @@ allow_headers=settings.CORS_ALLOW_HEADERS, ) -app.include_router(alert_router, prefix="/alert", tags=["Alert"]) app.include_router(receiver_router, prefix="/receiver", tags=["Receiver"]) app.include_router(fetcher_router, prefix="/fetcher", tags=["Fetcher"]) app.include_router(metric_router, prefix="/metric", tags=["Metric"]) diff --git a/aciniformes_backend/routes/fetcher.py b/aciniformes_backend/routes/fetcher.py index 65f2aec..5a7d372 100644 --- a/aciniformes_backend/routes/fetcher.py +++ b/aciniformes_backend/routes/fetcher.py @@ -44,7 +44,7 @@ class GetSchema(BaseModel): @router.post("", response_model=ResponsePostSchema) -async def create( +def create( create_schema: CreateSchema, _: dict[str] = Depends(UnionAuth(['pinger.fetcher.create'])), ): @@ -58,7 +58,7 @@ async def create( @router.get("") -async def get_all( +def get_all( _: dict[str] = Depends(UnionAuth(['pinger.fetcher.read'])), ): """ @@ -68,7 +68,7 @@ async def get_all( @router.get("/{id}") -async def get( +def get( id: int, _: dict[str] = Depends(UnionAuth(['pinger.fetcher.read'])), ): @@ -84,21 +84,23 @@ async def get( @router.patch("/{id}") -async def update( +def update( id: int, update_schema: UpdateSchema, _: dict[str] = Depends(UnionAuth(['pinger.fetcher.update'])), ): """Обновление одного сборщика метрик по id""" try: + q = sa.select(db_models.Fetcher).where(db_models.Fetcher.id_ == id) + res = db.session.scalar(q) + if not res: + raise exc.ObjectNotFound(id) q = ( sa.update(db_models.Fetcher) .where(db_models.Fetcher.id_ == id) .values(**update_schema) .returning(db_models.Fetcher) ) - if not await db.get_by_id(id): - raise exc.ObjectNotFound(id) res = db.session.execute(q).scalar() except exc.ObjectNotFound: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) @@ -106,7 +108,7 @@ async def update( @router.delete("/{id}") -async def delete( +def delete( id: int, _: dict[str] = Depends(UnionAuth(['pinger.fetcher.delete'])), ): diff --git a/aciniformes_backend/routes/mectric.py b/aciniformes_backend/routes/mectric.py index 05dce87..42ffe4b 100644 --- a/aciniformes_backend/routes/mectric.py +++ b/aciniformes_backend/routes/mectric.py @@ -47,7 +47,7 @@ async def get_all( _: dict[str] = Depends(UnionAuth(['pinger.metric.read'])), ): """Получение всех метрик.""" - return list(db.session.scalars(sa.select(db_models.Fetcher)).all()) + return list(db.session.scalars(sa.select(db_models.Metric)).all()) @router.get("/{id}") @@ -57,7 +57,7 @@ async def get( ): """Получение одной метрики по id.""" try: - q = sa.select(db_models.Fetcher).where(db_models.Fetcher.id_ == id) + q = sa.select(db_models.Metric).where(db_models.Metric.id_ == id) res = db.session.scalar(q) if not res: raise exc.ObjectNotFound(id) From fa9c1eff6099ec3004d8aea77f5007495ae63d91 Mon Sep 17 00:00:00 2001 From: Stanislav Roslavtsev Date: Wed, 9 Oct 2024 15:04:24 +0300 Subject: [PATCH 08/11] Remove async --- aciniformes_backend/routes/mectric.py | 6 +++--- aciniformes_backend/routes/receiver.py | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/aciniformes_backend/routes/mectric.py b/aciniformes_backend/routes/mectric.py index 42ffe4b..b856fd5 100644 --- a/aciniformes_backend/routes/mectric.py +++ b/aciniformes_backend/routes/mectric.py @@ -31,7 +31,7 @@ class GetSchema(BaseModel): @router.post("", response_model=ResponsePostSchema) -async def create( +def create( metric_schema: CreateSchema, _: dict[str] = Depends(UnionAuth(['pinger.metric.create'])), ): @@ -43,7 +43,7 @@ async def create( @router.get("") -async def get_all( +def get_all( _: dict[str] = Depends(UnionAuth(['pinger.metric.read'])), ): """Получение всех метрик.""" @@ -51,7 +51,7 @@ async def get_all( @router.get("/{id}") -async def get( +def get( id: int, _: dict[str] = Depends(UnionAuth(['pinger.metric.read'])), ): diff --git a/aciniformes_backend/routes/receiver.py b/aciniformes_backend/routes/receiver.py index d66afe5..699b8af 100644 --- a/aciniformes_backend/routes/receiver.py +++ b/aciniformes_backend/routes/receiver.py @@ -49,7 +49,7 @@ class GetSchema(BaseModel): @router.post("", response_model=PostResponseSchema) -async def create( +def create( create_schema: CreateSchema, _: dict[str] = Depends(UnionAuth(['pinger.receiver.create'])), ): @@ -61,7 +61,7 @@ async def create( @router.get("") -async def get_all( +def get_all( _: dict[str] = Depends(UnionAuth(['pinger.receiver.read'])), ): """Получить всех получателей уведомлений.""" @@ -69,7 +69,7 @@ async def get_all( @router.get("/{id}") -async def get( +def get( id: int, _: dict[str] = Depends(UnionAuth(['pinger.receiver.read'])), ): @@ -84,7 +84,7 @@ async def get( @router.patch("/{id}") -async def update( +def update( id: int, update_schema: UpdateSchema, _: dict[str] = Depends(UnionAuth(['pinger.receiver.update'])), @@ -108,7 +108,7 @@ async def update( @router.delete("/{id}") -async def delete( +def delete( id: int, _: dict[str] = Depends(UnionAuth(['pinger.receiver.delete'])), ): From ea0b050763d5de2019b0d7bb6e6144629c477e58 Mon Sep 17 00:00:00 2001 From: Stanislav Roslavtsev Date: Wed, 9 Oct 2024 15:07:27 +0300 Subject: [PATCH 09/11] Delete service tests --- tests/backend/service/__init__.py | 1 - tests/backend/service/test_fetcher_service.py | 62 ------------------- tests/backend/service/test_metric_service.py | 46 -------------- 3 files changed, 109 deletions(-) delete mode 100644 tests/backend/service/__init__.py delete mode 100644 tests/backend/service/test_fetcher_service.py delete mode 100644 tests/backend/service/test_metric_service.py diff --git a/tests/backend/service/__init__.py b/tests/backend/service/__init__.py deleted file mode 100644 index 1ca2d6c..0000000 --- a/tests/backend/service/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# real service impl, only service methods testing diff --git a/tests/backend/service/test_fetcher_service.py b/tests/backend/service/test_fetcher_service.py deleted file mode 100644 index b5c49fa..0000000 --- a/tests/backend/service/test_fetcher_service.py +++ /dev/null @@ -1,62 +0,0 @@ -import pytest -import sqlalchemy - -from aciniformes_backend.models import Fetcher -from aciniformes_backend.routes.fetcher import CreateSchema as FetcherCreateSchema -from aciniformes_backend.service.fetcher import PgFetcherService - - -@pytest.fixture -def fetcher_schema(): - body = { - "id": 6, - "type_": "ping", - "address": "https://www.python.org", - "fetch_data": "string", - "delay_ok": 30, - "delay_fail": 40, - } - schema = FetcherCreateSchema(**body) - return schema - - -@pytest.fixture() -def db_fetcher(dbsession, fetcher_schema): - q = sqlalchemy.insert(Fetcher).values(**fetcher_schema.model_dump(exclude_unset=True)).returning(Fetcher) - fetcher = dbsession.scalar(q) - dbsession.flush() - yield fetcher - if dbsession.get(Fetcher, fetcher.id_): - dbsession.delete(fetcher) - dbsession.flush() - - -class TestFetcherService: - @pytest.mark.asyncio - async def test_create(self, dbsession, fetcher_schema): - res = await PgFetcherService(dbsession).create(fetcher_schema.model_dump(exclude_unset=True)) - assert res is not None - assert type(res) is int - q = dbsession.scalar(sqlalchemy.select(Fetcher).where(Fetcher.id_ == res)) - assert q is not None - - @pytest.mark.asyncio - async def test_get_all(self, dbsession, db_fetcher): - res = await PgFetcherService(dbsession).get_all() - assert type(res) is list - assert type(res[0]) is Fetcher - - @pytest.mark.asyncio - async def test_get_by_id(self, dbsession, db_fetcher): - res = await PgFetcherService(dbsession).get_by_id(db_fetcher.id_) - assert res.address == db_fetcher.address - assert res.type_ == db_fetcher.type_ - - @pytest.mark.asyncio - async def test_delete(self, dbsession, db_fetcher): - await PgFetcherService(dbsession).delete(db_fetcher.id_) - - @pytest.mark.asyncio - async def test_update(self, dbsession, db_fetcher): - res = await PgFetcherService(dbsession).update(db_fetcher.id_, {"type_": "post"}) - assert res.type_ == "post" diff --git a/tests/backend/service/test_metric_service.py b/tests/backend/service/test_metric_service.py deleted file mode 100644 index 60a3fbe..0000000 --- a/tests/backend/service/test_metric_service.py +++ /dev/null @@ -1,46 +0,0 @@ -import pytest -import sqlalchemy - -from aciniformes_backend.models import Metric -from aciniformes_backend.routes.mectric import CreateSchema as MetricCreateSchema -from aciniformes_backend.service.metric import PgMetricService - - -@pytest.fixture -def metric_schema(): - body = {"id": 44, "name": "string", "ok": True, "time_delta": 0} - schema = MetricCreateSchema(**body) - return schema - - -@pytest.fixture() -def db_metric(dbsession, metric_schema): - q = sqlalchemy.insert(Metric).values(**metric_schema.model_dump(exclude_unset=True)).returning(Metric) - metric = dbsession.scalar(q) - dbsession.flush() - yield metric - if dbsession.get(Metric, metric.id_): - dbsession.delete(metric) - dbsession.flush() - - -class TestMetricService: - @pytest.mark.asyncio - async def test_create(self, metric_schema, dbsession): - res = await PgMetricService(dbsession).create(metric_schema.model_dump(exclude_unset=True)) - assert res is not None - assert type(res) is int - q = dbsession.scalar(sqlalchemy.select(Metric).where(Metric.id_ == res)) - assert q is not None - - @pytest.mark.asyncio - async def test_get_all(self, dbsession): - res = await PgMetricService(dbsession).get_all() - assert type(res) is list - assert type(res[0]) is Metric - - @pytest.mark.asyncio - async def test_get_by_id(self, dbsession, db_metric): - res = await PgMetricService(dbsession).get_by_id(db_metric.id_) - assert res.name == db_metric.name - assert res.ok == db_metric.ok From ed1a742027bf67a877432ce29a9ee7309b32404f Mon Sep 17 00:00:00 2001 From: Stanislav Roslavtsev Date: Wed, 9 Oct 2024 15:13:08 +0300 Subject: [PATCH 10/11] Test fix --- tests/backend/api/test_fetcher.py | 2 ++ tests/backend/api/test_metric.py | 2 ++ tests/backend/api/test_reciever.py | 2 ++ 3 files changed, 6 insertions(+) diff --git a/tests/backend/api/test_fetcher.py b/tests/backend/api/test_fetcher.py index fea60cb..1cbbd98 100644 --- a/tests/backend/api/test_fetcher.py +++ b/tests/backend/api/test_fetcher.py @@ -20,6 +20,7 @@ @pytest_asyncio.fixture async def this_fetcher(dbsession): + global fetcher q = sa.insert(db_models.Fetcher).values(**fetcher).returning(db_models.Fetcher) fetcher = dbsession.scalar(q) dbsession.flush() @@ -48,6 +49,7 @@ def test_post_success(crud_client): @pytest.mark.authenticated("pinger.fetcher.read") def test_get_by_id_success(crud_client, this_fetcher): + global fetcher res = crud_client.get(f"/fetcher/{this_fetcher}") assert res.status_code == status.HTTP_200_OK _new_fetcher = deepcopy(fetcher) diff --git a/tests/backend/api/test_metric.py b/tests/backend/api/test_metric.py index 22519fb..9ee65c6 100644 --- a/tests/backend/api/test_metric.py +++ b/tests/backend/api/test_metric.py @@ -11,6 +11,7 @@ @pytest_asyncio.fixture async def this_metric(dbsession): + global metric q = sa.insert(db_models.Metric).values(**metric).returning(db_models.Metric) metric = dbsession.scalar(q) dbsession.flush() @@ -36,6 +37,7 @@ def test_post_success(crud_client): @pytest.mark.authenticated("pinger.metric.read") def test_get_by_id_success(crud_client, this_metric): + global metric res = crud_client.get(f"/metric/{this_metric}") assert res.status_code == status.HTTP_200_OK for k, v in metric.items(): diff --git a/tests/backend/api/test_reciever.py b/tests/backend/api/test_reciever.py index cff4451..5b37ce9 100644 --- a/tests/backend/api/test_reciever.py +++ b/tests/backend/api/test_reciever.py @@ -14,6 +14,7 @@ @pytest_asyncio.fixture async def this_receiver(dbsession): + global receiver q = sa.insert(db_models.Receiver).values(**receiver.model_dump()).returning(db_models.Receiver) receiver = dbsession.execute(q).scalar() dbsession.flush() @@ -37,6 +38,7 @@ def test_post_success(crud_client): @pytest.mark.authenticated("pinger.receiver.read") def test_get_by_id_success(crud_client, this_receiver): + global receiver res = crud_client.get(f"/receiver/{this_receiver}") assert res.status_code == status.HTTP_200_OK res_body = res.json() From 0c413fa0d149041f974bb17f64c1ee51330e70d1 Mon Sep 17 00:00:00 2001 From: Stanislav Roslavtsev Date: Wed, 9 Oct 2024 15:17:11 +0300 Subject: [PATCH 11/11] Text fix v2 --- tests/backend/api/test_fetcher.py | 4 ++-- tests/backend/api/test_metric.py | 4 ++-- tests/backend/api/test_reciever.py | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/backend/api/test_fetcher.py b/tests/backend/api/test_fetcher.py index 1cbbd98..0ec4d85 100644 --- a/tests/backend/api/test_fetcher.py +++ b/tests/backend/api/test_fetcher.py @@ -22,10 +22,10 @@ async def this_fetcher(dbsession): global fetcher q = sa.insert(db_models.Fetcher).values(**fetcher).returning(db_models.Fetcher) - fetcher = dbsession.scalar(q) + fetcher_db = dbsession.scalar(q) dbsession.flush() - yield fetcher.id_ + yield fetcher_db.id_ q = sa.delete(db_models.Fetcher).where(db_models.Fetcher.id_ == id) dbsession.execute(q) diff --git a/tests/backend/api/test_metric.py b/tests/backend/api/test_metric.py index 9ee65c6..39ffd03 100644 --- a/tests/backend/api/test_metric.py +++ b/tests/backend/api/test_metric.py @@ -13,10 +13,10 @@ async def this_metric(dbsession): global metric q = sa.insert(db_models.Metric).values(**metric).returning(db_models.Metric) - metric = dbsession.scalar(q) + metric_db = dbsession.scalar(q) dbsession.flush() - yield metric.id_ + yield metric_db.id_ q = sa.delete(db_models.Metric).where(db_models.Metric.id_ == id) dbsession.execute(q) diff --git a/tests/backend/api/test_reciever.py b/tests/backend/api/test_reciever.py index 5b37ce9..ce4aab3 100644 --- a/tests/backend/api/test_reciever.py +++ b/tests/backend/api/test_reciever.py @@ -15,11 +15,11 @@ @pytest_asyncio.fixture async def this_receiver(dbsession): global receiver - q = sa.insert(db_models.Receiver).values(**receiver.model_dump()).returning(db_models.Receiver) - receiver = dbsession.execute(q).scalar() + q = sa.insert(db_models.Receiver).values(**receiver).returning(db_models.Receiver) + receiver_db = dbsession.execute(q).scalar() dbsession.flush() - yield receiver.id_ + yield receiver_db.id_ q = sa.delete(db_models.Receiver).where(db_models.Receiver.id_ == id) dbsession.execute(q)