Files
RuoYi-Vue3-FastAPI/ruoyi-fastapi-backend/tests/module_plugin/controller/test_plugin_release_controller.py
T
insistence 4bd83bc7cd feat: 支持 v2 插件、独立前端和签名制品发布 (#130)
* feat: 支持 v2 插件、原生扩展与签名发布

* fix: 修复测试

* feat: 增强宿主 SDK、运行观测与制品维护能力

* feat: 增强文件传输、配置观测与本地开发能力

* feat: 支持 SSE 实时事件流并完善开发脚手架

* feat: 完善长连接鉴权复核与关闭回收

* feat: 增强生命周期与任务关闭可靠性

* feat: 收紧健康检查契约并补齐前端与真实网络验收

* feat: 增加SDK溯源与离线更新工具并验证跨版本兼容

* feat: 增加持久化业务示例与受控 Python 交付

* feat: 增加统一运行诊断与多worker状态观测

* feat: 增加固定目标发布等待与自动验收

* fix: 修复多环境插件部署前缀与代理配置不一致

* fix: 修复测试
2026-10-09 23:49:45 +08:00

75 lines
3.0 KiB
Python

import json
from types import SimpleNamespace
from unittest.mock import AsyncMock
import pytest
from common.aspect.interface_auth import CheckUserInterfaceAuth
from module_plugin.controller import plugin_release_controller as controller
DIGEST = 'a' * 64
def test_artifact_http_endpoints_are_get_only_and_require_query_permission() -> None:
"""验证制品 HTTP 接口只接受查询且要求插件查询权限。"""
routes = controller.plugin_release_controller.routes
assert {route.path for route in routes} == {
'/system/plugin/artifacts/list',
'/system/plugin/release/status',
'/system/plugin/release/plan',
}
for route in routes:
assert route.methods == {'GET'}
assert any(
isinstance(dependency.dependency, CheckUserInterfaceAuth)
and dependency.dependency.perm == 'system:plugin:query'
for dependency in route.dependencies
)
@pytest.mark.asyncio
async def test_readonly_endpoints_forward_filters_and_plan_target(monkeypatch: pytest.MonkeyPatch) -> None:
"""验证只读接口正确传递过滤条件与目标制品信息。"""
service = SimpleNamespace(
catalog=SimpleNamespace(list_artifacts=AsyncMock(return_value={'ok': True, 'artifacts': []})),
status=AsyncMock(return_value={'ok': True, 'releases': []}),
plan=AsyncMock(return_value={'ok': True, 'pluginId': 'demo', 'digest': DIGEST}),
)
monkeypatch.setattr(controller, 'get_plugin_deployment_service', lambda: service)
responses = [
await controller.list_plugin_artifacts('demo'),
await controller.get_plugin_release_status('demo'),
await controller.plan_plugin_release('demo', DIGEST),
]
assert all(json.loads(response.body)['success'] for response in responses)
service.catalog.list_artifacts.assert_awaited_once_with('demo')
service.status.assert_awaited_once_with('demo')
service.plan.assert_awaited_once_with('demo', DIGEST)
@pytest.mark.asyncio
async def test_disabled_feature_returns_clear_blocked_response(monkeypatch: pytest.MonkeyPatch) -> None:
"""验证功能关闭时返回明确的受限响应。"""
def unavailable() -> None:
raise ValueError('签名制品发布功能未启用')
monkeypatch.setattr(controller, 'get_plugin_deployment_service', unavailable)
body = json.loads((await controller.get_plugin_release_status()).body)
assert body['success'] is False
assert body['data']['status'] == 'blocked'
assert '未启用' in body['msg']
@pytest.mark.asyncio
async def test_unexpected_database_error_does_not_expose_connection_details(monkeypatch: pytest.MonkeyPatch) -> None:
"""验证意外数据库异常不会将连接细节返回客户端。"""
def unavailable() -> None:
raise RuntimeError('mysql://secret-user:secret-password@host')
monkeypatch.setattr(controller, 'get_plugin_deployment_service', unavailable)
response = await controller.list_plugin_artifacts()
assert json.loads(response.body)['success'] is False
assert b'secret-password' not in response.body