Files
MoviePilot/tests/test_server_sharing_service.py
DDSRem 2de976f6b3 Merge pull request #7050 from DDSRem-Dev/codex-comment-migration
docs: 统一全项目中文注释和结构化契约说明
2026-10-17 19:26:29 +08:00

215 lines
6.1 KiB
Python

"""
验证共享识别服务的查询、上报与缓存行为。
"""
import asyncio
import json
from types import SimpleNamespace
from unittest.mock import AsyncMock, Mock
from app.application.server.share import ServerSharingService
from app.application.workflow import WorkflowSnapshot
def _workflow(*, actions=(), flows=()) -> WorkflowSnapshot:
"""
构造中心服务分享使用的真实工作流快照。
"""
return WorkflowSnapshot(
id=1,
name="Demo Workflow",
description="demo",
timer=None,
trigger_type="manual",
event_type=None,
event_conditions={},
state="W",
current_action=None,
result=None,
run_count=0,
actions=actions,
flows=flows,
context={"private": True},
execution_config={},
execution_state={},
add_time=None,
last_time=None,
)
def _service(**overrides) -> ServerSharingService:
"""
构造不依赖数据库和网络的中心服务分享用例。
"""
def handle_response(response, clear):
"""
模拟旧 Helper 的成功响应和缓存失效顺序。
"""
clear()
return response.status_code == 200, ""
defaults = {
"subscribe_provider": Mock(return_value=None),
"async_subscribe_provider": AsyncMock(return_value=None),
"workflow_provider": Mock(return_value=None),
"async_workflow_provider": AsyncMock(return_value=None),
"user_uuid_provider": Mock(return_value="user-1"),
"subscribe_sender": Mock(),
"async_subscribe_sender": AsyncMock(),
"workflow_sender": Mock(),
"async_workflow_sender": AsyncMock(),
"response_handler": handle_response,
"subscribe_cache_clearer": Mock(),
"workflow_cache_clearer": Mock(),
}
defaults.update(overrides)
return ServerSharingService(**defaults)
def test_subscribe_share_builds_public_payload_and_clears_cache_after_success():
"""
订阅分享隐藏本地字段,并在成功响应后触发缓存失效。
"""
sender = Mock(return_value=SimpleNamespace(status_code=200))
clear = Mock()
subscribe = SimpleNamespace(to_dict=lambda: {
"name": "Demo",
"type": "电影",
"media_source": "themoviedb",
"media_id": "123",
"username": "private",
})
service = _service(
subscribe_provider=Mock(return_value=subscribe),
subscribe_sender=sender,
subscribe_cache_clearer=clear,
)
result = service.share_subscribe(
enabled=True,
subscribe_id=1,
share_title="Title",
share_comment="Comment",
share_user="User",
)
assert result == (True, "")
payload = sender.call_args.args[0]
assert payload["share_uid"] == "user-1"
assert payload["media_source"] == "themoviedb"
assert "username" not in payload
clear.assert_called_once_with()
def test_workflow_validation_stops_before_transport():
"""
缺少动作或流程的工作流不会进入中心服务传输。
"""
sender = Mock()
workflow = _workflow(flows=({"id": 1},))
service = _service(
workflow_provider=Mock(return_value=workflow),
workflow_sender=sender,
)
result = service.share_workflow(
enabled=True,
workflow_id=1,
share_title="Title",
share_comment="Comment",
share_user="User",
)
assert result == (False, "请分享有动作和流程的工作流")
sender.assert_not_called()
def test_workflow_share_serializes_snapshot_without_local_fields():
"""
同步工作流分享从冻结快照生成兼容载荷并剔除本地上下文。
"""
sender = Mock(return_value=SimpleNamespace(status_code=200))
workflow = _workflow(
actions=({"id": "action-1"},),
flows=({"source": "action-1", "target": "end"},),
)
service = _service(
workflow_provider=Mock(return_value=workflow),
workflow_sender=sender,
)
result = service.share_workflow(
enabled=True,
workflow_id=1,
share_title="Title",
share_comment="Comment",
share_user="User",
)
assert result == (True, "")
payload = sender.call_args.args[0]
assert "id" not in payload
assert "context" not in payload
assert json.loads(payload["actions"]) == [{"id": "action-1"}]
assert json.loads(payload["flows"]) == [
{"source": "action-1", "target": "end"}
]
def test_async_subscribe_share_uses_async_reader_and_transport():
"""
异步分享路径不会回退到同步数据库或网络端口。
"""
subscribe = SimpleNamespace(to_dict=lambda: {
"name": "Demo",
"type": "电影",
"media_source": "themoviedb",
"media_id": "123",
})
reader = AsyncMock(return_value=subscribe)
sender = AsyncMock(return_value=SimpleNamespace(status_code=200))
service = _service(
async_subscribe_provider=reader,
async_subscribe_sender=sender,
)
result = asyncio.run(service.async_share_subscribe(
enabled=True,
subscribe_id=1,
share_title="Title",
share_comment="Comment",
share_user="User",
))
assert result == (True, "")
reader.assert_awaited_once_with(1)
sender.assert_awaited_once()
def test_async_workflow_share_uses_snapshot_reader_and_transport():
"""
异步工作流分享复用同一快照契约且不回退同步端口。
"""
workflow = _workflow(
actions=({"id": "action-1"},),
flows=({"source": "action-1", "target": "end"},),
)
reader = AsyncMock(return_value=workflow)
sender = AsyncMock(return_value=SimpleNamespace(status_code=200))
service = _service(
async_workflow_provider=reader,
async_workflow_sender=sender,
)
result = asyncio.run(service.async_share_workflow(
enabled=True,
workflow_id=1,
share_title="Title",
share_comment="Comment",
share_user="User",
))
assert result == (True, "")
reader.assert_awaited_once_with(1)
sender.assert_awaited_once()