mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-10-29 11:27:43 +08:00
151 lines
4.6 KiB
Python
151 lines
4.6 KiB
Python
"""Agent 启动组合根的对象身份与装配时序测试。"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import subprocess
|
|
import sys
|
|
from types import SimpleNamespace
|
|
|
|
from app.startup.composition import agent as agent_composition
|
|
from app.startup.composition.runtime import RuntimeDependencies
|
|
|
|
|
|
class _StartedWorker:
|
|
"""仅允许在已启动状态读取容量的数据库 worker 桩。"""
|
|
|
|
def __init__(self, events: list[str]) -> None:
|
|
"""保存顺序记录并模拟已完成启动。"""
|
|
self.started = True
|
|
self.events = events
|
|
|
|
def snapshot(self) -> SimpleNamespace:
|
|
"""确认启动已完成后返回测试容量。"""
|
|
assert self.started is True
|
|
self.events.append("read-capacity")
|
|
return SimpleNamespace(capacity=17)
|
|
|
|
|
|
def _compose() -> tuple[agent_composition.AgentComposition, _StartedWorker]:
|
|
"""构造一组无需真实数据库连接的 Agent composition。"""
|
|
events = ["worker-started"]
|
|
worker = _StartedWorker(events)
|
|
runtime = SimpleNamespace(
|
|
worker=worker,
|
|
transaction=SimpleNamespace(sync=lambda operation: operation(object())),
|
|
)
|
|
system_config = SimpleNamespace(publish_many=lambda _values: None)
|
|
dependencies = RuntimeDependencies(
|
|
download_history=object(),
|
|
transfer_history=object(),
|
|
site=object(),
|
|
subscription=object(),
|
|
subscription_history=object(),
|
|
transfer_execution=object(),
|
|
message_helper=object(),
|
|
message_queue=object(),
|
|
)
|
|
composition = agent_composition.compose_agent(
|
|
runtime=runtime,
|
|
system_config=system_config,
|
|
dependencies=dependencies,
|
|
)
|
|
return composition, worker
|
|
|
|
|
|
def test_agent_composition_reuses_shared_objects_and_started_worker() -> None:
|
|
"""HostRuntime、Agent 数据与任务入口必须复用同一批对象。"""
|
|
composition, worker = _compose()
|
|
|
|
assert composition.data.tasks is composition.tasks
|
|
assert composition.persistence is composition.data.chat_persistence
|
|
assert composition.data.chat_persistence._async_executor is worker
|
|
assert composition.data.chat_persistence._capacity == 17
|
|
assert composition.execution._async_executor is worker
|
|
assert worker.events == ["worker-started", "read-capacity"]
|
|
|
|
|
|
def test_publish_agent_services_registers_composed_identity(monkeypatch) -> None:
|
|
"""兼容 provider 与 Agent initializer 必须收到 composition 中的原对象。"""
|
|
composition, _worker = _compose()
|
|
published: dict[str, object] = {}
|
|
|
|
monkeypatch.setattr(
|
|
agent_composition,
|
|
"configure_agent_chat_service",
|
|
lambda service: published.update(chat=service),
|
|
)
|
|
monkeypatch.setattr(
|
|
agent_composition,
|
|
"configure_agent_chat_persistence",
|
|
lambda service: published.update(persistence=service),
|
|
)
|
|
monkeypatch.setattr(
|
|
agent_composition,
|
|
"configure_agent_task_execution",
|
|
lambda service: published.update(execution=service),
|
|
)
|
|
|
|
agent_composition.publish_agent_services(
|
|
composition,
|
|
data_context_registrar=lambda data: published.update(data=data),
|
|
)
|
|
|
|
assert published == {
|
|
"chat": composition.data.chat,
|
|
"persistence": composition.data.chat_persistence,
|
|
"execution": composition.execution,
|
|
"data": composition.data,
|
|
}
|
|
|
|
|
|
def test_agent_composition_import_is_cold() -> None:
|
|
"""导入 Agent composition 不得登记服务或加载 Agent 实现层。"""
|
|
completed = subprocess.run(
|
|
[
|
|
sys.executable,
|
|
"-c",
|
|
r"""
|
|
import json
|
|
import sys
|
|
|
|
from app.application.agenttask import get_agent_task_execution_service
|
|
from app.application.messaging.chat import (
|
|
get_configured_agent_chat_persistence,
|
|
get_configured_agent_chat_service,
|
|
)
|
|
|
|
import app.startup.composition.agent
|
|
|
|
unconfigured = []
|
|
for getter in (
|
|
get_agent_task_execution_service,
|
|
get_configured_agent_chat_persistence,
|
|
get_configured_agent_chat_service,
|
|
):
|
|
try:
|
|
getter()
|
|
except RuntimeError:
|
|
unconfigured.append(True)
|
|
|
|
loaded_agent_implementation = sorted(
|
|
name for name in sys.modules if name == "app.agent" or name.startswith("app.agent.")
|
|
)
|
|
print(json.dumps({
|
|
"initializer_loaded": "app.startup.initializers.agent" in sys.modules,
|
|
"loaded_agent_implementation": loaded_agent_implementation,
|
|
"unconfigured": len(unconfigured),
|
|
}))
|
|
""",
|
|
],
|
|
check=True,
|
|
capture_output=True,
|
|
text=True,
|
|
)
|
|
|
|
assert json.loads(completed.stdout) == {
|
|
"initializer_loaded": False,
|
|
"loaded_agent_implementation": [],
|
|
"unconfigured": 3,
|
|
}
|