Files
remnawave-bedolaga-telegram…/tests/services/test_promocode_service.py
c0mrade 9a2aea038a chore: add uv package manager and ruff linter configuration
- Add pyproject.toml with uv and ruff configuration
- Pin Python version to 3.13 via .python-version
- Add Makefile commands: lint, format, fix
- Apply ruff formatting to entire codebase
- Remove unused imports (base64 in yookassa/simple_subscription)
- Update .gitignore for new config files
2026-01-24 17:45:27 +03:00

385 lines
14 KiB
Python

"""
Tests for PromoCodeService - focus on promo group integration
"""
from unittest.mock import AsyncMock
from app.services.promocode_service import PromoCodeService
# Import fixtures
async def test_activate_promo_group_promocode_success(
monkeypatch,
sample_user,
sample_promo_group,
sample_promocode_promo_group,
mock_db_session,
):
"""
Test successful activation of PROMO_GROUP type promocode
Scenario:
- User activates valid promo group promocode
- User doesn't have this promo group yet
- User is successfully added to promo group
- Result includes promo group name
"""
# Make promocode valid
sample_promocode_promo_group.is_valid = True
# Mock CRUD functions
get_user_mock = AsyncMock(return_value=sample_user)
monkeypatch.setattr('app.services.promocode_service.get_user_by_id', get_user_mock)
get_promocode_mock = AsyncMock(return_value=sample_promocode_promo_group)
monkeypatch.setattr('app.services.promocode_service.get_promocode_by_code', get_promocode_mock)
check_usage_mock = AsyncMock(return_value=False)
monkeypatch.setattr('app.services.promocode_service.check_user_promocode_usage', check_usage_mock)
get_promo_group_mock = AsyncMock(return_value=sample_promo_group)
monkeypatch.setattr('app.services.promocode_service.get_promo_group_by_id', get_promo_group_mock)
has_promo_group_mock = AsyncMock(return_value=False)
monkeypatch.setattr('app.services.promocode_service.has_user_promo_group', has_promo_group_mock)
add_promo_group_mock = AsyncMock()
monkeypatch.setattr('app.services.promocode_service.add_user_to_promo_group', add_promo_group_mock)
create_usage_mock = AsyncMock()
monkeypatch.setattr('app.services.promocode_service.create_promocode_use', create_usage_mock)
# Execute
service = PromoCodeService()
result = await service.activate_promocode(mock_db_session, sample_user.id, 'VIPGROUP')
# Assertions
assert result['success'] is True
assert 'Test VIP Group' in result['description']
assert result['promocode']['promo_group_id'] == sample_promo_group.id
# Verify promo group was fetched
get_promo_group_mock.assert_awaited_once_with(mock_db_session, sample_promo_group.id)
# Verify user promo group check
has_promo_group_mock.assert_awaited_once_with(mock_db_session, sample_user.id, sample_promo_group.id)
# Verify promo group assignment
add_promo_group_mock.assert_awaited_once_with(
mock_db_session, sample_user.id, sample_promo_group.id, assigned_by='promocode'
)
# Verify usage recorded
create_usage_mock.assert_awaited_once_with(mock_db_session, sample_promocode_promo_group.id, sample_user.id)
# Verify counter incremented
assert sample_promocode_promo_group.current_uses == 21
mock_db_session.commit.assert_awaited()
async def test_activate_promo_group_user_already_has_group(
monkeypatch,
sample_user,
sample_promo_group,
sample_promocode_promo_group,
mock_db_session,
):
"""
Test activation when user already has the promo group
Scenario:
- User activates promo group promocode
- User already has this promo group
- add_user_to_promo_group should NOT be called
- Activation still succeeds
"""
sample_promocode_promo_group.is_valid = True
# Mock CRUD functions
get_user_mock = AsyncMock(return_value=sample_user)
monkeypatch.setattr('app.services.promocode_service.get_user_by_id', get_user_mock)
get_promocode_mock = AsyncMock(return_value=sample_promocode_promo_group)
monkeypatch.setattr('app.services.promocode_service.get_promocode_by_code', get_promocode_mock)
check_usage_mock = AsyncMock(return_value=False)
monkeypatch.setattr('app.services.promocode_service.check_user_promocode_usage', check_usage_mock)
# User ALREADY HAS the promo group
has_promo_group_mock = AsyncMock(return_value=True)
monkeypatch.setattr('app.services.promocode_service.has_user_promo_group', has_promo_group_mock)
add_promo_group_mock = AsyncMock()
monkeypatch.setattr('app.services.promocode_service.add_user_to_promo_group', add_promo_group_mock)
create_usage_mock = AsyncMock()
monkeypatch.setattr('app.services.promocode_service.create_promocode_use', create_usage_mock)
# Execute
service = PromoCodeService()
result = await service.activate_promocode(mock_db_session, sample_user.id, 'VIPGROUP')
# Assertions
assert result['success'] is True
# Verify promo group assignment was NOT called
add_promo_group_mock.assert_not_awaited()
# But usage was still recorded
create_usage_mock.assert_awaited_once()
async def test_activate_promo_group_group_not_found(
monkeypatch,
sample_user,
sample_promocode_promo_group,
mock_db_session,
):
"""
Test activation when promo group doesn't exist (deleted/invalid)
Scenario:
- Promocode references non-existent promo_group_id
- get_promo_group_by_id returns None
- Warning is logged but activation doesn't fail
- Promocode effects still apply (graceful degradation)
"""
sample_promocode_promo_group.is_valid = True
# Mock CRUD functions
get_user_mock = AsyncMock(return_value=sample_user)
monkeypatch.setattr('app.services.promocode_service.get_user_by_id', get_user_mock)
get_promocode_mock = AsyncMock(return_value=sample_promocode_promo_group)
monkeypatch.setattr('app.services.promocode_service.get_promocode_by_code', get_promocode_mock)
check_usage_mock = AsyncMock(return_value=False)
monkeypatch.setattr('app.services.promocode_service.check_user_promocode_usage', check_usage_mock)
has_promo_group_mock = AsyncMock(return_value=False)
monkeypatch.setattr('app.services.promocode_service.has_user_promo_group', has_promo_group_mock)
# Promo group NOT FOUND
get_promo_group_mock = AsyncMock(return_value=None)
monkeypatch.setattr('app.services.promocode_service.get_promo_group_by_id', get_promo_group_mock)
add_promo_group_mock = AsyncMock()
monkeypatch.setattr('app.services.promocode_service.add_user_to_promo_group', add_promo_group_mock)
create_usage_mock = AsyncMock()
monkeypatch.setattr('app.services.promocode_service.create_promocode_use', create_usage_mock)
# Execute
service = PromoCodeService()
result = await service.activate_promocode(mock_db_session, sample_user.id, 'VIPGROUP')
# Assertions
assert result['success'] is True # Still succeeds!
# Verify promo group was attempted to fetch
get_promo_group_mock.assert_awaited_once()
# Verify promo group assignment was NOT called (because group not found)
add_promo_group_mock.assert_not_awaited()
# But usage was still recorded
create_usage_mock.assert_awaited_once()
async def test_activate_promo_group_assignment_error(
monkeypatch,
sample_user,
sample_promo_group,
sample_promocode_promo_group,
mock_db_session,
):
"""
Test activation when promo group assignment fails
Scenario:
- add_user_to_promo_group raises exception
- Error is logged but activation doesn't fail
- Promocode usage is still recorded (graceful degradation)
"""
sample_promocode_promo_group.is_valid = True
# Mock CRUD functions
get_user_mock = AsyncMock(return_value=sample_user)
monkeypatch.setattr('app.services.promocode_service.get_user_by_id', get_user_mock)
get_promocode_mock = AsyncMock(return_value=sample_promocode_promo_group)
monkeypatch.setattr('app.services.promocode_service.get_promocode_by_code', get_promocode_mock)
check_usage_mock = AsyncMock(return_value=False)
monkeypatch.setattr('app.services.promocode_service.check_user_promocode_usage', check_usage_mock)
get_promo_group_mock = AsyncMock(return_value=sample_promo_group)
monkeypatch.setattr('app.services.promocode_service.get_promo_group_by_id', get_promo_group_mock)
has_promo_group_mock = AsyncMock(return_value=False)
monkeypatch.setattr('app.services.promocode_service.has_user_promo_group', has_promo_group_mock)
# add_user_to_promo_group RAISES EXCEPTION
add_promo_group_mock = AsyncMock(side_effect=Exception('Database error'))
monkeypatch.setattr('app.services.promocode_service.add_user_to_promo_group', add_promo_group_mock)
create_usage_mock = AsyncMock()
monkeypatch.setattr('app.services.promocode_service.create_promocode_use', create_usage_mock)
# Execute
service = PromoCodeService()
result = await service.activate_promocode(mock_db_session, sample_user.id, 'VIPGROUP')
# Assertions
assert result['success'] is True # Still succeeds!
# Verify promo group assignment was attempted
add_promo_group_mock.assert_awaited_once()
# But usage was still recorded
create_usage_mock.assert_awaited_once()
async def test_activate_promo_group_assigned_by_value(
monkeypatch,
sample_user,
sample_promo_group,
sample_promocode_promo_group,
mock_db_session,
):
"""
Test that assigned_by parameter is correctly set to 'promocode'
Scenario:
- Verify add_user_to_promo_group is called with assigned_by="promocode"
"""
sample_promocode_promo_group.is_valid = True
# Mock CRUD functions
get_user_mock = AsyncMock(return_value=sample_user)
monkeypatch.setattr('app.services.promocode_service.get_user_by_id', get_user_mock)
get_promocode_mock = AsyncMock(return_value=sample_promocode_promo_group)
monkeypatch.setattr('app.services.promocode_service.get_promocode_by_code', get_promocode_mock)
check_usage_mock = AsyncMock(return_value=False)
monkeypatch.setattr('app.services.promocode_service.check_user_promocode_usage', check_usage_mock)
get_promo_group_mock = AsyncMock(return_value=sample_promo_group)
monkeypatch.setattr('app.services.promocode_service.get_promo_group_by_id', get_promo_group_mock)
has_promo_group_mock = AsyncMock(return_value=False)
monkeypatch.setattr('app.services.promocode_service.has_user_promo_group', has_promo_group_mock)
add_promo_group_mock = AsyncMock()
monkeypatch.setattr('app.services.promocode_service.add_user_to_promo_group', add_promo_group_mock)
create_usage_mock = AsyncMock()
monkeypatch.setattr('app.services.promocode_service.create_promocode_use', create_usage_mock)
# Execute
service = PromoCodeService()
await service.activate_promocode(mock_db_session, sample_user.id, 'VIPGROUP')
# Verify assigned_by="promocode"
add_promo_group_mock.assert_awaited_once_with(
mock_db_session,
sample_user.id,
sample_promo_group.id,
assigned_by='promocode', # Critical assertion
)
async def test_activate_promo_group_description_includes_group_name(
monkeypatch,
sample_user,
sample_promo_group,
sample_promocode_promo_group,
mock_db_session,
):
"""
Test that result description includes promo group name
Scenario:
- When promo group is assigned, description should include group name
"""
sample_promocode_promo_group.is_valid = True
# Mock CRUD functions
get_user_mock = AsyncMock(return_value=sample_user)
monkeypatch.setattr('app.services.promocode_service.get_user_by_id', get_user_mock)
get_promocode_mock = AsyncMock(return_value=sample_promocode_promo_group)
monkeypatch.setattr('app.services.promocode_service.get_promocode_by_code', get_promocode_mock)
check_usage_mock = AsyncMock(return_value=False)
monkeypatch.setattr('app.services.promocode_service.check_user_promocode_usage', check_usage_mock)
get_promo_group_mock = AsyncMock(return_value=sample_promo_group)
monkeypatch.setattr('app.services.promocode_service.get_promo_group_by_id', get_promo_group_mock)
has_promo_group_mock = AsyncMock(return_value=False)
monkeypatch.setattr('app.services.promocode_service.has_user_promo_group', has_promo_group_mock)
add_promo_group_mock = AsyncMock()
monkeypatch.setattr('app.services.promocode_service.add_user_to_promo_group', add_promo_group_mock)
create_usage_mock = AsyncMock()
monkeypatch.setattr('app.services.promocode_service.create_promocode_use', create_usage_mock)
# Execute
service = PromoCodeService()
result = await service.activate_promocode(mock_db_session, sample_user.id, 'VIPGROUP')
# Verify description includes promo group name
assert 'Назначена промогруппа: Test VIP Group' in result['description']
async def test_promocode_data_includes_promo_group_id(
monkeypatch,
sample_user,
sample_promo_group,
sample_promocode_promo_group,
mock_db_session,
):
"""
Test that returned promocode data includes promo_group_id
Scenario:
- Verify result["promocode"]["promo_group_id"] is present
"""
sample_promocode_promo_group.is_valid = True
# Mock CRUD functions
get_user_mock = AsyncMock(return_value=sample_user)
monkeypatch.setattr('app.services.promocode_service.get_user_by_id', get_user_mock)
get_promocode_mock = AsyncMock(return_value=sample_promocode_promo_group)
monkeypatch.setattr('app.services.promocode_service.get_promocode_by_code', get_promocode_mock)
check_usage_mock = AsyncMock(return_value=False)
monkeypatch.setattr('app.services.promocode_service.check_user_promocode_usage', check_usage_mock)
get_promo_group_mock = AsyncMock(return_value=sample_promo_group)
monkeypatch.setattr('app.services.promocode_service.get_promo_group_by_id', get_promo_group_mock)
has_promo_group_mock = AsyncMock(return_value=False)
monkeypatch.setattr('app.services.promocode_service.has_user_promo_group', has_promo_group_mock)
add_promo_group_mock = AsyncMock()
monkeypatch.setattr('app.services.promocode_service.add_user_to_promo_group', add_promo_group_mock)
create_usage_mock = AsyncMock()
monkeypatch.setattr('app.services.promocode_service.create_promocode_use', create_usage_mock)
# Execute
service = PromoCodeService()
result = await service.activate_promocode(mock_db_session, sample_user.id, 'VIPGROUP')
# Verify promocode data structure
assert 'promocode' in result
assert 'promo_group_id' in result['promocode']
assert result['promocode']['promo_group_id'] == sample_promo_group.id