Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 8 additions & 6 deletions rental_backend/routes/rental_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ async def check_sessions_overdue():
)
async def create_rental_session(
item_type_id: int,
user=Depends(UnionAuth(scopes=["rental.session.create"], enable_userdata=True)),
user=Depends(UnionAuth(scopes=["rental.session.create"], enable_userdata=True)),
):
"""
Создает новую сессию аренды для указанного типа предмета.
Expand Down Expand Up @@ -176,7 +176,9 @@ def validate_deadline_ts(deadline_ts: datetime.datetime | None = Query(descripti
"/{session_id}/start", response_model=RentalSessionGet, dependencies=[Depends(check_sessions_expiration)]
)
async def start_rental_session(
session_id, deadline_ts=Depends(validate_deadline_ts), user=Depends(UnionAuth(scopes=["rental.session.admin"]))
session_id: int,
deadline_ts=Depends(validate_deadline_ts),
user=Depends(UnionAuth(scopes=["rental.session.admin"]))
):
"""
Starts a rental session, changing its status to ACTIVE.
Expand Down Expand Up @@ -230,7 +232,7 @@ async def accept_end_rental_session(
session_id: int,
with_strike: bool = Query(False, description="A flag indicating whether to issue a strike."),
strike_reason: str = Query("", description="The reason for the strike."),
user=Depends(UnionAuth(scopes=["rental.session.admin"])),
user=Depends(UnionAuth(scopes=["rental.session.admin"]))
):
"""
Ends a rental session, changing its status to RETURNED. Issues a strike if specified.
Expand Down Expand Up @@ -279,7 +281,7 @@ async def accept_end_rental_session(
session=db.session, **strike_info.model_dump(), create_ts=datetime.datetime.now(tz=datetime.timezone.utc)
)

ended_session.strike_id = new_strike.id
ended_session.strike = new_strike
db.session.commit()

ActionLogger.log_event(
Expand Down Expand Up @@ -398,7 +400,7 @@ async def get_rental_sessions(
is_expired: bool = Query(False, description="Флаг, показывать просроченные"),
item_type_id: int = Query(0, description="ID типа предмета"),
user_id: int = Query(0, description="User_id для получения сессий"),
user=Depends(UnionAuth(scopes=["rental.session.admin"])),
user=Depends(UnionAuth(scopes=["rental.session.admin"])),
):
"""
Retrieves a list of rental sessions with optional status filtering.
Expand Down Expand Up @@ -543,7 +545,7 @@ async def cancel_rental_session(session_id: int, user=Depends(UnionAuth())):

@rental_session.patch("/{session_id}", response_model=RentalSessionGet)
async def update_rental_session(
session_id: int, update_data: RentalSessionPatch, user=Depends(UnionAuth(scopes=["rental.session.admin"]))
session_id: int, update_data: RentalSessionPatch, user=Depends(UnionAuth(scopes=["rental.session.admin"]))
):
"""
Updates the information of a rental session.
Expand Down
89 changes: 78 additions & 11 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
import importlib
import sys
from functools import lru_cache
from pathlib import Path
from typing import Any, Dict, List

import datetime
import pytest
from _pytest.monkeypatch import MonkeyPatch
from alembic import command
from alembic.config import Config as AlembicConfig
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy import create_engine, func
from sqlalchemy.orm import sessionmaker
from testcontainers.postgres import PostgresContainer

from rental_backend.models.db import *
from rental_backend.routes import app
from rental_backend.settings import Settings, get_settings
from rental_backend.schemas.models import RentStatus
from rental_backend.routes.rental_session import RENTAL_SESSION_EXPIRY


class PostgresConfig:
Expand Down Expand Up @@ -90,11 +93,16 @@
return {
"auth_methods": ["string"],
"session_scopes": [{"id": 0, "name": "string"}],
"user_scopes": [{"id": 0, "name": "string"}],
"user_scopes": [{"id": 1, "name": "rental.session.admin"}], # добавлен нужный скоуп "rental.session.admin" (по сути сейчас эта строка ничего не делает, но как в UnionAuth)
"scopes": ["rental.session.admin"], # добавлено для корректной работы прав в тесте test_admin_can_update_any_rental_session
"indirect_groups": [0],
"groups": [0],
"id": 0,
"email": "string",
"userdata": [
{"param": "Полное имя", "value": "Тестов Тест"},
{"param": "Номер телефона", "value": "+79991234567"}
],
}


Expand All @@ -107,7 +115,8 @@
return {
"auth_methods": ["string"],
"session_scopes": [{"id": 0, "name": "string"}],
"user_scopes": [{"id": 0, "name": "string"}],
"user_scopes": [],
"scopes": [],
"indirect_groups": [0],
"groups": [0],
"id": 1,
Expand Down Expand Up @@ -228,6 +237,19 @@
dbsession.commit()
return item

@pytest.fixture
def available_item(dbsession, item_type_fixture):
"""Создаёт доступный предмет для первого типа."""
item = Item(type_id=item_type_fixture[0].id, is_available=True)
dbsession.add(item)
dbsession.commit()
return item

@pytest.fixture
def nonexistent_type_id(dbsession):
"""Возвращает заведомо несуществующий ID типа предмета. (для тестов при создании сессий)"""
max_id = dbsession.query(func.max(ItemType.id)).scalar() or 0
return max_id + 1

@pytest.fixture()
def items_with_types(dbsession):
Expand All @@ -254,12 +276,6 @@
dbsession.add(i)
dbsession.commit()
yield items
for i in item_types:
for item in i.items:
dbsession.delete(item)
dbsession.flush()
dbsession.delete(i)
dbsession.commit()


@pytest.fixture()
Expand Down Expand Up @@ -289,6 +305,37 @@
dbsession.delete(i)
dbsession.commit()

@pytest.fixture
def two_available_items_same_type(dbsession, item_types):
"""
Создаёт для два доступных предмета к первому типу из item_types и возвращает тип.
"""
item_type = item_types[0]
items = [
Item(type_id=item_type.id, is_available=True),
Item(type_id=item_type.id, is_available=True),
]
dbsession.add_all(items)
dbsession.commit()
return item_type

@pytest.fixture(params=[RentStatus.RESERVED, RentStatus.ACTIVE, RentStatus.OVERDUE])
def blocking_session(request, dbsession, two_available_items_same_type, authlib_user):
"""Создаёт сессию для первого предмета типа с заданным статусом."""
item_type = two_available_items_same_type
items = item_type.items
now = datetime.datetime.now(datetime.timezone.utc)
session = RentalSession.create(
session=dbsession,
user_id=authlib_user["id"],
item_id=items[0].id,
status=request.param,
reservation_ts=now,
)
items[0].is_available = False
dbsession.add(session, items[0])
dbsession.commit()
return item_type

@pytest.fixture
def items_with_same_type(dbsession, item_types) -> List[Item]:
Expand All @@ -303,7 +350,7 @@
@pytest.fixture()
def expire_mock(mocker):
"""Mock-объект для функции check_session_expiration."""
fake_check = mocker.patch('rental_backend.routes.rental_session.check_session_expiration')
fake_check = mocker.patch('rental_backend.routes.rental_session.check_sessions_expiration')
fake_check.return_value = True
return fake_check

Expand Down Expand Up @@ -346,7 +393,7 @@
item_id=renting_item.id,
status=RentStatus.RESERVED,
)
Item.update(id=renting_item.id, session=dbsession, is_available=False)
renting_item.is_available = False
dbsession.add(rent)
dbsession.commit()
return rent
Expand All @@ -366,6 +413,26 @@
dbsession.commit()
return rent

@pytest.fixture
def expired_reserved_session(dbsession, rentses):
"""
Принимает сессию rentses (RESERVED) и сдвигает её reservation_ts в прошлое, чтобы она стала просроченной согласно RENTAL_SESSION_EXPIRY.
Возвращает ID сессии.
"""
now = datetime.datetime.now(datetime.timezone.utc)
past_ts = now - RENTAL_SESSION_EXPIRY - datetime.timedelta(seconds=1)
rentses.reservation_ts = past_ts
dbsession.add(rentses)
dbsession.commit()
return rentses.id

@pytest.fixture
def active_rentses_with_end_ts(dbsession, active_rentses):
"""Возвращает активную сессию с предустановленным end_ts."""
active_rentses.end_ts = datetime.datetime.now(tz=datetime.timezone.utc)
dbsession.add(active_rentses)
dbsession.commit()
return active_rentses

# Utils
def model_to_dict(model: BaseDbModel) -> Dict[str, Any]:
Expand Down
Loading
Loading