Initial commit: import from sinmb79/Gov-chat-bot

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
airkjw
2026-03-26 12:49:43 +09:00
commit a16c972dbb
104 changed files with 8063 additions and 0 deletions
+141
View File
@@ -0,0 +1,141 @@
"""
악성·반복 민원 제한 서비스 테스트.
"""
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