Stabilize staff concurrency and premium emoji; enable verified Drone deployment
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
2026-09-13 19:48:41 +09:00
parent 733298bf06
commit cb35bb12e3
86 changed files with 2993 additions and 2455 deletions

90
tests/test_dispatcher.py Normal file
View File

@@ -0,0 +1,90 @@
from datetime import datetime, timezone
from aiogram import Bot
from aiogram.client.session.base import BaseSession
from aiogram.types import Update, Message, User as TelegramUser, Chat, CallbackQuery
from sqlalchemy import select
from src.core.database import async_session_maker
from src.core.models import User
from src.core.services import UserService
class TelegramStub(BaseSession):
def __init__(self):
super().__init__()
self.calls = []
async def close(self):
pass
async def make_request(self, bot, method, timeout=None):
self.calls.append(method)
if method.__api_method__ in {"answerCallbackQuery", "deleteMessage"}:
return True
return Message(message_id=100, date=datetime.now(timezone.utc),
chat=Chat(id=int(getattr(method, "chat_id", 1)), type="private"),
from_user=TelegramUser(id=bot.id, is_bot=True, first_name="Bot"), text=getattr(method, "text", ""))
async def stream_content(self, url, headers=None, timeout=30, chunk_size=65536, raise_for_status=True):
yield b""
def event(user_id, text=None, callback_data=None):
actor = TelegramUser(id=user_id, is_bot=False, first_name="Human")
msg = Message(message_id=1, date=datetime.now(timezone.utc), chat=Chat(id=user_id, type="private"),
from_user=actor if text else TelegramUser(id=123456, is_bot=True, first_name="Bot"), text=text or "Menu")
if callback_data:
return Update(update_id=1, callback_query=CallbackQuery(id="test", from_user=actor, chat_instance="private",
message=msg, data=callback_data))
return Update(update_id=1, message=msg)
async def dispatch(update):
import main
if not main.dp.sub_routers:
main.configure_dispatcher()
stub = TelegramStub()
bot = Bot("123456:TEST_TOKEN_FOR_ISOLATED_TESTS", session=stub)
await main.dp.feed_update(bot, update)
return stub.calls
async def test_actual_back_button_never_registers_bot_as_user():
calls = await dispatch(event(701, callback_data="back_to_main"))
async with async_session_maker() as session:
ids = (await session.scalars(select(User.telegram_id))).all()
assert ids == [701]
assert any((getattr(call, "text", "") or "").startswith("👋") for call in calls)
async def test_actual_cashier_menu_available_to_cashier_but_admin_menu_denied():
calls = await dispatch(event(900002, text="/cashier"))
assert any("💼 Касса" in (getattr(call, "text", "") or "") for call in calls)
calls = await dispatch(event(900002, callback_data="admin_participants"))
assert any("Недостаточно прав" in (getattr(call, "text", "") or "") for call in calls)
async def test_actual_forged_account_callback_is_denied_before_mutation():
calls = await dispatch(event(702, callback_data="add_to_lottery_1"))
assert any("Недостаточно прав" in (getattr(call, "text", "") or "") for call in calls)
async def test_assigned_admin_can_open_participant_management():
async with async_session_maker() as session:
user = await UserService.get_or_create_user(session, 703)
user.is_admin = True
await session.commit()
calls = await dispatch(event(703, callback_data="admin_participants"))
assert any(getattr(call, "reply_markup", None) for call in calls)
assert not any("Недостаточно прав" in (getattr(call, "text", "") or "") for call in calls)
async def test_registration_cancel_clears_state():
calls = await dispatch(event(704, text="/register"))
assert any("Никнейм" in (getattr(call, "text", "") or "") or "никнейм" in (getattr(call, "text", "") or "") for call in calls)
import main
state = main.dp.fsm.get_context(bot=Bot("123456:TEST_TOKEN_FOR_ISOLATED_TESTS"), chat_id=704, user_id=704)
assert (await state.get_state()).endswith("waiting_for_nickname")
await dispatch(event(704, text="/cancel"))
assert await state.get_state() is None