Spaces:
Runtime error
Runtime error
| """Tests for admin-only skill CRUD at /api/admin/skills/. | |
| Matches the existing test_roles.py style (pytest + force_authenticate). | |
| """ | |
| import pytest | |
| from django.contrib.auth import get_user_model | |
| from rest_framework import status | |
| from rest_framework.test import APIClient | |
| from apps.roles.models import Role, RoleSkill | |
| from apps.skills.models import Skill, UserSkill | |
| User = get_user_model() | |
| pytestmark = pytest.mark.django_db | |
| ADMIN_SKILLS_URL = '/api/admin/skills/' | |
| def admin_client(): | |
| user = User.objects.create_user( | |
| username='admin@test.example', email='admin@test.example', | |
| password='x', name='Admin', role_type='ADMIN', | |
| is_staff=True, | |
| ) | |
| c = APIClient() | |
| c.force_authenticate(user=user) | |
| return c | |
| def student_client(): | |
| user = User.objects.create_user( | |
| username='student@test.example', email='student@test.example', | |
| password='x', name='Student', role_type='STUDENT', | |
| ) | |
| c = APIClient() | |
| c.force_authenticate(user=user) | |
| return c | |
| def skill(): | |
| return Skill.objects.create( | |
| skill_name='Python', category='Programming', difficulty_level='BEGINNER', | |
| ) | |
| class TestSkillAdminPermissions: | |
| def test_student_forbidden_on_create(self, student_client): | |
| resp = student_client.post(ADMIN_SKILLS_URL, { | |
| 'skill_name': 'Rust', 'category': 'Programming', | |
| 'difficulty_level': 'INTERMEDIATE', | |
| }, format='json') | |
| assert resp.status_code == status.HTTP_403_FORBIDDEN | |
| def test_anonymous_forbidden(self, skill): | |
| resp = APIClient().get(ADMIN_SKILLS_URL) | |
| # Default DRF returns 401 for unauthenticated, 403 if auth succeeds | |
| # but permission fails. Either way, access is denied. | |
| assert resp.status_code in (status.HTTP_401_UNAUTHORIZED, status.HTTP_403_FORBIDDEN) | |
| class TestSkillAdminCrud: | |
| def test_admin_full_cycle(self, admin_client): | |
| # Create | |
| resp = admin_client.post(ADMIN_SKILLS_URL, { | |
| 'skill_name': 'Go', | |
| 'category': 'Programming', | |
| 'description': 'Google Go', | |
| 'difficulty_level': 'INTERMEDIATE', | |
| }, format='json') | |
| assert resp.status_code == status.HTTP_201_CREATED, resp.data | |
| skill_id = resp.data['id'] | |
| # List | |
| resp = admin_client.get(ADMIN_SKILLS_URL) | |
| assert resp.status_code == status.HTTP_200_OK | |
| # Paginated response wraps rows in `results`. | |
| rows = resp.data['results'] if isinstance(resp.data, dict) else resp.data | |
| assert any(r['id'] == skill_id for r in rows) | |
| # Update | |
| resp = admin_client.patch( | |
| f'{ADMIN_SKILLS_URL}{skill_id}/', | |
| {'description': 'Updated'}, format='json', | |
| ) | |
| assert resp.status_code == status.HTTP_200_OK | |
| assert resp.data['description'] == 'Updated' | |
| # Delete (no references) succeeds | |
| resp = admin_client.delete(f'{ADMIN_SKILLS_URL}{skill_id}/') | |
| assert resp.status_code == status.HTTP_204_NO_CONTENT | |
| assert not Skill.objects.filter(pk=skill_id).exists() | |
| def test_delete_blocked_when_user_skill_references_it(self, admin_client, skill): | |
| # Reference the skill from a UserSkill row. | |
| user = User.objects.create_user( | |
| username='ref@test.example', email='ref@test.example', | |
| password='x', name='Ref', | |
| ) | |
| UserSkill.objects.create( | |
| user=user, skill=skill, proficiency=50, user_level='BEGINNER', | |
| ) | |
| resp = admin_client.delete(f'{ADMIN_SKILLS_URL}{skill.id}/') | |
| assert resp.status_code == status.HTTP_409_CONFLICT | |
| assert 'student skill profiles' in resp.data['detail'] | |
| # Skill still exists. | |
| assert Skill.objects.filter(pk=skill.id).exists() | |
| def test_delete_blocked_when_role_skill_references_it(self, admin_client, skill): | |
| role = Role.objects.create(role_name='Dev', industry='Tech') | |
| RoleSkill.objects.create( | |
| role=role, skill=skill, required_level='BEGINNER', | |
| ) | |
| resp = admin_client.delete(f'{ADMIN_SKILLS_URL}{skill.id}/') | |
| assert resp.status_code == status.HTTP_409_CONFLICT | |
| assert 'role requirements' in resp.data['detail'] | |