"""业务链条「发布审核」流程测试。 覆盖: - store:``pending_review`` 随 create(缺省 False)/ update 持久化; - store:``scope="pending"`` 仅管理员返回全部待审核链条;非管理员按 ``mine`` 退化; - 完整审核流:owner 提交审核 → 管理员在 pending 列表看到 → 发布(``is_public=True`` + ``pending_review=False``)后从 pending 列表消失、进入 public 列表。 """ from __future__ import annotations import pytest from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine async def _make_repo(): from deerflow.persistence.base import Base from deerflow.persistence.roundtable_chains.model import RoundtableChainRow # noqa: F401 注册表 from deerflow.persistence.roundtable_chains.sql import RoundtableChainRepository engine = create_async_engine("sqlite+aiosqlite:///:memory:") async with engine.begin() as conn: await conn.run_sync(Base.metadata.create_all) sf = async_sessionmaker(engine, expire_on_commit=False) return RoundtableChainRepository(sf), engine _SEATS = [ {"agent_id": "a", "name": "情报收集", "description": ""}, {"agent_id": "b", "name": "环境评估", "description": ""}, ] @pytest.mark.asyncio async def test_pending_review_flag_roundtrip(): repo, engine = await _make_repo() try: row = await repo.create_chain("u1", {"id": "c1", "title": "链", "seats": _SEATS}) # 缺省 False。 assert row["pending_review"] is False # owner 提交审核 → True。 updated = await repo.update_chain("c1", "u1", pending_review=True) assert updated is not None and updated["pending_review"] is True # 撤回 / 管理员发布清回 → False。 updated = await repo.update_chain("c1", "u1", pending_review=False) assert updated is not None and updated["pending_review"] is False finally: await engine.dispose() @pytest.mark.asyncio async def test_scope_pending_lists_all_users_pending_for_admin(): repo, engine = await _make_repo() try: await repo.create_chain("u1", {"id": "c1", "title": "U1 待审", "seats": _SEATS}) await repo.create_chain("u1", {"id": "c2", "title": "U1 草稿", "seats": _SEATS}) await repo.create_chain("u2", {"id": "c3", "title": "U2 待审", "seats": _SEATS}) await repo.update_chain("c1", "u1", pending_review=True) await repo.update_chain("c3", "u2", pending_review=True) # 管理员 pending → 只含两条待审核链条(跨账号)。 rows = await repo.list_chains("admin", scope="pending", is_admin=True) assert {r["id"] for r in rows} == {"c1", "c3"} # 非管理员误传 pending(is_admin=False)→ 退化为 mine:只见自己的(c1/c2), # 绝不越权看到他人待审核链条。 rows = await repo.list_chains("u1", scope="pending", is_admin=False) assert {r["id"] for r in rows} == {"c1", "c2"} finally: await engine.dispose() @pytest.mark.asyncio async def test_full_review_flow_owner_submit_admin_publish(): repo, engine = await _make_repo() try: await repo.create_chain("u1", {"id": "c1", "title": "走审核的链", "seats": _SEATS}) # ① owner 提交审核。 await repo.update_chain("c1", "u1", pending_review=True) # ② 管理员在「待审核」列表看到。 pending = await repo.list_chains("admin", scope="pending", is_admin=True) assert [r["id"] for r in pending] == ["c1"] # ③ 管理员审核发布:is_public=True + 清除待审核标记。 published = await repo.update_chain( "c1", "admin", is_public=True, pending_review=False, is_admin=True ) assert published is not None assert published["is_public"] is True assert published["pending_review"] is False # owner 不变。 assert published["owner_id"] == "u1" # ④ 发布后:pending 列表为空,public 列表可见(任何账号)。 assert await repo.list_chains("admin", scope="pending", is_admin=True) == [] public = await repo.list_chains("u2", scope="public") assert [r["id"] for r in public] == ["c1"] finally: await engine.dispose()