# -*- coding: utf-8 -*- """作品备注 —— 一个博主底下,哪几条是真正要盯的。 和博主备注(test_monitor_creators.py)是一对,但回答的不是同一个问题:博主备注回答 「这个账号是谁」,作品备注回答「这条作品我要盯着」。一个博主底下常常只有一两件值得 盯的作品,所以不能合成一条。 """ import httpx import pytest import pytest_asyncio from api.main import app from api.monitor import db as monitor_db from api.monitor.models import MODE_CREATOR, MonitorNote, MonitorTask NOTE_ID = "note-a" TITLE = "中秋哪儿都堵" @pytest_asyncio.fixture async def client(tmp_path): monitor_db.set_sqlite_path(tmp_path / "monitor.db") await monitor_db.init_db() transport = httpx.ASGITransport(app=app) async with httpx.AsyncClient(transport=transport, base_url="http://test") as http_client: yield http_client await monitor_db.dispose_engine() async def _seed(platform: str = "xhs", task_name: str = "任务", note_id: str = NOTE_ID) -> int: async with monitor_db.get_session() as session: task = MonitorTask( name=task_name, platform=platform, mode=MODE_CREATOR, enabled=True, interval_minutes=60, max_notes_count=20, enable_comments=False, max_comments_count=50, run_timeout_seconds=3600, notify_enabled=False, created_at=0, updated_at=0, ) session.add(task) await session.flush() session.add( MonitorNote( task_id=task.id, note_id=note_id, title=TITLE, note_url="", cover="", creator_hash="hash-a", creator_name="张三", source_kind="", published_at=None, first_seen_run_id=1, first_seen_at=0, last_seen_run_id=1, last_seen_at=0, ) ) return task.id async def _notes(client, platform: str = "xhs"): return (await client.get("/api/monitor/notes", params={"platform": platform})).json()["notes"] async def _set_alias(client, alias: str, platform: str = "xhs", note_id: str = NOTE_ID): return await client.put( f"/api/monitor/notes/{note_id}", params={"platform": platform}, json={"alias": alias}, ) class TestNoteAlias: @pytest.mark.asyncio async def test_notes_start_without_a_remark(self, client): await _seed() assert (await _notes(client))[0]["note_alias"] == "" @pytest.mark.asyncio async def test_a_remark_comes_back_with_the_notes(self, client): await _seed() response = await _set_alias(client, "重点") assert response.status_code == 200 note = (await _notes(client))[0] assert note["note_alias"] == "重点" # 备注是**叠加**在标题之上的,不是替换 —— 标题仍然是这条作品本身。 assert note["title"] == TITLE @pytest.mark.asyncio async def test_a_remark_is_shared_across_tasks(self, client): """同一件作品被两个任务都监控时,备注只该填一次。""" await _seed(task_name="任务甲") await _seed(task_name="任务乙") await _set_alias(client, "重点") for note in await _notes(client): assert note["note_alias"] == "重点" @pytest.mark.asyncio async def test_a_remark_does_not_leak_to_another_platform(self, client): """作品的 id 是平台各自的编号体系 —— 抖音的 123 和小红书的 123 是两条作品。""" await _seed(platform="xhs") await _seed(platform="dy") await _set_alias(client, "小红书那边的", platform="xhs") assert (await _notes(client, "xhs"))[0]["note_alias"] == "小红书那边的" assert (await _notes(client, "dy"))[0]["note_alias"] == "" @pytest.mark.asyncio async def test_a_remark_does_not_leak_to_another_work(self, client): """钉住这里的**作用域**:键是 note_id。写错成按任务存的话,给一条起了备注, 同一个博主底下的其它作品会跟着一起变 —— 那这个功能就没用了。""" await _seed(note_id="note-a") await _seed(task_name="另一个任务", note_id="note-b") await _set_alias(client, "重点", note_id="note-a") by_id = {note["note_id"]: note["note_alias"] for note in await _notes(client)} assert by_id == {"note-a": "重点", "note-b": ""} @pytest.mark.asyncio async def test_an_empty_remark_clears_it(self, client): await _seed() await _set_alias(client, "重点") await _set_alias(client, "") assert (await _notes(client))[0]["note_alias"] == "" @pytest.mark.asyncio async def test_a_remark_is_trimmed(self, client): await _seed() await _set_alias(client, " 重点 ") assert (await _notes(client))[0]["note_alias"] == "重点" @pytest.mark.asyncio async def test_the_two_kinds_of_remark_stay_apart(self, client): """博主备注和作品备注是两张表、两个键 —— 一个不该把另一个盖掉。""" await _seed() await _set_alias(client, "重点") await client.put( "/api/monitor/creators/hash-a", params={"platform": "xhs"}, json={"alias": "竞品A"} ) note = (await _notes(client))[0] assert note["note_alias"] == "重点" assert note["creator_alias"] == "竞品A"