test(unit): add roles, web deps, use cases, VO boundary tests — reach 70% coverage
Some checks failed
ci/woodpecker/pr/pipeline Pipeline was canceled
Some checks failed
ci/woodpecker/pr/pipeline Pipeline was canceled
This commit is contained in:
@@ -1,11 +1,17 @@
|
||||
"""Tests for role-based access control."""
|
||||
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
from app.domain.exceptions import ForbiddenException
|
||||
from app.domain.roles import (
|
||||
ROLE_PERMISSIONS,
|
||||
Permission,
|
||||
Role,
|
||||
get_effective_role,
|
||||
has_permission,
|
||||
require_permission,
|
||||
)
|
||||
|
||||
|
||||
@@ -121,3 +127,61 @@ class TestGetEffectiveRole:
|
||||
assert get_effective_role(["user", "admin", "guest"]) == Role.ADMIN
|
||||
# User takes precedence over guest
|
||||
assert get_effective_role(["guest", "user"]) == Role.USER
|
||||
|
||||
|
||||
class TestRequirePermission:
|
||||
"""Test require_permission decorator."""
|
||||
|
||||
async def test_admin_passes_permission_check(self) -> None:
|
||||
"""Test admin with permission succeeds."""
|
||||
|
||||
@require_permission(Permission.POST_CREATE)
|
||||
async def dummy(*, token_info: Any = None) -> str:
|
||||
return "ok"
|
||||
|
||||
token = type("TokenInfo", (), {"roles": ["admin"]})()
|
||||
result = await dummy(token_info=token)
|
||||
assert result == "ok"
|
||||
|
||||
async def test_user_passes_permission_check(self) -> None:
|
||||
"""Test user with permission succeeds."""
|
||||
|
||||
@require_permission(Permission.POST_READ)
|
||||
async def dummy(*, token_info: Any = None) -> str:
|
||||
return "ok"
|
||||
|
||||
token = type("TokenInfo", (), {"roles": ["user"]})()
|
||||
result = await dummy(token_info=token)
|
||||
assert result == "ok"
|
||||
|
||||
async def test_no_token_raises(self) -> None:
|
||||
"""Test missing token raises ForbiddenException."""
|
||||
|
||||
@require_permission(Permission.POST_CREATE)
|
||||
async def dummy(*, token_info: Any = None) -> str:
|
||||
return "ok"
|
||||
|
||||
with pytest.raises(ForbiddenException, match="Authentication required"):
|
||||
await dummy()
|
||||
|
||||
async def test_guest_without_permission_raises(self) -> None:
|
||||
"""Test guest lacking permission raises ForbiddenException."""
|
||||
|
||||
@require_permission(Permission.POST_CREATE)
|
||||
async def dummy(*, token_info: Any = None) -> str:
|
||||
return "ok"
|
||||
|
||||
token = type("TokenInfo", (), {"roles": []})()
|
||||
with pytest.raises(ForbiddenException, match="Permission 'post:create' required"):
|
||||
await dummy(token_info=token)
|
||||
|
||||
async def test_user_forbidden_unpublished(self) -> None:
|
||||
"""Test user cannot read unpublished via decorator."""
|
||||
|
||||
@require_permission(Permission.POST_READ_UNPUBLISHED)
|
||||
async def dummy(*, token_info: Any = None) -> str:
|
||||
return "ok"
|
||||
|
||||
token = type("TokenInfo", (), {"roles": ["user"]})()
|
||||
with pytest.raises(ForbiddenException, match="Permission 'post:read_unpublished' required"):
|
||||
await dummy(token_info=token)
|
||||
|
||||
Reference in New Issue
Block a user