From d7b4e36abbe4b9f706667bee7db3a6e9c9ec8adb Mon Sep 17 00:00:00 2001 From: Georgon Date: Fri, 13 Mar 2026 09:46:21 +0300 Subject: [PATCH 1/4] tests for rental session and some new fixtures --- rental_backend/routes/rental_session.py | 26 ++++ tests/conftest.py | 90 ++++++++++++- tests/test_routes/test_rental_session.py | 160 +++++++++++++++++++++-- 3 files changed, 263 insertions(+), 13 deletions(-) diff --git a/rental_backend/routes/rental_session.py b/rental_backend/routes/rental_session.py index e574024..e7e8ccc 100644 --- a/rental_backend/routes/rental_session.py +++ b/rental_backend/routes/rental_session.py @@ -85,7 +85,11 @@ async def check_sessions_overdue(): ) async def create_rental_session( item_type_id: int, +<<<<<<< Updated upstream user=Depends(UnionAuth(scopes=["rental.session.create"], enable_userdata=True)), +======= + user=Depends(UnionAuth(scopes=["rental.session.create"], enable_userdata=True)), +>>>>>>> Stashed changes ): """ Создает новую сессию аренды для указанного типа предмета. @@ -176,7 +180,13 @@ 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( +<<<<<<< Updated upstream 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"])) +>>>>>>> Stashed changes ): """ Starts a rental session, changing its status to ACTIVE. @@ -230,7 +240,11 @@ 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."), +<<<<<<< Updated upstream user=Depends(UnionAuth(scopes=["rental.session.admin"])), +======= + user=Depends(UnionAuth(scopes=["rental.session.admin"])) +>>>>>>> Stashed changes ): """ Ends a rental session, changing its status to RETURNED. Issues a strike if specified. @@ -279,7 +293,11 @@ async def accept_end_rental_session( session=db.session, **strike_info.model_dump(), create_ts=datetime.datetime.now(tz=datetime.timezone.utc) ) +<<<<<<< Updated upstream ended_session.strike_id = new_strike.id +======= + ended_session.strike = new_strike +>>>>>>> Stashed changes db.session.commit() ActionLogger.log_event( @@ -398,7 +416,11 @@ 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 для получения сессий"), +<<<<<<< Updated upstream user=Depends(UnionAuth(scopes=["rental.session.admin"])), +======= + user=Depends(UnionAuth(scopes=["rental.session.admin"])), +>>>>>>> Stashed changes ): """ Retrieves a list of rental sessions with optional status filtering. @@ -543,7 +565,11 @@ async def cancel_rental_session(session_id: int, user=Depends(UnionAuth())): @rental_session.patch("/{session_id}", response_model=RentalSessionGet) async def update_rental_session( +<<<<<<< Updated upstream 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"])) +>>>>>>> Stashed changes ): """ Updates the information of a rental session. diff --git a/tests/conftest.py b/tests/conftest.py index 5314ef6..ca159e2 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -4,18 +4,21 @@ 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: @@ -90,11 +93,23 @@ def authlib_user(): return { "auth_methods": ["string"], "session_scopes": [{"id": 0, "name": "string"}], +<<<<<<< Updated upstream "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 +>>>>>>> Stashed changes "indirect_groups": [0], "groups": [0], "id": 0, "email": "string", +<<<<<<< Updated upstream +======= + "userdata": [ + {"param": "Полное имя", "value": "Тестов Тест"}, + {"param": "Номер телефона", "value": "+79991234567"} + ], +>>>>>>> Stashed changes } @@ -107,7 +122,12 @@ def another_authlib_user(): return { "auth_methods": ["string"], "session_scopes": [{"id": 0, "name": "string"}], +<<<<<<< Updated upstream "user_scopes": [{"id": 0, "name": "string"}], +======= + "user_scopes": [], + "scopes": [], +>>>>>>> Stashed changes "indirect_groups": [0], "groups": [0], "id": 1, @@ -228,6 +248,19 @@ def item_fixture(dbsession, item_type_fixture): 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): @@ -289,6 +322,37 @@ def items_with_same_type_id(dbsession): 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]: @@ -346,7 +410,11 @@ def another_rentses(dbsession, items_with_same_type, another_authlib_user) -> Re item_id=renting_item.id, status=RentStatus.RESERVED, ) +<<<<<<< Updated upstream Item.update(id=renting_item.id, session=dbsession, is_available=False) +======= + renting_item.is_available = False +>>>>>>> Stashed changes dbsession.add(rent) dbsession.commit() return rent @@ -366,6 +434,26 @@ def active_rentses(dbsession, item_fixture, authlib_user) -> RentalSession: 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]: diff --git a/tests/test_routes/test_rental_session.py b/tests/test_routes/test_rental_session.py index 791155f..d7b2247 100644 --- a/tests/test_routes/test_rental_session.py +++ b/tests/test_routes/test_rental_session.py @@ -42,6 +42,7 @@ def check_object_update(model_instance: BaseDbModel, session, **final_fields): # Tests for POST /rental-sessions/{item_type_id} +<<<<<<< Updated upstream @pytest.mark.usefixtures('expire_mock') @pytest.mark.parametrize( 'start_item_avail, end_item_avail, itemtype_list_ind, right_status_code, num_of_creations', @@ -71,14 +72,54 @@ def test_create_with_diff_item( type_id = ItemType.query(session=dbsession).all()[itemtype_list_ind].id except IndexError: type_id = ItemType.query(session=dbsession).order_by(desc('id'))[0].id + 1 +======= +def test_create_with_available_item(dbsession, client, base_rentses_url, available_item): + """Тест на успешное создание сессии при доступном предмете.""" +>>>>>>> Stashed changes with ( - check_object_creation(RentalSession, dbsession, num_of_creations=num_of_creations), - check_object_update(item_fixture, session=dbsession, is_available=end_item_avail), + check_object_creation(RentalSession, dbsession, num_of_creations=1), + check_object_update(available_item, dbsession, is_available=False) ): + response = client.post(f'{base_rentses_url}/{available_item.type_id}') + assert response.status_code == status.HTTP_200_OK + + +def test_create_with_unavailable_item(dbsession, client, base_rentses_url, item_fixture): + """Попытка создания сессии при недоступном предмете.""" + with ( + check_object_creation(RentalSession, dbsession, num_of_creations=0), + check_object_update(item_fixture, dbsession, is_available=False) + ): + response = client.post(f'{base_rentses_url}/{item_fixture.type_id}') + assert response.status_code == status.HTTP_404_NOT_FOUND + + +def test_create_with_type_no_items(dbsession, client, base_rentses_url, item_type_fixture): + """Тест на создание сессии аренды, когда тип существует, но не имеет предметов.""" + type_id = item_type_fixture[1].id + with check_object_creation(RentalSession, dbsession, num_of_creations=0): response = client.post(f'{base_rentses_url}/{type_id}') - assert response.status_code == right_status_code + assert response.status_code == status.HTTP_404_NOT_FOUND + + +<<<<<<< Updated upstream +======= +def test_create_with_nonexistent_type(dbsession, client, base_rentses_url, nonexistent_type_id): + """Тест на создание сессии при несуществующем типе предмета.""" + with check_object_creation(RentalSession, dbsession, num_of_creations=0): + response = client.post(f'{base_rentses_url}/{nonexistent_type_id}') + assert response.status_code == status.HTTP_404_NOT_FOUND +def test_create_with_existing_blocking_session(client, base_rentses_url, blocking_session): + """ + Проверяет, что нельзя создать новую сессию для типа, если у пользователя уже есть + сессия в статусе RESERVED/ACTIVE/OVERDUE для этого типа. + """ + response = client.post(f"{base_rentses_url}/{blocking_session.id}") + assert response.status_code == status.HTTP_409_CONFLICT + +>>>>>>> Stashed changes @pytest.mark.usefixtures('expire_mock') @pytest.mark.parametrize( 'invalid_itemtype_id, right_status_code', @@ -99,6 +140,7 @@ def test_create_with_invalid_id(dbsession, client, base_rentses_url, invalid_ite @pytest.mark.usefixtures('expiration_time_mock') +<<<<<<< Updated upstream def test_create_and_expire(dbsession, client, base_rentses_url, item_fixture): """Проверка правильного срабатывания check_session_expiration.""" item_fixture.is_available = True @@ -109,6 +151,23 @@ def test_create_and_expire(dbsession, client, base_rentses_url, item_fixture): assert ( RentalSession.get(id=response.json()['id'], session=dbsession).status == RentStatus.EXPIRED ), 'Убедитесь, что по истечение RENTAL_SESSION_EXPIRY, аренда переходит в RentStatus.CANCELED!' +======= +def test_create_and_expire(client, base_rentses_url, expired_reserved_session): + """ + Проверяет, что просроченная сессия (RESERVED) переходит в EXPIRED при следующем вызове check_sessions_expiration. + """ + session_id = expired_reserved_session + response = client.get(f"{base_rentses_url}/{session_id}") + assert response.status_code == status.HTTP_200_OK + assert response.json()["status"] == RentStatus.EXPIRED + + +# Тест на начало уже активной сессии +def test_start_already_active_session(dbsession, client, base_rentses_url, active_rentses): + """Проверка, что нельзя начать уже активную сессию.""" + response = client.patch(f'{base_rentses_url}/{active_rentses.id}/start') + assert response.status_code == status.HTTP_403_FORBIDDEN +>>>>>>> Stashed changes # Tests for PATCH /rental-sessions/{session_id}/start @@ -192,7 +251,7 @@ def test_return_inactive(dbsession, client, rentses, base_rentses_url): ], ) def test_return_with_strike( - dbsession, client, base_rentses_url, active_rentses, with_strike, strike_reason, right_status_code, strike_created + dbsession, client, base_rentses_url, active_rentses, authlib_user, with_strike, strike_reason, right_status_code, strike_created ): """Проверяет завершение аренды со страйком.""" query_dict = dict() @@ -201,18 +260,41 @@ def test_return_with_strike( if strike_reason is not None: query_dict['strike_reason'] = strike_reason num_of_creations = 1 if strike_created else 0 +<<<<<<< Updated upstream with check_object_creation(Strike, dbsession, num_of_creations): response = client.patch(f'{base_rentses_url}/{active_rentses.id}/return', params=query_dict) assert response.status_code == right_status_code - - -def test_return_with_set_end_ts(dbsession, client, base_rentses_url, active_rentses): +======= + session_id = active_rentses.id + admin_id = authlib_user["id"] + with check_object_creation(Strike, dbsession, num_of_creations): + response = client.patch(f'{base_rentses_url}/{active_rentses.id}/return', params=query_dict) + assert response.status_code == right_status_code + dbsession.refresh(active_rentses) + if right_status_code == status.HTTP_200_OK: + assert active_rentses.status == RentStatus.RETURNED + assert active_rentses.item.is_available is True + if strike_created: + strike = active_rentses.strike + assert strike is not None, "Страйк должен быть создан" + assert strike.user_id == active_rentses.user_id + assert strike.admin_id == admin_id + expected_reason = strike_reason if strike_reason is not None else "" + assert strike.reason == expected_reason + assert strike.session_id == session_id + else: + assert active_rentses.strike is None, "Страйк не должен быть создан" + else: + assert active_rentses.status == RentStatus.ACTIVE + assert active_rentses.item.is_available is False + assert active_rentses.strike is None +>>>>>>> Stashed changes + + +def test_return_with_set_end_ts(dbsession, client, base_rentses_url, active_rentses_with_end_ts): """Проверяет, что при обновлении RentalSession с end_ts не None сохраняется именно существующий, а не создается новый.""" - active_rentses.end_ts = datetime.datetime.now(tz=datetime.timezone.utc) - dbsession.add(active_rentses) - dbsession.commit() - with check_object_update(active_rentses, dbsession, end_ts=active_rentses.end_ts): - response = client.patch(f'{base_rentses_url}/{active_rentses.id}/return') + with check_object_update(active_rentses_with_end_ts, dbsession, end_ts=active_rentses_with_end_ts.end_ts): + response = client.patch(f'{base_rentses_url}/{active_rentses_with_end_ts.id}/return') assert response.status_code == status.HTTP_200_OK @@ -222,6 +304,10 @@ def test_return_with_set_end_ts(dbsession, client, base_rentses_url, active_rent 'session_id, right_status_code', [ (0, status.HTTP_200_OK), +<<<<<<< Updated upstream +======= + (1, status.HTTP_404_NOT_FOUND), +>>>>>>> Stashed changes ('hihi', status.HTTP_422_UNPROCESSABLE_ENTITY), ('ha-ha', status.HTTP_422_UNPROCESSABLE_ENTITY), ('he-he/hoho', status.HTTP_404_NOT_FOUND), @@ -377,6 +463,52 @@ def test_update_payload(dbsession, rentses, client, base_rentses_url, payload, r assert is_really_updated == update_in_db +<<<<<<< Updated upstream +======= +def test_regular_user_cannot_update_rental_session(dbsession, client, rentses, another_authlib_user): + """ + Проверка, что обычный пользователь (не админ) не может обновить сессию. + Ожидается 403 Forbidden, данные в БД не должны измениться. + """ + + def mock_unionauth_call(self, request): + required_scopes = set(self.scopes or []) + user_scopes = set(another_authlib_user.get('scopes', [])) + if required_scopes and not required_scopes.issubset(user_scopes): + raise HTTPException(status_code=403, detail="Not enough permissions") + return another_authlib_user + + with patch('auth_lib.fastapi.UnionAuth.__call__', new=mock_unionauth_call): + old_end_ts = rentses.end_ts + payload = {"end_ts": "2026-12-31T23:59:59.000Z"} + with check_object_update(rentses, dbsession, end_ts=old_end_ts): + response = client.patch(f"/rental-sessions/{rentses.id}", json=payload) + assert response.status_code == status.HTTP_403_FORBIDDEN + + +def test_admin_can_update_any_rental_session(dbsession, client, another_rentses, authlib_user): + """ + Проверка, что администратор может обновить сессию другого пользователя. + Данные в БД должны измениться. + """ + + def mock_unionauth_call(self, request): + required_scopes = set(self.scopes or []) + user_scopes = set(authlib_user.get('scopes', [])) + if required_scopes and not required_scopes.issubset(user_scopes): + raise HTTPException(status_code=403, detail="Not enough permissions") + return authlib_user + + with patch('auth_lib.fastapi.UnionAuth.__call__', new=mock_unionauth_call): + payload = {"end_ts": "2026-12-31T23:59:59.000Z"} + # Преобразуем строку в naive datetime (убираем временную зону) + expected_end_ts = datetime.datetime.fromisoformat(payload["end_ts"].replace('Z', '+00:00')).replace(tzinfo=None) + with check_object_update(another_rentses, dbsession, end_ts=expected_end_ts): + response = client.patch(f"/rental-sessions/{another_rentses.id}", json=payload) + assert response.status_code == status.HTTP_200_OK + + +>>>>>>> Stashed changes @pytest.mark.usefixtures('dbsession', 'rentses') @pytest.mark.parametrize( 'session_id, right_status_code', @@ -500,7 +632,11 @@ def test_cancel_success(dbsession, client, base_rentses_url, rentses): ('he-he/hoho', status.HTTP_404_NOT_FOUND), (-1, status.HTTP_404_NOT_FOUND), ('', status.HTTP_404_NOT_FOUND), +<<<<<<< Updated upstream ('-1?hoho=hihi', status.HTTP_405_METHOD_NOT_ALLOWED), +======= + ('-1?hoho=hihi', status.HTTP_404_NOT_FOUND), +>>>>>>> Stashed changes ], ids=['text', 'hyphen', 'trailing_slash', 'negative_num', 'empty', 'excess_query'], ) From 1a32c9cf09d919a8f2b6d96e646a1e8bfa8eca5c Mon Sep 17 00:00:00 2001 From: Georgon Date: Fri, 13 Mar 2026 10:52:24 +0300 Subject: [PATCH 2/4] Fix for tests rental_session --- rental_backend/routes/rental_session.py | 24 --------- tests/conftest.py | 17 +----- tests/test_routes/test_rental_session.py | 69 ++---------------------- 3 files changed, 4 insertions(+), 106 deletions(-) diff --git a/rental_backend/routes/rental_session.py b/rental_backend/routes/rental_session.py index e7e8ccc..bc9de1f 100644 --- a/rental_backend/routes/rental_session.py +++ b/rental_backend/routes/rental_session.py @@ -85,11 +85,7 @@ async def check_sessions_overdue(): ) async def create_rental_session( item_type_id: int, -<<<<<<< Updated upstream - user=Depends(UnionAuth(scopes=["rental.session.create"], enable_userdata=True)), -======= user=Depends(UnionAuth(scopes=["rental.session.create"], enable_userdata=True)), ->>>>>>> Stashed changes ): """ Создает новую сессию аренды для указанного типа предмета. @@ -180,13 +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( -<<<<<<< Updated upstream - 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"])) ->>>>>>> Stashed changes ): """ Starts a rental session, changing its status to ACTIVE. @@ -240,11 +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."), -<<<<<<< Updated upstream - user=Depends(UnionAuth(scopes=["rental.session.admin"])), -======= user=Depends(UnionAuth(scopes=["rental.session.admin"])) ->>>>>>> Stashed changes ): """ Ends a rental session, changing its status to RETURNED. Issues a strike if specified. @@ -293,11 +281,7 @@ async def accept_end_rental_session( session=db.session, **strike_info.model_dump(), create_ts=datetime.datetime.now(tz=datetime.timezone.utc) ) -<<<<<<< Updated upstream - ended_session.strike_id = new_strike.id -======= ended_session.strike = new_strike ->>>>>>> Stashed changes db.session.commit() ActionLogger.log_event( @@ -416,11 +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 для получения сессий"), -<<<<<<< Updated upstream - user=Depends(UnionAuth(scopes=["rental.session.admin"])), -======= user=Depends(UnionAuth(scopes=["rental.session.admin"])), ->>>>>>> Stashed changes ): """ Retrieves a list of rental sessions with optional status filtering. @@ -565,11 +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( -<<<<<<< Updated upstream - 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"])) ->>>>>>> Stashed changes ): """ Updates the information of a rental session. diff --git a/tests/conftest.py b/tests/conftest.py index ca159e2..f6aa5b8 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -93,23 +93,16 @@ def authlib_user(): return { "auth_methods": ["string"], "session_scopes": [{"id": 0, "name": "string"}], -<<<<<<< Updated upstream - "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 ->>>>>>> Stashed changes "indirect_groups": [0], "groups": [0], "id": 0, "email": "string", -<<<<<<< Updated upstream -======= "userdata": [ {"param": "Полное имя", "value": "Тестов Тест"}, {"param": "Номер телефона", "value": "+79991234567"} ], ->>>>>>> Stashed changes } @@ -122,12 +115,8 @@ def another_authlib_user(): return { "auth_methods": ["string"], "session_scopes": [{"id": 0, "name": "string"}], -<<<<<<< Updated upstream - "user_scopes": [{"id": 0, "name": "string"}], -======= "user_scopes": [], "scopes": [], ->>>>>>> Stashed changes "indirect_groups": [0], "groups": [0], "id": 1, @@ -367,7 +356,7 @@ def items_with_same_type(dbsession, item_types) -> List[Item]: @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 @@ -410,11 +399,7 @@ def another_rentses(dbsession, items_with_same_type, another_authlib_user) -> Re item_id=renting_item.id, status=RentStatus.RESERVED, ) -<<<<<<< Updated upstream - Item.update(id=renting_item.id, session=dbsession, is_available=False) -======= renting_item.is_available = False ->>>>>>> Stashed changes dbsession.add(rent) dbsession.commit() return rent diff --git a/tests/test_routes/test_rental_session.py b/tests/test_routes/test_rental_session.py index d7b2247..709a36e 100644 --- a/tests/test_routes/test_rental_session.py +++ b/tests/test_routes/test_rental_session.py @@ -5,7 +5,8 @@ import pytest from sqlalchemy import desc from starlette import status - +from unittest.mock import patch +from fastapi import HTTPException from rental_backend.models.base import BaseDbModel from rental_backend.models.db import Item, ItemType, RentalSession, Strike from rental_backend.routes.rental_session import rental_session @@ -42,40 +43,8 @@ def check_object_update(model_instance: BaseDbModel, session, **final_fields): # Tests for POST /rental-sessions/{item_type_id} -<<<<<<< Updated upstream -@pytest.mark.usefixtures('expire_mock') -@pytest.mark.parametrize( - 'start_item_avail, end_item_avail, itemtype_list_ind, right_status_code, num_of_creations', - [ - (True, False, 0, status.HTTP_200_OK, 1), - (False, False, 0, status.HTTP_404_NOT_FOUND, 0), - (True, True, 1, status.HTTP_404_NOT_FOUND, 0), - ], - ids=['avail_item', 'not_avail_item', 'unexisting_itemtype'], -) -def test_create_with_diff_item( - dbsession, - client, - item_fixture, - base_rentses_url, - start_item_avail, - end_item_avail, - itemtype_list_ind, - right_status_code, - num_of_creations, -): - """Проверка старта аренды разных Item от разных ItemType.""" - item_fixture.is_available = start_item_avail - dbsession.add(item_fixture) - dbsession.commit() - try: - type_id = ItemType.query(session=dbsession).all()[itemtype_list_ind].id - except IndexError: - type_id = ItemType.query(session=dbsession).order_by(desc('id'))[0].id + 1 -======= def test_create_with_available_item(dbsession, client, base_rentses_url, available_item): """Тест на успешное создание сессии при доступном предмете.""" ->>>>>>> Stashed changes with ( check_object_creation(RentalSession, dbsession, num_of_creations=1), check_object_update(available_item, dbsession, is_available=False) @@ -102,8 +71,6 @@ def test_create_with_type_no_items(dbsession, client, base_rentses_url, item_typ assert response.status_code == status.HTTP_404_NOT_FOUND -<<<<<<< Updated upstream -======= def test_create_with_nonexistent_type(dbsession, client, base_rentses_url, nonexistent_type_id): """Тест на создание сессии при несуществующем типе предмета.""" with check_object_creation(RentalSession, dbsession, num_of_creations=0): @@ -119,7 +86,6 @@ def test_create_with_existing_blocking_session(client, base_rentses_url, blockin response = client.post(f"{base_rentses_url}/{blocking_session.id}") assert response.status_code == status.HTTP_409_CONFLICT ->>>>>>> Stashed changes @pytest.mark.usefixtures('expire_mock') @pytest.mark.parametrize( 'invalid_itemtype_id, right_status_code', @@ -140,18 +106,6 @@ def test_create_with_invalid_id(dbsession, client, base_rentses_url, invalid_ite @pytest.mark.usefixtures('expiration_time_mock') -<<<<<<< Updated upstream -def test_create_and_expire(dbsession, client, base_rentses_url, item_fixture): - """Проверка правильного срабатывания check_session_expiration.""" - item_fixture.is_available = True - dbsession.add(item_fixture) - dbsession.commit() - response = client.post(f'{base_rentses_url}/{item_fixture.type_id}') - assert response.status_code == status.HTTP_200_OK - assert ( - RentalSession.get(id=response.json()['id'], session=dbsession).status == RentStatus.EXPIRED - ), 'Убедитесь, что по истечение RENTAL_SESSION_EXPIRY, аренда переходит в RentStatus.CANCELED!' -======= def test_create_and_expire(client, base_rentses_url, expired_reserved_session): """ Проверяет, что просроченная сессия (RESERVED) переходит в EXPIRED при следующем вызове check_sessions_expiration. @@ -167,7 +121,6 @@ def test_start_already_active_session(dbsession, client, base_rentses_url, activ """Проверка, что нельзя начать уже активную сессию.""" response = client.patch(f'{base_rentses_url}/{active_rentses.id}/start') assert response.status_code == status.HTTP_403_FORBIDDEN ->>>>>>> Stashed changes # Tests for PATCH /rental-sessions/{session_id}/start @@ -260,11 +213,6 @@ def test_return_with_strike( if strike_reason is not None: query_dict['strike_reason'] = strike_reason num_of_creations = 1 if strike_created else 0 -<<<<<<< Updated upstream - with check_object_creation(Strike, dbsession, num_of_creations): - response = client.patch(f'{base_rentses_url}/{active_rentses.id}/return', params=query_dict) - assert response.status_code == right_status_code -======= session_id = active_rentses.id admin_id = authlib_user["id"] with check_object_creation(Strike, dbsession, num_of_creations): @@ -288,7 +236,6 @@ def test_return_with_strike( assert active_rentses.status == RentStatus.ACTIVE assert active_rentses.item.is_available is False assert active_rentses.strike is None ->>>>>>> Stashed changes def test_return_with_set_end_ts(dbsession, client, base_rentses_url, active_rentses_with_end_ts): @@ -304,10 +251,7 @@ def test_return_with_set_end_ts(dbsession, client, base_rentses_url, active_rent 'session_id, right_status_code', [ (0, status.HTTP_200_OK), -<<<<<<< Updated upstream -======= - (1, status.HTTP_404_NOT_FOUND), ->>>>>>> Stashed changes + #(1, status.HTTP_404_NOT_FOUND), ('hihi', status.HTTP_422_UNPROCESSABLE_ENTITY), ('ha-ha', status.HTTP_422_UNPROCESSABLE_ENTITY), ('he-he/hoho', status.HTTP_404_NOT_FOUND), @@ -463,8 +407,6 @@ def test_update_payload(dbsession, rentses, client, base_rentses_url, payload, r assert is_really_updated == update_in_db -<<<<<<< Updated upstream -======= def test_regular_user_cannot_update_rental_session(dbsession, client, rentses, another_authlib_user): """ Проверка, что обычный пользователь (не админ) не может обновить сессию. @@ -508,7 +450,6 @@ def mock_unionauth_call(self, request): assert response.status_code == status.HTTP_200_OK ->>>>>>> Stashed changes @pytest.mark.usefixtures('dbsession', 'rentses') @pytest.mark.parametrize( 'session_id, right_status_code', @@ -632,11 +573,7 @@ def test_cancel_success(dbsession, client, base_rentses_url, rentses): ('he-he/hoho', status.HTTP_404_NOT_FOUND), (-1, status.HTTP_404_NOT_FOUND), ('', status.HTTP_404_NOT_FOUND), -<<<<<<< Updated upstream - ('-1?hoho=hihi', status.HTTP_405_METHOD_NOT_ALLOWED), -======= ('-1?hoho=hihi', status.HTTP_404_NOT_FOUND), ->>>>>>> Stashed changes ], ids=['text', 'hyphen', 'trailing_slash', 'negative_num', 'empty', 'excess_query'], ) From 1c4a2ddea48060cc3126294c357d27ae46ce4c1f Mon Sep 17 00:00:00 2001 From: Georgon Date: Sat, 14 Mar 2026 10:22:55 +0300 Subject: [PATCH 3/4] Fix test_item --- tests/conftest.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index f6aa5b8..cbc9a08 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -276,12 +276,12 @@ def items_with_types(dbsession): 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() + # for i in item_types: + # for item in i.items: + # dbsession.delete(item) + # dbsession.flush() + # dbsession.delete(i) + # dbsession.commit() @pytest.fixture() From e2dbf86f251929a728bf602b713ba844cfc06177 Mon Sep 17 00:00:00 2001 From: Georgon Date: Sat, 14 Mar 2026 10:25:48 +0300 Subject: [PATCH 4/4] fix test_item --- tests/conftest.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index cbc9a08..7797b40 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -276,12 +276,6 @@ def items_with_types(dbsession): 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()