Первый коммит
This commit is contained in:
193
tests/database/test_user_stats.py
Normal file
193
tests/database/test_user_stats.py
Normal file
@@ -0,0 +1,193 @@
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
import pytest
|
||||
from sqlalchemy import select, Sequence
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from database import User, UserMessage, BotDatabase
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
class TestUserStatistics:
|
||||
"""Тесты для статистики пользователей с полной строгой типизацией"""
|
||||
|
||||
async def test_add_user(self, test_db: BotDatabase, test_session: AsyncSession) -> None:
|
||||
"""
|
||||
Тест добавления пользователя.
|
||||
Проверяет, что пользователь создаётся с правильными данными и статусом 'active'.
|
||||
"""
|
||||
user_id: int = 111222333
|
||||
|
||||
await test_db.add_user(
|
||||
user_id=user_id,
|
||||
username="new_user",
|
||||
full_name="New User"
|
||||
)
|
||||
|
||||
user: User | None = await test_session.get(User, user_id)
|
||||
assert user is not None
|
||||
assert user.username == "new_user"
|
||||
assert user.status.value == "active"
|
||||
|
||||
async def test_add_message_creates_user(
|
||||
self, test_db: BotDatabase, test_session: AsyncSession
|
||||
) -> None:
|
||||
"""
|
||||
Тест, что добавление сообщения создаёт пользователя, если его нет.
|
||||
Проверяет, что пользователь и сообщение корректно создаются.
|
||||
"""
|
||||
user_id: int = 111222333
|
||||
|
||||
await test_db.add_message(
|
||||
user_id=user_id,
|
||||
message_text="Тестовое сообщение"
|
||||
)
|
||||
|
||||
user: User | None = await test_session.get(User, user_id)
|
||||
assert user is not None
|
||||
assert user.status.value == "active"
|
||||
|
||||
stmt = select(UserMessage).where(UserMessage.user_id == user_id)
|
||||
result = await test_session.execute(stmt)
|
||||
messages: Sequence[UserMessage] = result.scalars().all()
|
||||
|
||||
assert len(messages) == 1
|
||||
assert messages[0].message_text == "Тестовое сообщение"
|
||||
|
||||
async def test_message_stats_calculation(
|
||||
self, test_db: BotDatabase, test_user_with_messages: int
|
||||
) -> None:
|
||||
"""
|
||||
Тест расчёта статистики сообщений пользователя.
|
||||
Проверяет корректность статистики по дням, неделям, месяцам и общему количеству сообщений.
|
||||
"""
|
||||
user_id: int = test_user_with_messages
|
||||
|
||||
# Получаем статистику
|
||||
day: int
|
||||
week: int
|
||||
month: int
|
||||
total: int
|
||||
day, week, month, total = await test_db.get_message_stats(user_id)
|
||||
|
||||
assert total >= 10, f"Ожидается минимум 10 сообщений, получено {total}"
|
||||
assert day >= 0
|
||||
assert week >= 0
|
||||
assert month >= 0
|
||||
assert total >= 0
|
||||
assert day <= week <= month <= total
|
||||
|
||||
async def test_message_stats_with_dates(
|
||||
self, test_db: BotDatabase, test_user: int
|
||||
) -> None:
|
||||
"""
|
||||
Тест статистики с конкретными известными датами сообщений.
|
||||
Проверяет подсчёт сообщений за день, неделю, месяц и общее количество.
|
||||
"""
|
||||
user_id: int = test_user
|
||||
now: datetime = datetime.now(timezone.utc)
|
||||
|
||||
# Очищаем старые сообщения
|
||||
async with test_db.session_factory() as session:
|
||||
stmt = select(UserMessage).where(UserMessage.user_id == user_id)
|
||||
result = await session.execute(stmt)
|
||||
old_messages: Sequence[UserMessage] = result.scalars().all()
|
||||
for msg in old_messages:
|
||||
await session.delete(msg)
|
||||
await session.commit()
|
||||
|
||||
# Создаём сообщения с фиксированными датами
|
||||
test_messages: list[tuple[datetime, str]] = [
|
||||
(now - timedelta(days=45), "45 дней назад"),
|
||||
(now - timedelta(days=30), "30 дней назад"),
|
||||
(now - timedelta(days=15), "15 дней назад"),
|
||||
(now - timedelta(days=7), "7 дней назад"),
|
||||
(now - timedelta(days=3), "3 дня назад"),
|
||||
(now - timedelta(hours=6), "6 часов назад"),
|
||||
(now, "сейчас")
|
||||
]
|
||||
|
||||
for date, text in test_messages:
|
||||
await test_db.add_message(user_id, text, date)
|
||||
|
||||
day: int
|
||||
week: int
|
||||
month: int
|
||||
total: int
|
||||
day, week, month, total = await test_db.get_message_stats(user_id)
|
||||
|
||||
assert total == 7, f"Ожидалось 7 сообщений, получено {total}"
|
||||
|
||||
day_start: datetime = now.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
expected_day: int = sum(1 for date, _ in test_messages if date >= day_start)
|
||||
assert day == expected_day, f"За день: ожидалось {expected_day}, получено {day}"
|
||||
|
||||
monday: datetime = (now - timedelta(days=now.weekday())).replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
expected_week: int = sum(1 for date, _ in test_messages if date >= monday)
|
||||
assert week == expected_week, f"За неделю: ожидалось {expected_week}, получено {week}"
|
||||
|
||||
month_start: datetime = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
|
||||
expected_month: int = sum(1 for date, _ in test_messages if date >= month_start)
|
||||
assert month == expected_month, f"За месяц: ожидалось {expected_month}, получено {month}"
|
||||
|
||||
async def test_empty_user_stats(self, test_db: BotDatabase) -> None:
|
||||
"""
|
||||
Тест статистики для пользователя без сообщений.
|
||||
Все значения должны быть равны нулю.
|
||||
"""
|
||||
user_id: int = 0o00111222
|
||||
await test_db.add_user(user_id, "empty_user", "Empty User")
|
||||
|
||||
day: int
|
||||
week: int
|
||||
month: int
|
||||
total: int
|
||||
day, week, month, total = await test_db.get_message_stats(user_id)
|
||||
|
||||
assert day == 0
|
||||
assert week == 0
|
||||
assert month == 0
|
||||
assert total == 0
|
||||
|
||||
async def test_user_management(self, test_db: BotDatabase) -> None:
|
||||
"""
|
||||
Тест управления пользователями.
|
||||
Проверяет добавление, назначение админа, бан/разбан и возврат статуса пользователя.
|
||||
"""
|
||||
user_id: int = 555666777
|
||||
|
||||
# Добавление пользователя
|
||||
await test_db.add_user(user_id, "managed_user", "Managed User")
|
||||
|
||||
async with test_db.session_factory() as session:
|
||||
user: User | None = await session.get(User, user_id)
|
||||
assert user is not None
|
||||
assert user.status.value == "active"
|
||||
|
||||
# Назначение админом
|
||||
await test_db.set_admin(user_id, True)
|
||||
async with test_db.session_factory() as session:
|
||||
user = await session.get(User, user_id)
|
||||
assert user is not None
|
||||
assert user.status.value == "admin"
|
||||
|
||||
# Бан пользователя
|
||||
await test_db.ban_user(user_id)
|
||||
async with test_db.session_factory() as session:
|
||||
user = await session.get(User, user_id)
|
||||
assert user is not None
|
||||
assert user.status.value == "banned"
|
||||
|
||||
# Разбан
|
||||
await test_db.unban_user(user_id)
|
||||
async with test_db.session_factory() as session:
|
||||
user = await session.get(User, user_id)
|
||||
assert user is not None
|
||||
assert user.status.value == "active"
|
||||
|
||||
# Снятие админки
|
||||
await test_db.set_admin(user_id, False)
|
||||
async with test_db.session_factory() as session:
|
||||
user = await session.get(User, user_id)
|
||||
assert user is not None
|
||||
assert user.status.value == "active"
|
||||
Reference in New Issue
Block a user