mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-05 15:38:19 +08:00
refactor: isolate agent history queries
This commit is contained in:
+3
-33
@@ -1,43 +1,13 @@
|
||||
{
|
||||
"model_decorators": {
|
||||
"by_kind": {
|
||||
"async_db_query": 9,
|
||||
"async_db_query": 7,
|
||||
"async_db_update": 0,
|
||||
"db_query": 9,
|
||||
"db_query": 5,
|
||||
"db_update": 0
|
||||
},
|
||||
"count": 18,
|
||||
"count": 12,
|
||||
"methods": [
|
||||
{
|
||||
"decorator": "async_db_query",
|
||||
"file": "app/db/models/agentchat.py",
|
||||
"method": "AgentChat.async_get_by_session"
|
||||
},
|
||||
{
|
||||
"decorator": "async_db_query",
|
||||
"file": "app/db/models/agentchat.py",
|
||||
"method": "AgentChat.async_list_by_page"
|
||||
},
|
||||
{
|
||||
"decorator": "db_query",
|
||||
"file": "app/db/models/agentchat.py",
|
||||
"method": "AgentChat.get_by_session"
|
||||
},
|
||||
{
|
||||
"decorator": "db_query",
|
||||
"file": "app/db/models/agentchat.py",
|
||||
"method": "AgentChat.list_by_page"
|
||||
},
|
||||
{
|
||||
"decorator": "db_query",
|
||||
"file": "app/db/models/agenttaskrun.py",
|
||||
"method": "AgentTaskRun.get_by_run_id"
|
||||
},
|
||||
{
|
||||
"decorator": "db_query",
|
||||
"file": "app/db/models/agenttaskrun.py",
|
||||
"method": "AgentTaskRun.list_for_task"
|
||||
},
|
||||
{
|
||||
"decorator": "async_db_query",
|
||||
"file": "app/db/models/passkey.py",
|
||||
|
||||
@@ -14,6 +14,7 @@ from app.db.oper.agenttask import AgentTaskOper
|
||||
from app.db.models.agenttask import AgentTask
|
||||
from app.db.models.agenttaskrun import AgentTaskRun
|
||||
from app.db.session import SessionFactory
|
||||
from app.db import decorators
|
||||
|
||||
|
||||
Engine = get_engine()
|
||||
@@ -134,6 +135,35 @@ def test_begin_run_rejects_unknown_trigger_source() -> None:
|
||||
assert AgentTaskOper().list_runs(task.id) == []
|
||||
|
||||
|
||||
def test_agenttaskrun_oper_reuses_explicit_query_session(db, monkeypatch):
|
||||
"""AgentTaskOper 的运行记录查询必须复用调用方同步会话。"""
|
||||
task = _add_task("run-explicit-query")
|
||||
run = AgentTaskOper().begin_run(task.id)
|
||||
assert run
|
||||
monkeypatch.setattr(
|
||||
decorators,
|
||||
"ScopedSession",
|
||||
lambda: (_ for _ in ()).throw(AssertionError("不应创建额外同步会话")),
|
||||
)
|
||||
|
||||
oper = AgentTaskOper(db.session)
|
||||
assert oper.get_run(run.run_id) is not None
|
||||
assert oper.list_runs(task.id)
|
||||
|
||||
|
||||
def test_agenttaskrun_model_legacy_query_keeps_keyword_abi(monkeypatch):
|
||||
"""旧插件以关键字直调 AgentTaskRun 时仍自动补入短会话。"""
|
||||
opened = []
|
||||
monkeypatch.setattr(
|
||||
decorators,
|
||||
"ScopedSession",
|
||||
lambda: (opened.append(True) or SessionFactory()),
|
||||
)
|
||||
|
||||
assert AgentTaskRun.get_by_run_id(run_id="missing-legacy") is None
|
||||
assert opened == [True]
|
||||
|
||||
|
||||
def test_begin_run_rolls_back_task_claim_when_run_insert_fails() -> None:
|
||||
"""运行记录插入失败时,任务的 running 投影必须随事务回滚。"""
|
||||
first_task = _add_task("run-rollback-first")
|
||||
|
||||
@@ -126,8 +126,8 @@ def test_transaction_debt_baseline_is_a_model_and_oper_ratchet() -> None:
|
||||
baseline = json.loads(baseline_path.read_text(encoding="utf-8"))
|
||||
|
||||
assert baseline["schema_version"] == 1
|
||||
assert baseline["model_decorators"]["count"] == 18
|
||||
assert sum(baseline["model_decorators"]["by_kind"].values()) == 18
|
||||
assert baseline["model_decorators"]["count"] == 12
|
||||
assert sum(baseline["model_decorators"]["by_kind"].values()) == 12
|
||||
assert baseline["model_decorators"]["by_kind"]["db_update"] == 0
|
||||
assert baseline["model_decorators"]["by_kind"]["async_db_update"] == 0
|
||||
assert baseline["model_transaction_calls"] == {"count": 0, "calls": []}
|
||||
|
||||
@@ -8,12 +8,14 @@ import asyncio
|
||||
|
||||
import pytest
|
||||
|
||||
from app.db import decorators
|
||||
from app.db.models.agentchat import AgentChat
|
||||
from app.db.models.agenttask import AgentTask
|
||||
from app.db.models.downloadfailure import DownloadFailure
|
||||
from app.db.models.message import Message
|
||||
from app.db.models.plugindata import PluginData
|
||||
from app.db.oper.agenttask import AgentTaskOper
|
||||
from app.db.session import SessionFactory
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
@@ -238,6 +240,48 @@ def test_agentchat_get_by_session_enforces_user_scope(db):
|
||||
assert asyncio.run(AgentChat.async_get_by_session(session_id="s-owned", user_id="bob")) is None
|
||||
|
||||
|
||||
def test_agentchat_oper_reuses_explicit_query_sessions(db, monkeypatch):
|
||||
"""AgentChatOper 的同步与异步查询必须复用调用方会话。"""
|
||||
db.add(_chat("s-explicit", user_id="explicit"))
|
||||
monkeypatch.setattr(
|
||||
decorators,
|
||||
"ScopedSession",
|
||||
lambda: (_ for _ in ()).throw(AssertionError("不应创建额外同步会话")),
|
||||
)
|
||||
|
||||
from app.db.oper.agentchat import AgentChatOper
|
||||
|
||||
assert AgentChatOper(db.session).get("s-explicit", "explicit") is not None
|
||||
|
||||
async def check() -> None:
|
||||
"""验证异步 Agent 会话查询复用显式 AsyncSession。"""
|
||||
from app.db.session import async_session_scope
|
||||
|
||||
async with async_session_scope() as session:
|
||||
monkeypatch.setattr(
|
||||
decorators,
|
||||
"async_session_scope",
|
||||
lambda: (_ for _ in ()).throw(AssertionError("不应创建额外异步会话")),
|
||||
)
|
||||
assert await AgentChatOper(session).async_get("s-explicit", "explicit")
|
||||
|
||||
asyncio.run(check())
|
||||
|
||||
|
||||
def test_agentchat_model_legacy_query_keeps_keyword_abi(db, monkeypatch):
|
||||
"""旧插件以关键字直调 AgentChat 时仍自动补入短会话。"""
|
||||
db.add(_chat("s-legacy"))
|
||||
opened = []
|
||||
monkeypatch.setattr(
|
||||
decorators,
|
||||
"ScopedSession",
|
||||
lambda: (opened.append(True) or SessionFactory()),
|
||||
)
|
||||
|
||||
assert AgentChat.get_by_session(session_id="s-legacy") is not None
|
||||
assert opened == [True]
|
||||
|
||||
|
||||
def test_agentchat_list_by_page_matches_either_user_or_username(db):
|
||||
"""
|
||||
同时给出用户 ID 与用户名时按「或」匹配。
|
||||
|
||||
Reference in New Issue
Block a user