Docs: [3.0.0] 전체 문서 업데이트 — YouTube Data API + n8n Discord 전송 구조 반영
All checks were successful
news-summary-bot-cicd / build_push_deploy (push) Successful in 25m15s

- README: 아키텍처, 환경변수, API 응답 형식 업데이트
- n8n-setup: RSS → YouTube Data API playlistItems 전환, 노드별 상세 설정
- development: discord.py 제거 반영, API 응답 형식 추가
- operations: CI/CD 자동 배포 설명, DISCORD_WEBHOOK_URL 제거
- testing: DISCORD_WEBHOOK_URL 더미값 제거
- .env.example: DISCORD_WEBHOOK_URL 제거
- tests/test_discord.py 삭제 (모듈 삭제됨)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
sm4640
2026-03-25 15:18:39 +09:00
parent 302f892c5d
commit a2a82084ba
7 changed files with 260 additions and 273 deletions

View File

@@ -1,137 +0,0 @@
"""discord.py 유닛 테스트 — 파싱, 비디오 ID 추출, 임베드 구성."""
from unittest.mock import AsyncMock, patch
import pytest
from app.discord import _extract_video_id, _parse_summary, send_to_discord
# ── _extract_video_id ──
@pytest.mark.parametrize(
"url, expected",
[
("https://youtu.be/abc123", "abc123"),
("https://www.youtube.com/watch?v=xyz789", "xyz789"),
("https://www.youtube.com/watch?v=xyz789&t=10", "xyz789"),
("https://youtu.be/abc123?si=something", "abc123"),
("https://example.com/no-video", None),
],
)
def test_extract_video_id(url: str, expected: str | None):
assert _extract_video_id(url) == expected
# ── _parse_summary ──
SAMPLE_SUMMARY_BOLD = """\
- **한줄 요약**: 한국 경제가 위기에 처했다.
- **주요 내용**:
- GDP 성장률 하락
- 수출 감소
- 환율 불안정
- **결론/시사점**: 정부의 적극적 대응이 필요하다.
"""
SAMPLE_SUMMARY_HEADING = """\
## 한줄 요약
한국 경제가 위기에 처했다.
## 주요 내용
- GDP 성장률 하락
- 수출 감소
- 환율 불안정
## 결론/시사점
정부의 적극적 대응이 필요하다.
"""
def test_parse_summary_bold_format():
result = _parse_summary(SAMPLE_SUMMARY_BOLD)
assert "한줄요약" in result
assert "한국 경제가 위기에 처했다." in result["한줄요약"]
assert "주요내용" in result
assert "GDP 성장률 하락" in result["주요내용"]
assert "결론/시사점" in result or "결론시사점" in result
def test_parse_summary_heading_format():
result = _parse_summary(SAMPLE_SUMMARY_HEADING)
assert "한줄요약" in result
assert "한국 경제가 위기에 처했다." in result["한줄요약"]
assert "주요내용" in result
assert "GDP 성장률 하락" in result["주요내용"]
def test_parse_summary_empty():
result = _parse_summary("이건 파싱 안 되는 텍스트")
assert result == {}
# ── send_to_discord ──
@pytest.mark.asyncio
async def test_send_to_discord_embed_structure():
"""send_to_discord가 올바른 임베드 구조로 웹훅을 호출하는지 확인."""
mock_response = AsyncMock()
mock_response.raise_for_status = lambda: None
with patch("app.discord.httpx.AsyncClient") as mock_client_cls:
mock_client = AsyncMock()
mock_client.post.return_value = mock_response
mock_client_cls.return_value.__aenter__ = AsyncMock(return_value=mock_client)
mock_client_cls.return_value.__aexit__ = AsyncMock(return_value=False)
await send_to_discord(
title="테스트 영상",
video_url="https://youtu.be/abc123",
summary=SAMPLE_SUMMARY_BOLD,
)
mock_client.post.assert_called_once()
payload = mock_client.post.call_args[1]["json"]
embed = payload["embeds"][0]
assert "📰 테스트 영상" == embed["title"]
assert embed["url"] == "https://youtu.be/abc123"
assert embed["thumbnail"]["url"] == "https://img.youtube.com/vi/abc123/hqdefault.jpg"
assert embed["footer"]["text"] == "YouTube 뉴스 요약 봇"
assert "timestamp" in embed
# 필드 확인
field_names = [f["name"] for f in embed["fields"]]
assert "📋 주요 내용" in field_names
assert "🎯 결론 / 시사점" in field_names
assert "🔗 원본 영상" in field_names
# description에 한줄 요약 포함
assert "한국 경제가 위기에 처했다" in embed["description"]
@pytest.mark.asyncio
async def test_send_to_discord_fallback_on_unparsable():
"""파싱 실패 시 전체 summary가 description에 들어가는지 확인."""
mock_response = AsyncMock()
mock_response.raise_for_status = lambda: None
with patch("app.discord.httpx.AsyncClient") as mock_client_cls:
mock_client = AsyncMock()
mock_client.post.return_value = mock_response
mock_client_cls.return_value.__aenter__ = AsyncMock(return_value=mock_client)
mock_client_cls.return_value.__aexit__ = AsyncMock(return_value=False)
raw = "이건 섹션 없는 요약 텍스트입니다."
await send_to_discord("테스트", "https://youtu.be/abc", raw)
payload = mock_client.post.call_args[1]["json"]
embed = payload["embeds"][0]
assert embed["description"] == raw
assert len(embed["fields"]) == 1
assert embed["fields"][0]["name"] == "🔗 원본 영상"