"""Tests for permission enhancements. Tests for: 1. Manager workload access - department managers can view subordinate workloads 2. Cross-department project access via project membership """ import pytest from unittest.mock import MagicMock from app.middleware.auth import check_project_access, check_project_edit_access # ============================================================================ # Test Helpers # ============================================================================ def get_mock_user( user_id="test-user-id", is_admin=False, is_department_manager=False, department_id="dept-1", ): """Create a mock user for testing.""" user = MagicMock() user.id = user_id user.is_system_admin = is_admin user.is_department_manager = is_department_manager user.department_id = department_id return user def get_mock_project_member(user_id, role="member"): """Create a mock project member.""" member = MagicMock() member.user_id = user_id member.role = role return member def get_mock_project( owner_id="owner-id", security_level="department", department_id="dept-1", members=None, ): """Create a mock project for testing.""" project = MagicMock() project.id = "project-id" project.owner_id = owner_id project.security_level = security_level project.department_id = department_id project.members = members or [] return project # ============================================================================ # Test Manager Workload Access # ============================================================================ class TestManagerWorkloadAccess: """Test that department managers can view subordinate workloads.""" def test_manager_flag_exists_on_user(self): """Test that is_department_manager flag exists on mock user.""" manager = get_mock_user(is_department_manager=True) assert manager.is_department_manager == True regular_user = get_mock_user(is_department_manager=False) assert regular_user.is_department_manager == False def test_system_admin_can_view_all_workloads(self): """Test that system admin can view any user's workload.""" from app.api.workload.router import check_workload_access admin = get_mock_user(is_admin=True) # Should not raise for any target user check_workload_access(admin, target_user_id="any-user-id") check_workload_access(admin, department_id="any-dept") def test_manager_can_view_same_department_workload(self): """Test that manager can view workload of users in their department.""" from app.api.workload.router import check_workload_access manager = get_mock_user( is_department_manager=True, department_id="dept-1" ) # Manager can view workload of user in same department check_workload_access( manager, target_user_id="subordinate-user-id", target_user_department_id="dept-1" ) def test_manager_cannot_view_other_department_workload(self): """Test that manager cannot view workload of users in other departments.""" from app.api.workload.router import check_workload_access from fastapi import HTTPException manager = get_mock_user( is_department_manager=True, department_id="dept-1" ) # Manager cannot view workload of user in different department with pytest.raises(HTTPException) as exc_info: check_workload_access( manager, target_user_id="other-dept-user-id", target_user_department_id="dept-2" ) assert exc_info.value.status_code == 403 def test_regular_user_can_only_view_own_workload(self): """Test that regular users can only view their own workload.""" from app.api.workload.router import check_workload_access from fastapi import HTTPException user = get_mock_user( user_id="user-123", is_department_manager=False ) # User can view their own workload check_workload_access(user, target_user_id="user-123") # User cannot view others' workload with pytest.raises(HTTPException) as exc_info: check_workload_access(user, target_user_id="other-user") assert exc_info.value.status_code == 403 # ============================================================================ # Test Cross-Department Project Access via Membership # ============================================================================ class TestProjectMemberAccess: """Test that project members have access regardless of department.""" def test_project_member_has_access(self): """Test that project member can access project from different department.""" user = get_mock_user(user_id="member-user", department_id="dept-2") # Project is in dept-1 but user from dept-2 is a member member = get_mock_project_member(user_id="member-user", role="member") project = get_mock_project( security_level="department", department_id="dept-1", members=[member], ) assert check_project_access(user, project) == True def test_non_member_from_different_dept_denied(self): """Test that non-member from different department is denied access.""" user = get_mock_user(user_id="outsider", department_id="dept-2") project = get_mock_project( security_level="department", department_id="dept-1", members=[], # No members ) assert check_project_access(user, project) == False def test_member_access_confidential_project(self): """Test that members can access confidential projects.""" user = get_mock_user(user_id="member-user", department_id="dept-2") member = get_mock_project_member(user_id="member-user", role="member") project = get_mock_project( owner_id="owner-id", # User is not owner security_level="confidential", department_id="dept-1", members=[member], ) # Member should have access even to confidential project assert check_project_access(user, project) == True def test_member_with_admin_role_can_edit(self): """Test that project member with admin role can edit project.""" user = get_mock_user(user_id="admin-member", department_id="dept-2") member = get_mock_project_member(user_id="admin-member", role="admin") project = get_mock_project( owner_id="owner-id", # User is not owner security_level="department", members=[member], ) assert check_project_edit_access(user, project) == True def test_member_with_member_role_cannot_edit(self): """Test that project member with member role cannot edit project.""" user = get_mock_user(user_id="regular-member", department_id="dept-2") member = get_mock_project_member(user_id="regular-member", role="member") project = get_mock_project( owner_id="owner-id", # User is not owner security_level="department", members=[member], ) assert check_project_edit_access(user, project) == False def test_owner_can_still_edit(self): """Test that project owner can edit regardless of members.""" user = get_mock_user(user_id="owner-id") project = get_mock_project( owner_id="owner-id", security_level="confidential", members=[], ) assert check_project_access(user, project) == True assert check_project_edit_access(user, project) == True # ============================================================================ # Test Filter Accessible Users for Manager # ============================================================================ class TestFilterAccessibleUsersForManager: """Test the filter_accessible_users function for managers.""" def test_admin_can_see_all_users(self): """Test that admin can see all users.""" from app.api.workload.router import filter_accessible_users admin = get_mock_user(is_admin=True) # Admin with no filter gets None (means all users) result = filter_accessible_users(admin, None, None) assert result is None # Admin with specific users gets those users result = filter_accessible_users(admin, ["user1", "user2"], None) assert result == ["user1", "user2"] def test_regular_user_sees_only_self(self): """Test that regular user can only see themselves.""" from app.api.workload.router import filter_accessible_users user = get_mock_user(user_id="user-123", is_department_manager=False) # Regular user with no filter gets only self result = filter_accessible_users(user, None, None) assert result == ["user-123"] # Regular user with other users gets only self result = filter_accessible_users(user, ["user1", "user2", "user-123"], None) assert result == ["user-123"] class TestAccessDeniedForNonManagersAndNonMembers: """Test that access is properly denied for unauthorized users.""" def test_non_manager_cannot_view_subordinate_workload(self): """Test that non-manager cannot view other users' workload.""" from app.api.workload.router import check_workload_access from fastapi import HTTPException user = get_mock_user(is_department_manager=False) with pytest.raises(HTTPException) as exc_info: check_workload_access(user, target_user_id="other-user") assert exc_info.value.status_code == 403 def test_non_member_cannot_access_department_project(self): """Test that non-member from different department cannot access.""" user = get_mock_user(department_id="dept-2") project = get_mock_project( security_level="department", department_id="dept-1", members=[], ) assert check_project_access(user, project) == False