Files
my-daily/ai-daily-main/tests/pytest/test_main_morning_push.py
T

124 lines
3.7 KiB
Python

"""测试早报四模块编排:gather + insights 串行 + sentinel 拼装 + 失败隔离"""
import sys
from pathlib import Path
from unittest.mock import patch, AsyncMock
import pytest
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
from src.main import _run_morning_push
def _insights_meta() -> dict:
return {
"title": "📰 AI Daily 每日精选 | 2026-05-22",
"lead": "lead text",
"highlights": ["a"],
"profile": "morning",
"date": "2026-05-22",
"excerpt": "",
"seotitle": "",
"seodescription": "",
}
@pytest.mark.asyncio
async def test_assembles_all_four_sections(sample_config):
sample_config["filter"]["push_context_days"] = 5
sent = {}
async def fake_send(content, push_cfg, title=None, metadata=None):
sent["content"] = content
sent["metadata"] = metadata
saved = {}
def fake_save(
filepath,
content,
source_count,
total_entries,
profile="default",
metadata=None,
):
saved["profile"] = profile
saved["content"] = content
saved["metadata"] = metadata
with patch(
"src.main.run_rss_section", new=AsyncMock(return_value=("R", None, None))
), patch(
"src.main.run_github_section", new=AsyncMock(return_value=("G", None))
), patch(
"src.main.run_hackernews_section", new=AsyncMock(return_value=("H", None))
), patch(
"src.main.run_insights_section",
new=AsyncMock(return_value=("I", _insights_meta(), None)),
), patch(
"src.main.send_to_platforms", new=AsyncMock(side_effect=fake_send)
), patch(
"src.main.save_push_file", side_effect=fake_save
):
await _run_morning_push(sample_config)
assert "SECTION:rss" in sent["content"]
assert "SECTION:github" in sent["content"]
assert "SECTION:hackernews" in sent["content"]
assert "SECTION:insights" in sent["content"]
assert sent["metadata"]["profile"] == "morning"
assert saved["profile"] == "morning"
assert saved["metadata"]["lead"] == "lead text"
@pytest.mark.asyncio
async def test_rss_failure_raises_to_caller(sample_config):
sample_config["filter"]["push_context_days"] = 5
with patch(
"src.main.run_rss_section",
new=AsyncMock(return_value=("", None, "compose_digest 失败")),
), patch(
"src.main.run_github_section", new=AsyncMock(return_value=("G", None))
), patch(
"src.main.run_hackernews_section", new=AsyncMock(return_value=("H", None))
), patch(
"src.main.notify_llm_errors", new=AsyncMock()
):
with pytest.raises(RuntimeError):
await _run_morning_push(sample_config)
@pytest.mark.asyncio
async def test_section_failure_degrades_to_omission(sample_config):
sample_config["filter"]["push_context_days"] = 5
sent = {}
async def fake_send(content, push_cfg, title=None, metadata=None):
sent["content"] = content
with patch(
"src.main.run_rss_section", new=AsyncMock(return_value=("R", None, None))
), patch(
"src.main.run_github_section", new=AsyncMock(return_value=("", "gh down"))
), patch(
"src.main.run_hackernews_section", new=AsyncMock(return_value=("H", None))
), patch(
"src.main.run_insights_section",
new=AsyncMock(return_value=("I", _insights_meta(), None)),
), patch(
"src.main.notify_llm_errors", new=AsyncMock()
), patch(
"src.main.send_to_platforms", new=AsyncMock(side_effect=fake_send)
), patch(
"src.main.save_push_file"
):
await _run_morning_push(sample_config)
assert "SECTION:rss" in sent["content"]
assert "SECTION:github" not in sent["content"]
assert "SECTION:hackernews" in sent["content"]