deer-flow/backend/tests/test_tool_approval_migration.py
Wenchao An 3d826c6d95
feat(approvals): add Ask, Auto and Full tool permission modes (#8033)
* feat(hitl): add human-in-the-loop approval for high-risk tool calls

* fix(hitl): address approval review findings

* docs(hitl): keep agent guidance under size limit

* fix(hitl): guard approval pause recovery

* docs(hitl): shrink inherited guidance

* fix(hitl): harden approval admission and recovery

* fix(approvals): address review safety and reconciliation gaps

* ci: retry approval checks after runner timeout

---------

Co-authored-by: wangzeren <1004695029@qq.com>
2026-11-11 20:59:05 +08:00

35 lines
1.8 KiB
Python

"""Exercise upgrade, retry and downgrade through the actual migration chain."""
import asyncio
import pytest
import sqlalchemy as sa
from alembic import command
from sqlalchemy.ext.asyncio import create_async_engine
from deerflow.persistence import bootstrap
@pytest.mark.asyncio
async def test_approval_migration_retry_and_downgrade(tmp_path):
engine = create_async_engine(f"sqlite+aiosqlite:///{tmp_path / 'migration.db'}")
cfg = bootstrap._get_alembic_config(engine)
try:
await asyncio.to_thread(command.upgrade, cfg, "0052_batch_continuation")
await asyncio.to_thread(command.upgrade, cfg, "0053_tool_approvals")
async with engine.begin() as conn:
await conn.execute(sa.text("INSERT INTO tool_approvals (request_id,user_id,thread_id,incarnation,run_id,fingerprint,kind,status,payload,created_at) VALUES ('r','u','t','i','run','fingerprint','audit','consumed','{}',1)"))
await asyncio.to_thread(command.stamp, cfg, "0052_batch_continuation")
async with engine.begin() as conn:
await conn.execute(sa.text("DROP INDEX ix_tool_approvals_scope"))
await asyncio.to_thread(command.upgrade, cfg, "0053_tool_approvals")
async with engine.connect() as conn:
assert (await conn.execute(sa.text("SELECT request_id FROM tool_approvals"))).scalar_one() == "r"
indexes = await conn.run_sync(lambda c: sa.inspect(c).get_indexes("tool_approvals"))
assert {index["name"] for index in indexes} == {"ix_tool_approvals_run", "ix_tool_approvals_scope"}
await asyncio.to_thread(command.downgrade, cfg, "0052_batch_continuation")
async with engine.connect() as conn:
assert not await conn.run_sync(lambda c: sa.inspect(c).has_table("tool_approvals"))
finally:
await engine.dispose()