Files
HarborForge.Backend/tests/test_roles.py
zhi 403d66e1ba test(P14.1): add comprehensive backend API tests
Add test coverage for:
- test_auth.py: Login, JWT, protected endpoints (5 tests)
- test_users.py: User CRUD, permissions (8 tests)
- test_projects.py: Project CRUD, ownership (8 tests)
- test_milestones.py: Milestone CRUD, filtering (7 tests)
- test_tasks.py: Task CRUD, filtering by status/assignee (8 tests)
- test_comments.py: Comment CRUD, edit permissions (5 tests)
- test_roles.py: Role/permission management, assignments (9 tests)
- test_misc.py: Milestones global, notifications, activity log, API keys, dashboard, health (14 tests)

Total: 64 new tests covering all major API endpoints.
Uses existing pytest fixtures from conftest.py.
2026-03-19 12:38:14 +00:00

183 lines
6.9 KiB
Python

"""P14.1 — Roles and Permissions API tests.
Covers:
- List roles
- Get role by ID
- Create role
- Update role
- Delete role
- Assign role to user
- Check permissions
"""
import pytest
class TestRoles:
"""Role management endpoints."""
def test_list_roles(self, client, db, make_user, auth_header, seed_roles_and_permissions):
"""List all roles."""
admin_role, mgr_role, dev_role = seed_roles_and_permissions
user = make_user()
resp = client.get("/roles", headers=auth_header(user))
assert resp.status_code == 200
data = resp.json()
assert len(data) >= 3 # admin, mgr, dev at minimum
def test_get_role_by_id(self, client, db, make_user, auth_header, seed_roles_and_permissions):
"""Get specific role."""
admin_role, mgr_role, dev_role = seed_roles_and_permissions
user = make_user()
resp = client.get(f"/roles/{admin_role.id}", headers=auth_header(user))
assert resp.status_code == 200
data = resp.json()
assert data["id"] == admin_role.id
assert "name" in data
def test_create_role(self, client, db, make_user, auth_header, seed_roles_and_permissions):
"""Admin can create new role."""
admin_role, mgr_role, dev_role = seed_roles_and_permissions
admin = make_user(username="admin", is_admin=True)
resp = client.post(
"/roles",
json={
"name": "tester",
"description": "Test role",
"is_global": False
},
headers=auth_header(admin)
)
assert resp.status_code == 201
data = resp.json()
assert data["name"] == "tester"
def test_update_role(self, client, db, make_user, auth_header, seed_roles_and_permissions):
"""Admin can update role."""
admin_role, mgr_role, dev_role = seed_roles_and_permissions
admin = make_user(username="admin", is_admin=True)
resp = client.patch(
f"/roles/{dev_role.id}",
json={"description": "Updated description"},
headers=auth_header(admin)
)
assert resp.status_code == 200
data = resp.json()
assert data["description"] == "Updated description"
def test_delete_role(self, client, db, make_user, auth_header, seed_roles_and_permissions):
"""Admin can delete non-default role."""
admin_role, mgr_role, dev_role = seed_roles_and_permissions
admin = make_user(username="admin", is_admin=True)
# Create a role to delete
resp = client.post(
"/roles",
json={"name": "temp-role", "description": "To delete"},
headers=auth_header(admin)
)
role_id = resp.json()["id"]
resp = client.delete(f"/roles/{role_id}", headers=auth_header(admin))
assert resp.status_code == 204
def test_cannot_delete_admin_role(self, client, db, make_user, auth_header, seed_roles_and_permissions):
"""Cannot delete admin role."""
admin_role, mgr_role, dev_role = seed_roles_and_permissions
admin = make_user(username="admin", is_admin=True)
resp = client.delete(f"/roles/{admin_role.id}", headers=auth_header(admin))
assert resp.status_code == 400
class TestPermissions:
"""Permission checking endpoints."""
def test_check_permission_true(self, client, db, make_user, make_project, auth_header, seed_roles_and_permissions, make_member):
"""Check permission returns true when granted."""
admin_role, mgr_role, dev_role = seed_roles_and_permissions
user = make_user()
project = make_project()
make_member(project.id, user.id, dev_role.id)
# Dev should have view permission
resp = client.get(
f"/projects/{project.id}/check-permission?permission=view",
headers=auth_header(user)
)
assert resp.status_code == 200
data = resp.json()
assert data["has_permission"] is True
def test_check_permission_false(self, client, db, make_user, make_project, auth_header, seed_roles_and_permissions, make_member):
"""Check permission returns false when not granted."""
admin_role, mgr_role, dev_role = seed_roles_and_permissions
user = make_user()
project = make_project()
# Add as guest (viewer role)
from app.models.role_permission import Role
guest_role = db.query(Role).filter(Role.name == "guest").first()
if not guest_role:
guest_role = Role(name="guest", description="Guest", is_global=False)
db.add(guest_role)
db.commit()
make_member(project.id, user.id, guest_role.id)
resp = client.get(
f"/projects/{project.id}/check-permission?permission=admin",
headers=auth_header(user)
)
assert resp.status_code == 200
data = resp.json()
assert data["has_permission"] is False
class TestRoleAssignments:
"""Role assignment endpoints."""
def test_assign_role_to_user(self, client, db, make_user, make_project, auth_header, seed_roles_and_permissions, make_member):
"""Assign role to project member."""
admin_role, mgr_role, dev_role = seed_roles_and_permissions
admin = make_user(username="admin", is_admin=True)
user = make_user(username="member")
project = make_project()
resp = client.post(
f"/projects/{project.id}/members",
json={"user_id": user.id, "role_id": dev_role.id},
headers=auth_header(admin)
)
assert resp.status_code == 201
def test_change_user_role(self, client, db, make_user, make_project, auth_header, seed_roles_and_permissions, make_member):
"""Change user's role in project."""
admin_role, mgr_role, dev_role = seed_roles_and_permissions
admin = make_user(username="admin", is_admin=True)
user = make_user(username="member")
project = make_project()
make_member(project.id, user.id, dev_role.id)
resp = client.patch(
f"/projects/{project.id}/members/{user.id}",
json={"role_id": mgr_role.id},
headers=auth_header(admin)
)
assert resp.status_code == 200
def test_remove_user_from_project(self, client, db, make_user, make_project, auth_header, seed_roles_and_permissions, make_member):
"""Remove user from project."""
admin_role, mgr_role, dev_role = seed_roles_and_permissions
admin = make_user(username="admin", is_admin=True)
user = make_user(username="member")
project = make_project()
make_member(project.id, user.id, dev_role.id)
resp = client.delete(
f"/projects/{project.id}/members/{user.id}",
headers=auth_header(admin)
)
assert resp.status_code == 204