Files
ctms/backend/tests/test_permission_templates.py
T
2026-05-26 14:46:01 +08:00

302 lines
10 KiB
Python

"""权限模板服务单元测试"""
from __future__ import annotations
import uuid
import pytest
from app.models.permission_template import PermissionTemplate, TemplateType
from app.schemas.permission_template import PermissionTemplateCreate, PermissionTemplateUpdate
from app.services.permission_template_service import PermissionTemplateService
SAMPLE_PERMISSIONS = {
"PM": {
"subjects:create": True,
"subjects:read": True,
"subjects:update": True,
"subjects:delete": False,
},
"CRA": {
"subjects:create": False,
"subjects:read": True,
"subjects:update": False,
"subjects:delete": False,
},
}
@pytest.fixture
def user_id() -> uuid.UUID:
return uuid.uuid4()
# ---------------------------------------------------------------------------
# 创建模板
# ---------------------------------------------------------------------------
@pytest.mark.asyncio
async def test_create_template_success(db_session, user_id):
payload = PermissionTemplateCreate(
name="测试模板",
description="用于测试",
template_type=TemplateType.CUSTOM,
permissions=SAMPLE_PERMISSIONS,
)
template = await PermissionTemplateService.create_template(db_session, payload, user_id)
assert template.id is not None
assert template.name == "测试模板"
assert template.is_system is False
assert template.template_type == TemplateType.CUSTOM
assert template.permissions == SAMPLE_PERMISSIONS
@pytest.mark.asyncio
async def test_create_template_creates_version_1(db_session, user_id):
payload = PermissionTemplateCreate(
name="版本测试",
template_type=TemplateType.CUSTOM,
permissions=SAMPLE_PERMISSIONS,
)
template = await PermissionTemplateService.create_template(db_session, payload, user_id)
await db_session.refresh(template, ["versions"])
assert len(template.versions) == 1
assert template.versions[0].version == 1
assert template.versions[0].change_log == "初始版本"
@pytest.mark.asyncio
async def test_create_template_rejects_non_custom_role_type(db_session, user_id):
payload = PermissionTemplateCreate(
name="预设角色不允许新增",
template_type=TemplateType.ROLE,
permissions=SAMPLE_PERMISSIONS,
)
with pytest.raises(ValueError, match="只能新增自定义角色"):
await PermissionTemplateService.create_template(db_session, payload, user_id)
@pytest.mark.asyncio
async def test_create_template_invalid_endpoint_key(db_session, user_id):
payload = PermissionTemplateCreate(
name="无效模板",
template_type=TemplateType.CUSTOM,
permissions={"PM": {"nonexistent:action": True}},
)
with pytest.raises(ValueError, match="权限操作 nonexistent:action 不存在"):
await PermissionTemplateService.create_template(db_session, payload, user_id)
@pytest.mark.asyncio
async def test_create_template_invalid_permission_value(db_session, user_id):
payload = PermissionTemplateCreate(
name="无效值模板",
template_type=TemplateType.CUSTOM,
permissions={"PM": {"subjects:read": "yes"}}, # type: ignore
)
with pytest.raises(ValueError, match="必须是布尔类型"):
await PermissionTemplateService.create_template(db_session, payload, user_id)
# ---------------------------------------------------------------------------
# 获取模板
# ---------------------------------------------------------------------------
@pytest.mark.asyncio
async def test_get_template_exists(db_session, user_id):
template = PermissionTemplate(
name="获取测试",
template_type=TemplateType.ROLE,
permissions=SAMPLE_PERMISSIONS,
)
db_session.add(template)
await db_session.commit()
await db_session.refresh(template)
fetched = await PermissionTemplateService.get_template(db_session, template.id)
assert fetched is not None
assert fetched.id == template.id
assert fetched.name == "获取测试"
@pytest.mark.asyncio
async def test_get_template_not_found(db_session):
result = await PermissionTemplateService.get_template(db_session, uuid.uuid4())
assert result is None
# ---------------------------------------------------------------------------
# 列表模板
# ---------------------------------------------------------------------------
@pytest.mark.asyncio
async def test_list_templates_filter_by_type(db_session, user_id):
db_session.add(
PermissionTemplate(
name="角色模板",
template_type=TemplateType.ROLE,
is_system=True,
category="PM",
permissions=SAMPLE_PERMISSIONS,
)
)
await PermissionTemplateService.create_template(
db_session,
PermissionTemplateCreate(name="自定义角色", template_type=TemplateType.CUSTOM, permissions=SAMPLE_PERMISSIONS),
user_id,
)
await db_session.commit()
role_templates = await PermissionTemplateService.list_templates(db_session, template_type=TemplateType.ROLE)
assert all(t.template_type == TemplateType.ROLE for t in role_templates)
assert len(role_templates) >= 1
@pytest.mark.asyncio
async def test_list_templates_excludes_qa_system_preset(db_session):
qa_template = PermissionTemplate(
name="质量保证",
template_type=TemplateType.ROLE,
is_system=True,
category="QA",
permissions={"QA": {"subjects:read": True}},
)
pm_template = PermissionTemplate(
name="PM",
template_type=TemplateType.ROLE,
is_system=True,
category="PM",
permissions={"PM": {"subjects:read": True}},
)
db_session.add_all([qa_template, pm_template])
await db_session.commit()
role_templates = await PermissionTemplateService.list_templates(db_session, template_type=TemplateType.ROLE)
assert "PM" in {template.category for template in role_templates}
assert "QA" not in {template.category for template in role_templates if template.is_system}
# ---------------------------------------------------------------------------
# 更新模板
# ---------------------------------------------------------------------------
@pytest.mark.asyncio
async def test_update_template_name(db_session, user_id):
created = await PermissionTemplateService.create_template(
db_session,
PermissionTemplateCreate(name="旧名称", template_type=TemplateType.CUSTOM, permissions=SAMPLE_PERMISSIONS),
user_id,
)
updated = await PermissionTemplateService.update_template(
db_session, created.id, PermissionTemplateUpdate(name="新名称")
)
assert updated.name == "新名称"
@pytest.mark.asyncio
async def test_update_template_permissions_creates_new_version(db_session, user_id):
created = await PermissionTemplateService.create_template(
db_session,
PermissionTemplateCreate(name="版本测试2", template_type=TemplateType.CUSTOM, permissions=SAMPLE_PERMISSIONS),
user_id,
)
new_perms = {"PM": {"subjects:read": True}}
await PermissionTemplateService.update_template(
db_session, created.id, PermissionTemplateUpdate(permissions=new_perms)
)
updated = await PermissionTemplateService.get_template(db_session, created.id)
await db_session.refresh(updated, ["versions"])
assert len(updated.versions) == 2
assert updated.versions[-1].version == 2
assert updated.permissions == new_perms
@pytest.mark.asyncio
async def test_update_system_template_allows_name_and_description(db_session):
system_template = PermissionTemplate(
name="系统模板",
description="旧描述",
template_type=TemplateType.ROLE,
is_system=True,
permissions=SAMPLE_PERMISSIONS,
)
db_session.add(system_template)
await db_session.commit()
await db_session.refresh(system_template)
updated = await PermissionTemplateService.update_template(
db_session,
system_template.id,
PermissionTemplateUpdate(name="新名称", description="新描述"),
)
assert updated.name == "新名称"
assert updated.description == "新描述"
assert updated.permissions == SAMPLE_PERMISSIONS
@pytest.mark.asyncio
async def test_update_system_template_rejects_protected_fields(db_session):
system_template = PermissionTemplate(
name="系统模板",
template_type=TemplateType.ROLE,
is_system=True,
permissions=SAMPLE_PERMISSIONS,
)
db_session.add(system_template)
await db_session.commit()
await db_session.refresh(system_template)
with pytest.raises(ValueError, match="不允许修改系统预设模板"):
await PermissionTemplateService.update_template(
db_session,
system_template.id,
PermissionTemplateUpdate(permissions={"PM": {"subjects:read": True}}),
)
# ---------------------------------------------------------------------------
# 删除模板
# ---------------------------------------------------------------------------
@pytest.mark.asyncio
async def test_delete_template_success(db_session, user_id):
created = await PermissionTemplateService.create_template(
db_session,
PermissionTemplateCreate(name="待删除", template_type=TemplateType.CUSTOM, permissions=SAMPLE_PERMISSIONS),
user_id,
)
await PermissionTemplateService.delete_template(db_session, created.id)
assert await PermissionTemplateService.get_template(db_session, created.id) is None
@pytest.mark.asyncio
async def test_delete_system_template_raises(db_session):
system_template = PermissionTemplate(
name="系统模板2",
template_type=TemplateType.ROLE,
is_system=True,
permissions=SAMPLE_PERMISSIONS,
)
db_session.add(system_template)
await db_session.commit()
await db_session.refresh(system_template)
with pytest.raises(ValueError, match="不允许删除系统预设模板"):
await PermissionTemplateService.delete_template(db_session, system_template.id)
@pytest.mark.asyncio
async def test_delete_nonexistent_template_raises(db_session):
with pytest.raises(ValueError, match="不存在"):
await PermissionTemplateService.delete_template(db_session, uuid.uuid4())