Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions migrations/versions/bd5dc5ad8627_changed_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
Create Date: 2026-08-17 12:55:02.773293

"""
from alembic import op
import sqlalchemy as sa

import sqlalchemy as sa
from alembic import op

# revision identifiers, used by Alembic.
revision = 'bd5dc5ad8627'
Expand Down
1 change: 0 additions & 1 deletion modal_backend/models/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
Integer,
String,
cast,
func,
or_,
true,
)
Expand Down
6 changes: 3 additions & 3 deletions modal_backend/routes/notes.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ async def get_notes(
type_id: int = Query(None),
groups_id: list[int] = Query(None),
services_id: list[int] = Query(None),
status: str = Query(
status: ModalStatus = Query(
enum=["active", "archived"],
default=None,
),
asc_order: bool = False,
limit: int = 10,
offset: int = 0,
limit: int = Query(10, ge=0, description="Лимит записей"),
offset: int = Query(0, ge=0, description="Смещение записей на N+offset, где N - первая запись"),
user=Depends(UnionAuth()),
) -> list[NoteGet]:
"""
Expand Down
2 changes: 1 addition & 1 deletion modal_backend/utils/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ async def get_notes_by_filters(
type_id: int = None,
groups_id: list[int] = None,
services_id: list[int] = None,
status: str = None,
status: ModalStatus | None = None,
):
notes_query = (
Note.query(session=db.session)
Expand Down
208 changes: 208 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from datetime import datetime, timedelta, timezone
from functools import lru_cache
from pathlib import Path

Expand All @@ -10,8 +11,18 @@
from sqlalchemy.orm import sessionmaker
from testcontainers.postgres import PostgresContainer

from modal_backend.models.db import Group, ModalStatus, Note, NoteTypeEnum, Service
from modal_backend.schemas.models import (
NoteChoicePost,
NoteImagePost,
NoteInfoPost,
NoteRatingPost,
NoteTextPost,
)
from modal_backend.settings import Settings

NOW = datetime.now(timezone.utc).replace(tzinfo=None)


class PostgresConfig:
"""Дата-класс со значениями для контейнера с тестовой БД и для alembic-миграции."""
Expand Down Expand Up @@ -133,3 +144,200 @@ def client(get_app_with_test_settings, user_mock):
app = get_app_with_test_settings
client = TestClient(app)
return client


def create_group(group_id: int, name: str) -> Group:
"""Вспомогательная функция-мини-фабрика для создания разных групп в фикстуре groups."""
return Group(group_id=group_id, name=name)


@pytest.fixture()
def groups(dbsession):
"""Создает три группы."""
group_data = [(1, "Group_1"), (2, "Group_2"), (3, "Group_3")]
groups = [create_group(*group) for group in group_data]
for group in groups:
dbsession.add(group)
dbsession.commit()
yield groups
for group in groups:
dbsession.delete(group)
dbsession.commit()


def create_service(service_id: int, name: str) -> Service:
"""Вспомогательная функция-мини-фабрика для создания разных сервисов в фикстуре services."""
return Service(service_id=service_id, name=name)


@pytest.fixture()
def services(dbsession):
"""Создает три сервиса."""
service_data = [(1, "Service_1"), (2, "Service_2"), (3, "Service_3")]
services = [create_service(*service) for service in service_data]
for service in services:
dbsession.add(service)
dbsession.commit()
yield services
for service in services:
dbsession.delete(service)
dbsession.commit()


@pytest.fixture()
def mock_datetime_now(mocker):
mock_datetime = mocker.patch("modal_backend.utils.services.datetime")
mock_datetime.now.return_value = NOW
yield


def create_note(
type_id: int,
schema: NoteChoicePost | NoteImagePost | NoteInfoPost | NoteRatingPost | NoteTextPost,
admin_id: int,
status: ModalStatus,
):
return Note(
type_id=type_id,
**schema.model_dump(),
admin_id=admin_id,
status=status,
)


@pytest.fixture()
def notes(
dbsession,
groups,
services,
authlib_user_data,
):
"""Создает 8 модалок:
indexes: descriprion:
(0, 1, 2, 3, 4) 5 с разными типами
(0, 1, 2) 3 активные
(3, 4, 5, 6, 7) 5 архивных
(0, 2, 4, 6, 7) group_ids = [3] service_ids = [3]
(1, 3) group_ids = [1, 2] service_ids = [1, 2]
(5) group_ids - [1, 2, 3] service_ids = [1, 2, 3]
(6, 7) просроченные, одна с is_always=True
"""
note_data = [
{
"type_id": NoteTypeEnum.INFO,
"schema": NoteInfoPost(
header="header_1",
is_always=False,
frequency=10,
group_ids=[group.id for group in groups][2:3],
service_ids=[service.id for service in services][2:3],
),
"admin_id": authlib_user_data.get("id"),
"status": ModalStatus.ACTIVE,
},
{
"type_id": NoteTypeEnum.RATING,
"schema": NoteRatingPost(
header="header_2",
is_always=False,
frequency=10,
group_ids=[group.id for group in groups][:2],
service_ids=[service.id for service in services][:2],
),
"admin_id": authlib_user_data.get("id"),
"status": ModalStatus.ACTIVE,
},
{
"type_id": NoteTypeEnum.TEXT,
"schema": NoteTextPost(
header="header_3",
is_always=False,
frequency=10,
group_ids=[group.id for group in groups][2:3],
service_ids=[service.id for service in services][2:3],
),
"admin_id": authlib_user_data.get("id"),
"status": ModalStatus.ACTIVE,
},
{
"type_id": NoteTypeEnum.CHOICE,
"schema": NoteChoicePost(
header="header_4",
is_always=False,
frequency=10,
group_ids=[group.id for group in groups][:2],
service_ids=[service.id for service in services][:2],
),
"admin_id": authlib_user_data.get("id"),
"status": ModalStatus.ARCHIVED,
},
{
"type_id": NoteTypeEnum.IMAGE,
"schema": NoteImagePost(
header="header_5",
is_always=False,
frequency=10,
group_ids=[group.id for group in groups][2:3],
service_ids=[service.id for service in services][2:3],
),
"admin_id": authlib_user_data.get("id"),
"status": ModalStatus.ARCHIVED,
},
{
"type_id": NoteTypeEnum.IMAGE,
"schema": NoteImagePost(
header="header_5",
is_always=False,
frequency=10,
group_ids=[group.id for group in groups],
service_ids=[service.id for service in services],
),
"admin_id": authlib_user_data.get("id"),
"status": ModalStatus.ARCHIVED,
},
]

for offset, d in enumerate(note_data):
d["schema"].start_ts = NOW + offset * timedelta(hours=1)
d["schema"].end_ts = NOW + offset * timedelta(hours=1) + timedelta(hours=1)
note_data.extend(
[
{ # просроченная модалка index 6
"type_id": NoteTypeEnum.IMAGE,
"schema": NoteImagePost(
header="header_6",
is_always=False,
frequency=10,
group_ids=[group.id for group in groups][2:3],
service_ids=[service.id for service in services][2:3],
start_ts=NOW + timedelta(hours=2) * 5,
end_ts=NOW - timedelta(hours=1) * 5,
),
"admin_id": authlib_user_data.get("id"),
"status": ModalStatus.ARCHIVED,
},
{ # просроченная модалка c is_always=True index 7
"type_id": NoteTypeEnum.IMAGE,
"schema": NoteImagePost(
header="header_7",
is_always=True,
frequency=10,
group_ids=[group.id for group in groups][2:3],
service_ids=[service.id for service in services][2:3],
start_ts=NOW + timedelta(hours=3) * 5,
end_ts=NOW - timedelta(hours=1) * 5,
),
"admin_id": authlib_user_data.get("id"),
"status": ModalStatus.ARCHIVED,
},
]
)
notes = [create_note(**note) for note in note_data]

for note in notes:
dbsession.add(note)
dbsession.commit()
yield notes
for note in notes:
dbsession.delete(note)
dbsession.commit()
Loading
Loading