Files
tgex-backend/tests/test_views.py
2025-12-08 22:53:31 +03:00

300 lines
10 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Тесты работы с просмотрами рекламных постов."""
import datetime
import pytest
from src import domain, dto, usecase
from tests.conftest import MockDatabase
@pytest.mark.asyncio
async def test_update_views_manually(usecases: usecase.Usecase, mock_database: MockDatabase) -> None:
"""Ручное обновление просмотров создаёт снимок и обновляет закуп."""
user = domain.User(telegram_id=123456, username='testuser')
await mock_database.create_user(user)
target_channel = domain.TargetChannel(
telegram_id=-1001234567890,
title='Target Channel',
username='targetchannel',
user_id=user.id,
status=domain.TargetChannelStatus.ACTIVE,
)
await mock_database.upsert_target_channel(target_channel)
external_channel = domain.ExternalChannel(
telegram_id=-1009876543210,
title='External Channel',
username='externalchannel',
description=None,
subscribers_count=40000,
user_id=user.id,
)
await mock_database.create_external_channel(external_channel)
creative = domain.Creative(
name='Test Creative',
text='Test text',
target_channel_id=target_channel.id,
user_id=user.id,
status=domain.CreativeStatus.ACTIVE,
)
await mock_database.create_creative(creative)
placement = domain.Placement(
target_channel_id=target_channel.id,
external_channel_id=external_channel.id,
creative_id=creative.id,
user_id=user.id,
placement_date=datetime.datetime.now(datetime.UTC),
invite_link='https://t.me/+link3',
invite_link_type=domain.InviteLinkType.PUBLIC,
status=domain.PlacementStatus.ACTIVE,
ad_post_url='https://t.me/externalchannel/456',
)
await mock_database.create_placement(placement)
input_data = dto.UpdateViewsManuallyInput(
placement_id=placement.id,
user_id=user.id,
views_count=15000,
)
result = await usecases.update_views_manually(input=input_data)
# Проверяем возвращённый результат
assert result.views_count == 15000
assert result.views_availability == domain.PostViewsAvailability.MANUAL
assert result.last_views_fetch_at is not None
# Проверяем, что создана история просмотров
histories = [h for h in mock_database.placement_views_histories.values() if h.placement_id == placement.id]
assert len(histories) == 1
assert histories[0].views_count == 15000
# Проверяем, что закуп обновлён
updated_placement = await mock_database.get_placement(user.id, placement.id)
assert updated_placement is not None
assert updated_placement.views_count == 15000
assert updated_placement.views_availability == domain.PostViewsAvailability.MANUAL
@pytest.mark.asyncio
async def test_get_views_history_empty(usecases: usecase.Usecase, mock_database: MockDatabase) -> None:
"""Получение истории просмотров для закупа без снимков возвращает пустой список."""
user = domain.User(telegram_id=123456, username='testuser')
await mock_database.create_user(user)
target_channel = domain.TargetChannel(
telegram_id=-1001234567890,
title='Target Channel',
username='targetchannel',
user_id=user.id,
status=domain.TargetChannelStatus.ACTIVE,
)
await mock_database.upsert_target_channel(target_channel)
external_channel = domain.ExternalChannel(
telegram_id=-1009876543210,
title='External Channel',
username='externalchannel',
description=None,
subscribers_count=25000,
user_id=user.id,
)
await mock_database.create_external_channel(external_channel)
creative = domain.Creative(
name='Test Creative',
text='Test text',
target_channel_id=target_channel.id,
user_id=user.id,
status=domain.CreativeStatus.ACTIVE,
)
await mock_database.create_creative(creative)
placement = domain.Placement(
target_channel_id=target_channel.id,
external_channel_id=external_channel.id,
creative_id=creative.id,
user_id=user.id,
placement_date=datetime.datetime.now(datetime.UTC),
invite_link='https://t.me/+link4',
invite_link_type=domain.InviteLinkType.PUBLIC,
status=domain.PlacementStatus.ACTIVE,
)
await mock_database.create_placement(placement)
input_data = dto.GetViewsHistoryInput(
placement_id=placement.id,
user_id=user.id,
)
result = await usecases.get_views_history(input=input_data)
assert len(result.histories) == 0
@pytest.mark.asyncio
async def test_get_views_history_with_snapshots(usecases: usecase.Usecase, mock_database: MockDatabase) -> None:
"""Получение истории просмотров возвращает записи в хронологическом порядке."""
user = domain.User(telegram_id=123456, username='testuser')
await mock_database.create_user(user)
target_channel = domain.TargetChannel(
telegram_id=-1001234567890,
title='Target Channel',
username='targetchannel',
user_id=user.id,
status=domain.TargetChannelStatus.ACTIVE,
)
await mock_database.upsert_target_channel(target_channel)
external_channel = domain.ExternalChannel(
telegram_id=-1009876543210,
title='External Channel',
username='externalchannel',
description=None,
subscribers_count=35000,
user_id=user.id,
)
await mock_database.create_external_channel(external_channel)
creative = domain.Creative(
name='Test Creative',
text='Test text',
target_channel_id=target_channel.id,
user_id=user.id,
status=domain.CreativeStatus.ACTIVE,
)
await mock_database.create_creative(creative)
placement = domain.Placement(
target_channel_id=target_channel.id,
external_channel_id=external_channel.id,
creative_id=creative.id,
user_id=user.id,
placement_date=datetime.datetime.now(datetime.UTC),
invite_link='https://t.me/+link5',
invite_link_type=domain.InviteLinkType.PUBLIC,
status=domain.PlacementStatus.ACTIVE,
)
await mock_database.create_placement(placement)
# Создаём несколько записей истории
now = datetime.datetime.now(datetime.UTC)
history1 = domain.PlacementViewsHistory(
placement_id=placement.id,
views_count=1000,
fetched_at=now - datetime.timedelta(hours=2),
)
history2 = domain.PlacementViewsHistory(
placement_id=placement.id,
views_count=1500,
fetched_at=now - datetime.timedelta(hours=1),
)
history3 = domain.PlacementViewsHistory(
placement_id=placement.id,
views_count=2000,
fetched_at=now,
)
await mock_database.create_placement_views_history(history1)
await mock_database.create_placement_views_history(history2)
await mock_database.create_placement_views_history(history3)
input_data = dto.GetViewsHistoryInput(
placement_id=placement.id,
user_id=user.id,
)
result = await usecases.get_views_history(input=input_data)
assert len(result.histories) == 3
# Проверяем сортировку по времени (старые первые)
assert result.histories[0].views_count == 1000
assert result.histories[1].views_count == 1500
assert result.histories[2].views_count == 2000
@pytest.mark.asyncio
async def test_get_views_history_with_date_filter(usecases: usecase.Usecase, mock_database: MockDatabase) -> None:
"""Фильтрация истории просмотров по датам работает корректно."""
user = domain.User(telegram_id=123456, username='testuser')
await mock_database.create_user(user)
target_channel = domain.TargetChannel(
telegram_id=-1001234567890,
title='Target Channel',
username='targetchannel',
user_id=user.id,
status=domain.TargetChannelStatus.ACTIVE,
)
await mock_database.upsert_target_channel(target_channel)
external_channel = domain.ExternalChannel(
telegram_id=-1009876543210,
title='External Channel',
username='externalchannel',
description=None,
subscribers_count=28000,
user_id=user.id,
)
await mock_database.create_external_channel(external_channel)
creative = domain.Creative(
name='Test Creative',
text='Test text',
target_channel_id=target_channel.id,
user_id=user.id,
status=domain.CreativeStatus.ACTIVE,
)
await mock_database.create_creative(creative)
placement = domain.Placement(
target_channel_id=target_channel.id,
external_channel_id=external_channel.id,
creative_id=creative.id,
user_id=user.id,
placement_date=datetime.datetime.now(datetime.UTC),
invite_link='https://t.me/+link6',
invite_link_type=domain.InviteLinkType.PUBLIC,
status=domain.PlacementStatus.ACTIVE,
)
await mock_database.create_placement(placement)
# Создаём записи с разными датами
now = datetime.datetime.now(datetime.UTC)
history1 = domain.PlacementViewsHistory(
placement_id=placement.id,
views_count=1000,
fetched_at=now - datetime.timedelta(days=3),
)
history2 = domain.PlacementViewsHistory(
placement_id=placement.id,
views_count=1500,
fetched_at=now - datetime.timedelta(days=1),
)
history3 = domain.PlacementViewsHistory(
placement_id=placement.id,
views_count=2000,
fetched_at=now,
)
await mock_database.create_placement_views_history(history1)
await mock_database.create_placement_views_history(history2)
await mock_database.create_placement_views_history(history3)
# Запрашиваем историю за последние 2 дня
input_data = dto.GetViewsHistoryInput(
placement_id=placement.id,
user_id=user.id,
from_date=now - datetime.timedelta(days=2),
)
result = await usecases.get_views_history(input=input_data)
# Должны вернуться только history2 и history3
assert len(result.histories) == 2
assert result.histories[0].views_count == 1500
assert result.histories[1].views_count == 2000