"""单元测试:前置权限检查""" import pytest import uuid from sqlalchemy.ext.asyncio import AsyncSession from app.core.project_permissions import ( role_has_api_permission, get_missing_prerequisites, ) from app.models.api_endpoint_permission import ApiEndpointPermission @pytest.mark.asyncio async def test_prerequisite_permission_satisfied(db_session: AsyncSession): """测试前置权限满足的情况""" study_id = uuid.uuid4() # 创建权限:主权限 + 前置权限都允许 main_perm = ApiEndpointPermission( study_id=study_id, role="CRA", endpoint_key="subjects:create", allowed=True, ) prereq_perm = ApiEndpointPermission( study_id=study_id, role="CRA", endpoint_key="sites:read", allowed=True, ) db_session.add(main_perm) db_session.add(prereq_perm) await db_session.commit() # 验证权限(包含前置权限检查) result = await role_has_api_permission( db_session, study_id, "CRA", "subjects:create", check_prerequisites=True ) assert result is True @pytest.mark.asyncio async def test_prerequisite_permission_missing(db_session: AsyncSession): """测试前置权限缺失的情况""" study_id = uuid.uuid4() # 创建权限:主权限允许,但前置权限不允许 main_perm = ApiEndpointPermission( study_id=study_id, role="CRA", endpoint_key="subjects:create", allowed=True, ) prereq_perm = ApiEndpointPermission( study_id=study_id, role="CRA", endpoint_key="sites:read", allowed=False, ) db_session.add(main_perm) db_session.add(prereq_perm) await db_session.commit() # 验证权限(包含前置权限检查) result = await role_has_api_permission( db_session, study_id, "CRA", "subjects:create", check_prerequisites=True ) assert result is False @pytest.mark.asyncio async def test_default_prerequisite_permission_satisfies_when_not_overridden(db_session: AsyncSession): """预设角色未配置前置权限时,应使用默认权限矩阵判断""" study_id = uuid.uuid4() # CRA 默认拥有 sites:read,因此未显式配置前置权限时仍满足前置条件。 main_perm = ApiEndpointPermission( study_id=study_id, role="CRA", endpoint_key="subjects:create", allowed=True, ) db_session.add(main_perm) await db_session.commit() # 验证权限(包含前置权限检查) result = await role_has_api_permission( db_session, study_id, "CRA", "subjects:create", check_prerequisites=True ) assert result is True @pytest.mark.asyncio async def test_custom_role_prerequisite_permission_not_configured(db_session: AsyncSession): """自定义角色无默认前置权限时,应被前置权限拦截""" study_id = uuid.uuid4() main_perm = ApiEndpointPermission( study_id=study_id, role="DATA_MANAGER", endpoint_key="subjects:create", allowed=True, ) db_session.add(main_perm) await db_session.commit() result = await role_has_api_permission( db_session, study_id, "DATA_MANAGER", "subjects:create", check_prerequisites=True ) assert result is False @pytest.mark.asyncio async def test_multiple_prerequisites_all_satisfied(db_session: AsyncSession): """测试多个前置权限都满足的情况""" study_id = uuid.uuid4() # 创建权限:主权限 + 所有前置权限都允许 main_perm = ApiEndpointPermission( study_id=study_id, role="CRA", endpoint_key="visits:create", allowed=True, ) prereq1 = ApiEndpointPermission( study_id=study_id, role="CRA", endpoint_key="subjects:read", allowed=True, ) prereq2 = ApiEndpointPermission( study_id=study_id, role="CRA", endpoint_key="sites:read", allowed=True, ) db_session.add(main_perm) db_session.add(prereq1) db_session.add(prereq2) await db_session.commit() # 验证权限 result = await role_has_api_permission( db_session, study_id, "CRA", "visits:create", check_prerequisites=True ) assert result is True @pytest.mark.asyncio async def test_multiple_prerequisites_one_missing(db_session: AsyncSession): """测试多个前置权限中有一个缺失的情况""" study_id = uuid.uuid4() # 创建权限:主权限允许,但其中一个前置权限不允许 main_perm = ApiEndpointPermission( study_id=study_id, role="CRA", endpoint_key="visits:create", allowed=True, ) prereq1 = ApiEndpointPermission( study_id=study_id, role="CRA", endpoint_key="subjects:read", allowed=True, ) prereq2 = ApiEndpointPermission( study_id=study_id, role="CRA", endpoint_key="sites:read", allowed=False, ) db_session.add(main_perm) db_session.add(prereq1) db_session.add(prereq2) await db_session.commit() # 验证权限 result = await role_has_api_permission( db_session, study_id, "CRA", "visits:create", check_prerequisites=True ) assert result is False @pytest.mark.asyncio async def test_get_missing_prerequisites_empty(db_session: AsyncSession): """测试获取缺失的前置权限 - 无缺失""" study_id = uuid.uuid4() # 创建权限:所有权限都允许 main_perm = ApiEndpointPermission( study_id=study_id, role="CRA", endpoint_key="subjects:create", allowed=True, ) prereq_perm = ApiEndpointPermission( study_id=study_id, role="CRA", endpoint_key="sites:read", allowed=True, ) db_session.add(main_perm) db_session.add(prereq_perm) await db_session.commit() # 获取缺失的前置权限 missing = await get_missing_prerequisites( db_session, study_id, "CRA", "subjects:create" ) assert missing == [] @pytest.mark.asyncio async def test_get_missing_prerequisites_single(db_session: AsyncSession): """测试获取缺失的前置权限 - 单个缺失""" study_id = uuid.uuid4() # 创建权限:前置权限不允许 main_perm = ApiEndpointPermission( study_id=study_id, role="CRA", endpoint_key="subjects:create", allowed=True, ) prereq_perm = ApiEndpointPermission( study_id=study_id, role="CRA", endpoint_key="sites:read", allowed=False, ) db_session.add(main_perm) db_session.add(prereq_perm) await db_session.commit() # 获取缺失的前置权限 missing = await get_missing_prerequisites( db_session, study_id, "CRA", "subjects:create" ) assert missing == ["sites:read"] @pytest.mark.asyncio async def test_get_missing_prerequisites_multiple(db_session: AsyncSession): """测试获取缺失的前置权限 - 多个缺失""" study_id = uuid.uuid4() # 创建权限:两个前置权限都不允许 main_perm = ApiEndpointPermission( study_id=study_id, role="CRA", endpoint_key="visits:create", allowed=True, ) prereq1 = ApiEndpointPermission( study_id=study_id, role="CRA", endpoint_key="subjects:read", allowed=False, ) prereq2 = ApiEndpointPermission( study_id=study_id, role="CRA", endpoint_key="sites:read", allowed=False, ) db_session.add(main_perm) db_session.add(prereq1) db_session.add(prereq2) await db_session.commit() # 获取缺失的前置权限 missing = await get_missing_prerequisites( db_session, study_id, "CRA", "visits:create" ) assert set(missing) == {"subjects:read", "sites:read"} @pytest.mark.asyncio async def test_prerequisite_check_disabled(db_session: AsyncSession): """测试禁用前置权限检查""" study_id = uuid.uuid4() # 创建权限:主权限允许,前置权限不允许 main_perm = ApiEndpointPermission( study_id=study_id, role="CRA", endpoint_key="subjects:create", allowed=True, ) prereq_perm = ApiEndpointPermission( study_id=study_id, role="CRA", endpoint_key="sites:read", allowed=False, ) db_session.add(main_perm) db_session.add(prereq_perm) await db_session.commit() # 验证权限(禁用前置权限检查) result = await role_has_api_permission( db_session, study_id, "CRA", "subjects:create", check_prerequisites=False ) assert result is True @pytest.mark.asyncio async def test_admin_bypasses_prerequisites(db_session: AsyncSession): """测试ADMIN角色绕过前置权限检查""" study_id = uuid.uuid4() # 不创建任何权限 # 验证权限(ADMIN应该总是被允许) result = await role_has_api_permission( db_session, study_id, "ADMIN", "subjects:create", check_prerequisites=True ) assert result is True @pytest.mark.asyncio async def test_prerequisite_with_no_prerequisites_operation(db_session: AsyncSession): """测试没有前置权限的操作""" study_id = uuid.uuid4() # 创建权限:操作允许(没有前置权限) perm = ApiEndpointPermission( study_id=study_id, role="CRA", endpoint_key="sites:read", allowed=True, ) db_session.add(perm) await db_session.commit() # 验证权限 result = await role_has_api_permission( db_session, study_id, "CRA", "sites:read", check_prerequisites=True ) assert result is True @pytest.mark.asyncio async def test_default_prerequisite_not_reported_missing_when_not_overridden(db_session: AsyncSession): """预设角色默认拥有前置权限时,不应报告缺失""" study_id = uuid.uuid4() # 创建权限:主权限允许,前置权限未配置 main_perm = ApiEndpointPermission( study_id=study_id, role="CRA", endpoint_key="subjects:create", allowed=True, ) db_session.add(main_perm) await db_session.commit() # 获取缺失的前置权限 missing = await get_missing_prerequisites( db_session, study_id, "CRA", "subjects:create" ) assert missing == [] @pytest.mark.asyncio async def test_custom_role_prerequisite_missing_not_configured(db_session: AsyncSession): """自定义角色无默认前置权限时,应报告缺失""" study_id = uuid.uuid4() main_perm = ApiEndpointPermission( study_id=study_id, role="DATA_MANAGER", endpoint_key="subjects:create", allowed=True, ) db_session.add(main_perm) await db_session.commit() missing = await get_missing_prerequisites( db_session, study_id, "DATA_MANAGER", "subjects:create" ) assert "sites:read" in missing