Files
Gov-chat-bot/backend/tests/test_moderation.py
2026-03-26 12:49:43 +09:00

142 lines
4.0 KiB
Python

"""
악성·반복 민원 제한 서비스 테스트.
"""
import pytest
from datetime import datetime, timedelta, timezone
from unittest.mock import AsyncMock, MagicMock
from app.services.moderation import ModerationService, ModerationResult
from app.models.moderation import UserRestriction, RestrictionLevel
def make_db(restriction=None):
db = AsyncMock()
db.add = MagicMock()
db.commit = AsyncMock()
db.execute = AsyncMock()
scalar = MagicMock()
scalar.scalar_one_or_none = MagicMock(return_value=restriction)
db.execute.return_value = scalar
return db
@pytest.mark.asyncio
async def test_check_normal_user_is_allowed():
"""제한 없는 사용자 → 허용."""
db = make_db(restriction=None)
service = ModerationService(db)
result = await service.check("t1", "user-1")
assert result.allowed is True
assert result.level == 0
@pytest.mark.asyncio
async def test_check_blocked_user_is_denied():
"""Level 5 (BLOCKED) → 차단."""
r = MagicMock()
r.level = RestrictionLevel.BLOCKED
r.expires_at = None
db = make_db(restriction=r)
service = ModerationService(db)
result = await service.check("t1", "user-block")
assert result.allowed is False
assert result.level == RestrictionLevel.BLOCKED
@pytest.mark.asyncio
async def test_check_suspended_user_is_denied():
"""Level 4 (SUSPENDED) → 편집장 확인 전 차단."""
r = MagicMock()
r.level = RestrictionLevel.SUSPENDED
r.expires_at = datetime.now(timezone.utc) + timedelta(hours=1)
db = make_db(restriction=r)
service = ModerationService(db)
result = await service.check("t1", "user-sus")
assert result.allowed is False
@pytest.mark.asyncio
async def test_check_warning_user_has_delay():
"""Level 2 (WARNING) → 허용 + 30초 지연."""
r = MagicMock()
r.level = RestrictionLevel.WARNING
r.expires_at = datetime.now(timezone.utc) + timedelta(hours=1)
db = make_db(restriction=r)
service = ModerationService(db)
result = await service.check("t1", "user-warn")
assert result.allowed is True
assert result.delay_seconds == 30
@pytest.mark.asyncio
async def test_escalate_increases_level():
"""레벨 상승: NORMAL → 다음 레벨."""
r = MagicMock(spec=UserRestriction)
r.level = RestrictionLevel.NORMAL
r.expires_at = None
r.auto_applied = True
db = make_db(restriction=r)
service = ModerationService(db)
new_level = await service.escalate("t1", "user-1", "반복 민원")
assert new_level == RestrictionLevel.NORMAL + 1
db.commit.assert_called_once()
@pytest.mark.asyncio
async def test_escalate_stops_at_suspended():
"""Level 4 이상 자동 상승 금지."""
r = MagicMock(spec=UserRestriction)
r.level = RestrictionLevel.SUSPENDED
r.expires_at = None
db = make_db(restriction=r)
service = ModerationService(db)
new_level = await service.escalate("t1", "user-1")
# Level 4에서 멈춤
assert new_level == RestrictionLevel.SUSPENDED
@pytest.mark.asyncio
async def test_release_resets_level():
"""수동 해제 → level 0."""
r = MagicMock(spec=UserRestriction)
r.level = RestrictionLevel.SUSPENDED
r.expires_at = None
r.auto_applied = True
r.applied_by = None
db = make_db(restriction=r)
service = ModerationService(db)
await service.release("t1", "user-1", applied_by="editor-1")
assert r.level == RestrictionLevel.NORMAL
assert r.applied_by == "editor-1"
db.commit.assert_called_once()
@pytest.mark.asyncio
async def test_check_expired_restriction_resets():
"""만료된 제한 → 자동 해제."""
r = MagicMock(spec=UserRestriction)
r.level = RestrictionLevel.WARNING # Level 2
r.expires_at = datetime.now(timezone.utc) - timedelta(hours=1) # 만료
r.auto_applied = True
r.applied_by = None
db = make_db(restriction=r)
service = ModerationService(db)
result = await service.check("t1", "user-expired")
assert result.allowed is True
assert result.level == 0