refactor: isolate pending transfer and config queries

This commit is contained in:
jxxghp
2026-08-23 14:29:59 +08:00
parent 8fc9a021b0
commit 2120b8040a
10 changed files with 104 additions and 30 deletions
+3 -18
View File
@@ -1,12 +1,12 @@
{
"model_decorators": {
"by_kind": {
"async_db_query": 7,
"async_db_query": 6,
"async_db_update": 0,
"db_query": 5,
"db_query": 3,
"db_update": 0
},
"count": 12,
"count": 9,
"methods": [
{
"decorator": "async_db_query",
@@ -52,21 +52,6 @@
"decorator": "db_query",
"file": "app/db/models/subscribehistory.py",
"method": "SubscribeHistory.list_by_type"
},
{
"decorator": "async_db_query",
"file": "app/db/models/systemconfig.py",
"method": "SystemConfig.async_get_by_key"
},
{
"decorator": "db_query",
"file": "app/db/models/systemconfig.py",
"method": "SystemConfig.get_by_key"
},
{
"decorator": "db_query",
"file": "app/db/models/transferpending.py",
"method": "TransferPending.list_all"
}
]
},
+2 -2
View File
@@ -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"] == 12
assert sum(baseline["model_decorators"]["by_kind"].values()) == 12
assert baseline["model_decorators"]["count"] == 9
assert sum(baseline["model_decorators"]["by_kind"].values()) == 9
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": []}
+42
View File
@@ -9,12 +9,14 @@ import asyncio
import pytest
from app.db import decorators
from app.db.models.passkey import PassKey
from app.db.models.systemconfig import SystemConfig
from app.db.models.user import User
from app.db.models.userconfig import UserConfig
from app.db.oper.passkey import PassKeyOper
from app.db.oper.user import UserOper
from app.db.session import SessionFactory, async_session_scope
@pytest.fixture(autouse=True)
@@ -48,6 +50,46 @@ def test_systemconfig_get_by_key_returns_none_when_absent(db):
assert SystemConfig.get_by_key(db.session, "mp-test-missing") is None
def test_systemconfig_queries_reuse_explicit_sessions(db, monkeypatch):
"""SystemConfig 显式同步与异步会话不得触发兼容会话。"""
db.add(SystemConfig(key="mp-explicit-config", value=True))
monkeypatch.setattr(
decorators,
"ScopedSession",
lambda: (_ for _ in ()).throw(AssertionError("不应创建额外同步会话")),
)
assert SystemConfig.get_by_key(db.session, "mp-explicit-config") is not None
async def check() -> None:
"""验证异步配置查询复用显式 AsyncSession。"""
async with async_session_scope() as session:
monkeypatch.setattr(
decorators,
"async_session_scope",
lambda: (_ for _ in ()).throw(AssertionError("不应创建额外异步会话")),
)
assert await SystemConfig.async_get_by_key(
session,
"mp-explicit-config",
) is not None
asyncio.run(check())
def test_systemconfig_model_legacy_query_keeps_keyword_abi(db, monkeypatch):
"""旧插件以关键字直调 SystemConfig 时仍自动补入短会话。"""
db.add(SystemConfig(key="mp-legacy-config", value=True))
opened = []
monkeypatch.setattr(
decorators,
"ScopedSession",
lambda: (opened.append(True) or SessionFactory()),
)
assert SystemConfig.get_by_key(key="mp-legacy-config") is not None
assert opened == [True]
def test_systemconfig_delete_by_key_removes_only_that_key(db):
"""
按键删除只能删掉那一个键,误删会静默丢失其他配置。
+36
View File
@@ -7,8 +7,10 @@
"""
import pytest
from app.db import decorators
from app.db.models.transferpending import TransferPending
from app.db.oper.transferpending import TransferPendingOper
from app.db.session import SessionFactory
@pytest.fixture(autouse=True)
@@ -150,6 +152,40 @@ def test_oper_returns_plain_tuples_not_orm_instances(db):
assert all(isinstance(item, tuple) for item in listed)
def test_oper_reuses_explicit_query_session(db, monkeypatch):
"""TransferPendingOper 查询必须复用调用方会话。"""
db.add(TransferPending(
storage="local",
src_path="/mnt/explicit.mkv",
created_at="2026-08-13 10:00:00",
))
monkeypatch.setattr(
decorators,
"ScopedSession",
lambda: (_ for _ in ()).throw(AssertionError("不应创建额外同步会话")),
)
assert ("local", "/mnt/explicit.mkv") in TransferPendingOper(db.session).list_all()
def test_model_legacy_query_keeps_keyword_abi(db, monkeypatch):
"""旧插件以关键字直调 TransferPending 时仍自动补入短会话。"""
db.add(TransferPending(
storage="local",
src_path="/mnt/legacy.mkv",
created_at="2026-08-13 10:00:00",
))
opened = []
monkeypatch.setattr(
decorators,
"ScopedSession",
lambda: (opened.append(True) or SessionFactory()),
)
assert TransferPending.list_all(limit=1)
assert opened == [True]
def test_oper_drops_rows_with_missing_fields(db):
"""
回放时必须跳过字段残缺的历史遗留行,不能把空存储送进整理链。