Saas-Base / apps /access /tests.py
rsnarsna
fifth commit
bccb680
Raw
History Blame Contribute Delete
8.65 kB
"""
Tests for the access control app β€” Phase 3.
Covers role/permission CRUD, role↔permission binding,
user↔role assignment, permission checking, and seeding.
"""
from django.test import TestCase
from django.urls import reverse
from apps.accounts.services import register_user
from apps.access.models import Permission, Role, RolePermission, UserRole
from apps.access.services import (
assign_permission_to_role,
assign_role,
check_access,
create_permission,
create_role,
delete_role,
get_role,
get_role_permissions,
get_user_permissions,
get_user_roles,
has_permission,
has_role,
list_roles,
revoke_permission_from_role,
revoke_role,
seed_roles_and_permissions,
)
from core.exceptions import NotFoundError, ValidationError
# ─── Role Tests ──────────────────────────────────────────────────────────────
class RoleTests(TestCase):
"""Test role CRUD operations."""
def test_create_role(self):
"""Create a new role."""
role = create_role("test_admin", Role.Scope.PLATFORM, "Test admin role.")
self.assertEqual(role.name, "test_admin")
self.assertEqual(role.scope, Role.Scope.PLATFORM)
def test_create_duplicate_role_fails(self):
"""Cannot create a role with duplicate name."""
create_role("admin")
with self.assertRaises(ValidationError):
create_role("admin")
def test_get_role(self):
"""Retrieve a role by name."""
create_role("viewer")
role = get_role("viewer")
self.assertEqual(role.name, "viewer")
def test_get_nonexistent_role_fails(self):
"""Getting a non-existent role raises NotFoundError."""
with self.assertRaises(NotFoundError):
get_role("nonexistent")
def test_delete_role(self):
"""Delete a role removes it from the database."""
create_role("temp")
delete_role("temp")
with self.assertRaises(NotFoundError):
get_role("temp")
def test_list_roles_by_scope(self):
"""List roles filtered by scope."""
create_role("platform_a", Role.Scope.PLATFORM)
create_role("org_a", Role.Scope.ORG)
platform_roles = list_roles(scope=Role.Scope.PLATFORM)
self.assertTrue(all(r.scope == Role.Scope.PLATFORM for r in platform_roles))
# ─── Permission Tests ───────────────────────────────────────────────────────
class PermissionTests(TestCase):
"""Test permission CRUD."""
def test_create_permission(self):
"""Create a new permission."""
perm = create_permission("test_users", "read", "View users")
self.assertEqual(perm.codename, "test_users:read")
def test_create_duplicate_permission_fails(self):
"""Cannot create duplicate permission."""
create_permission("test_users", "read")
with self.assertRaises(ValidationError):
create_permission("test_users", "read")
# ─── Role ↔ Permission Tests ────────────────────────────────────────────────
class RolePermissionTests(TestCase):
"""Test role-permission binding."""
def setUp(self):
self.role = create_role("editor", Role.Scope.ORG)
self.perm1 = create_permission("articles", "read")
self.perm2 = create_permission("articles", "write")
def test_assign_permission_to_role(self):
"""Assign a permission to a role."""
assign_permission_to_role("editor", "articles", "read")
perms = get_role_permissions("editor")
self.assertIn("articles:read", perms)
def test_revoke_permission_from_role(self):
"""Revoke a permission from a role."""
assign_permission_to_role("editor", "articles", "read")
revoke_permission_from_role("editor", "articles", "read")
perms = get_role_permissions("editor")
self.assertNotIn("articles:read", perms)
def test_multiple_permissions_on_role(self):
"""Role can have multiple permissions."""
assign_permission_to_role("editor", "articles", "read")
assign_permission_to_role("editor", "articles", "write")
perms = get_role_permissions("editor")
self.assertEqual(len(perms), 2)
# ─── User ↔ Role Tests ──────────────────────────────────────────────────────
class UserRoleTests(TestCase):
"""Test user-role assignment and permission checking."""
def setUp(self):
self.user = register_user("rbac@example.com", "StrongPass123!", org_name="Test Org", business_type="SaaS")
self.role = create_role("test_platform_admin", Role.Scope.PLATFORM)
create_permission("test_usersxyz", "read")
create_permission("test_usersxyz", "write")
assign_permission_to_role("test_platform_admin", "test_usersxyz", "read")
assign_permission_to_role("test_platform_admin", "test_usersxyz", "write")
def test_assign_role_to_user(self):
"""Assign a role to a user."""
assign_role(self.user, "test_platform_admin")
self.assertTrue(has_role(self.user, "test_platform_admin"))
def test_revoke_role_from_user(self):
"""Revoke a role from a user."""
assign_role(self.user, "test_platform_admin")
revoke_role(self.user, "test_platform_admin")
self.assertFalse(has_role(self.user, "test_platform_admin"))
def test_get_user_roles(self):
"""Get all roles for a user."""
assign_role(self.user, "test_platform_admin")
roles = get_user_roles(self.user)
self.assertIn("test_platform_admin", roles)
def test_has_permission_via_role(self):
"""User has permission through assigned role."""
assign_role(self.user, "test_platform_admin")
self.assertTrue(has_permission(self.user, "test_usersxyz", "read"))
self.assertTrue(has_permission(self.user, "test_usersxyz", "write"))
def test_no_permission_without_role(self):
"""User without role has no permissions."""
self.assertFalse(has_permission(self.user, "test_usersxyz", "read"))
def test_check_access_codename_format(self):
"""check_access works with 'resource:action' format."""
assign_role(self.user, "test_platform_admin")
self.assertTrue(check_access(self.user, "test_usersxyz:read"))
self.assertFalse(check_access(self.user, "billing:read"))
def test_get_user_permissions_set(self):
"""get_user_permissions returns full set."""
assign_role(self.user, "test_platform_admin")
perms = get_user_permissions(self.user)
self.assertIn("test_usersxyz:read", perms)
self.assertIn("test_usersxyz:write", perms)
# ─── Seeding Tests ───────────────────────────────────────────────────────────
class SeedTests(TestCase):
"""Test role/permission seeding."""
def test_seed_creates_defaults(self):
"""Seeding creates default roles and permissions."""
seed_roles_and_permissions()
from apps.access.models import Role, Permission
self.assertGreater(Role.objects.count(), 0)
self.assertGreater(Permission.objects.count(), 0)
def test_seed_is_idempotent(self):
"""Running seed twice doesn't duplicate records."""
seed_roles_and_permissions()
result = seed_roles_and_permissions()
self.assertEqual(result["roles_created"], 0)
self.assertEqual(result["permissions_created"], 0)
# ─── URL Tests ───────────────────────────────────────────────────────────────
class AccessURLTests(TestCase):
"""Test URL routing."""
def test_roles_list_url(self):
url = reverse("access:roles-list")
self.assertEqual(url, "/access/roles/")
def test_permissions_list_url(self):
url = reverse("access:permissions-list")
self.assertEqual(url, "/access/permissions/")
def test_my_roles_url(self):
url = reverse("access:my-roles")
self.assertEqual(url, "/access/my-roles/")