Files
MoviePilot/tests/test_task_ownership_gate.py
T

72 lines
2.5 KiB
Python

"""TaskRegistry owner 静态门禁回归测试。"""
import textwrap
from pathlib import Path
from scripts.architecture.task_ownership import collect_task_owner_violations
def _scan_source(tmp_path: Path, source: str):
"""构造最小宿主源码并通过公开扫描入口返回违规。"""
source_path = tmp_path / "app/api/sample.py"
source_path.parent.mkdir(parents=True)
source_path.write_text(textwrap.dedent(source), encoding="utf-8")
return collect_task_owner_violations(tmp_path)
def test_host_task_registry_calls_use_literal_owner() -> None:
"""当前 canonical 宿主的登记器调用必须保持 owner 零债务。"""
assert collect_task_owner_violations() == []
def test_owner_gate_tracks_known_registry_without_matching_same_named_methods(
tmp_path: Path,
) -> None:
"""门禁只检查可证明的登记器接收者,并区分缺失、动态和空 owner。"""
violations = _scan_source(
tmp_path,
"""
from app.api.context import resolve_background_task_registry as resolve_registry
from app.runtime.tasks import TaskRegistry, get_task_registry
def schedule(task_registry: TaskRegistry, unrelated, dynamic_owner):
unrelated.create(work())
task_registry.create(work())
resolve_registry(task_registry).create_sync(work, owner=dynamic_owner)
get_task_registry().register(task, owner=" ")
""",
)
assert [violation.method for violation in violations] == [
"create",
"create_sync",
"register",
]
assert [violation.reason for violation in violations] == [
"缺少显式 owner",
"的 owner 必须是非空字符串字面量",
"的 owner 必须是非空字符串字面量",
]
def test_owner_gate_accepts_aliases_and_stable_literal_owners(tmp_path: Path) -> None:
"""类、模块和工厂别名仍应被识别,稳定字符串 owner 可以通过。"""
violations = _scan_source(
tmp_path,
"""
import app.runtime.tasks as runtime_tasks
from app.runtime.tasks import TaskRegistry as Registry
def schedule(task_registry: Registry):
local_registry = runtime_tasks.TaskRegistry()
task_registry.create(work(), owner="api.example.async")
local_registry.create_sync(work, owner="api.example.sync")
runtime_tasks.get_task_registry().register(
task,
owner="api.example.existing",
)
""",
)
assert violations == []