import asyncio from datetime import datetime, timedelta, timezone from sqlalchemy import select, update from src.core.database import async_session_maker from src.core.models import Winner, WinnerVerification, User from src.core.services import UserService, LotteryService, ParticipationService from src.core.redraw_services import redraw_unclaimed from src.core.chat_services import ChatSettingsService, BanService, ChatPermissionService from src.core.user_management import UserManagementService async def run(call, *args): async with async_session_maker() as session: return await call(session, *args) async def test_parallel_redraw_replaces_only_expired_unclaimed_prizes_once(): async with async_session_maker() as session: users = [await UserService.get_or_create_user(session, 800 + i) for i in range(4)] lottery = await LotteryService.create_lottery(session, "Draw", "", ["First", "Second"], users[0].id) lottery_id = lottery.id for user in users: await ParticipationService.add_participant(session, lottery_id, user.id) await LotteryService.conduct_draw(session, lottery_id) winners = await LotteryService.get_winners(session, lottery_id) claimed_id = winners[0].id winners[0].is_claimed = True winners[1].is_notified = True winners[1].created_at = datetime.now(timezone.utc) - timedelta(days=2) await session.commit() results = await asyncio.gather(*(run(redraw_unclaimed, lottery_id) for _ in range(5))) assert sum(len(result) for result in results) == 1 async with async_session_maker() as session: remaining = await LotteryService.get_winners(session, lottery_id) assert len(remaining) == 2 assert (await session.get(Winner, claimed_id)).is_claimed assert {winner.prize for winner in remaining} == {"First", "Second"} async def test_chat_settings_created_once_under_concurrency(): settings = await asyncio.gather(*(run(ChatSettingsService.get_or_create_settings) for _ in range(8))) assert {item.id for item in settings} == {1} async def test_both_admin_interfaces_clear_chat_bans(): async with async_session_maker() as session: admin = await UserService.get_or_create_user(session, 850) user = await UserService.get_or_create_user(session, 851) user.is_registered = True await session.commit() await BanService.ban_user(session, user.id, user.telegram_id, admin.id) assert not (await ChatPermissionService.can_send_message(session, 851))[0] await UserManagementService.unban_user_in_chat(session, user.id) assert (await ChatPermissionService.can_send_message(session, 851))[0] await BanService.ban_user(session, user.id, user.telegram_id, admin.id) assert await BanService.unban_user(session, 851) assert (await ChatPermissionService.can_send_message(session, 851))[0] async def test_lottery_delete_includes_verification_children(): async with async_session_maker() as session: user = await UserService.get_or_create_user(session, 870) lottery = await LotteryService.create_lottery(session, "Draw", "", ["Prize"], user.id) await ParticipationService.add_participant(session, lottery.id, user.id) await LotteryService.conduct_draw(session, lottery.id) winner = (await LotteryService.get_winners(session, lottery.id))[0] session.add(WinnerVerification(winner_id=winner.id, verification_token="test-token", expires_at=datetime.now(timezone.utc) + timedelta(days=1))) await session.commit() assert await LotteryService.delete_lottery(session, lottery.id) assert not list((await session.scalars(select(WinnerVerification))).all())