from django.test import TestCase from django.urls import reverse from rest_framework.test import APIClient from rest_framework import status from django.contrib.auth import get_user_model from tenants.models import Tenant from .models import Project, Task User = get_user_model() class ProjectTaskTests(TestCase): def setUp(self): self.client_a = APIClient() self.client_b = APIClient() self.tenant_a = Tenant.objects.create(name='Tenant A', subdomain='tenant-a') self.tenant_b = Tenant.objects.create(name='Tenant B', subdomain='tenant-b') self.teacher_a = User.objects.create_user(username='teacher_a', password='pw', role='teacher', tenant=self.tenant_a) self.student_a = User.objects.create_user(username='student_a', password='pw', role='student', tenant=self.tenant_a) self.teacher_b = User.objects.create_user(username='teacher_b', password='pw', role='teacher', tenant=self.tenant_b) # Login clients response_a = self.client_a.post(reverse('token_obtain_pair'), {'username': 'teacher_a', 'password': 'pw'}) self.client_a.credentials(HTTP_AUTHORIZATION='Bearer ' + response_a.data['access'], HTTP_X_TENANT_ID=str(self.tenant_a.id)) response_b = self.client_b.post(reverse('token_obtain_pair'), {'username': 'teacher_b', 'password': 'pw'}) self.client_b.credentials(HTTP_AUTHORIZATION='Bearer ' + response_b.data['access'], HTTP_X_TENANT_ID=str(self.tenant_b.id)) self.client_student = APIClient() response_stud = self.client_student.post(reverse('token_obtain_pair'), {'username': 'student_a', 'password': 'pw'}) self.client_student.credentials(HTTP_AUTHORIZATION='Bearer ' + response_stud.data['access'], HTTP_X_TENANT_ID=str(self.tenant_a.id)) def test_project_crud(self): # Create url = reverse('project-list') data = {'name': 'Project Alpha', 'description': 'Test project'} response = self.client_a.post(url, data, format='json') self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(Project.objects.count(), 1) project_id = response.data['id'] # List response = self.client_a.get(url) self.assertEqual(response.data['count'], 1) self.assertEqual(len(response.data['results']), 1) # Update detail_url = reverse('project-detail', kwargs={'pk': project_id}) response = self.client_a.put(detail_url, {'name': 'Project Alpha Updated'}, format='json') self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data['name'], 'Project Alpha Updated') # Tenant Isolation - B should not see A's projects response = self.client_b.get(url) self.assertEqual(response.data['count'], 0) # Role Based - Student can read, but not create response = self.client_student.get(url) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data['count'], 1) response = self.client_student.post(url, data, format='json') self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_task_crud(self): project = Project.objects.create(name='Proj A', tenant=self.tenant_a, created_by=self.teacher_a) # Create Task url = reverse('project-tasks-list', kwargs={'project_pk': project.id}) data = {'title': 'Backend Auth', 'description': 'JWT Setup', 'status': 'todo', 'priority': 'high'} response = self.client_a.post(url, data, format='json') self.assertEqual(response.status_code, status.HTTP_201_CREATED) task_id = response.data['id'] # Update Task Assignment detail_url = reverse('project-tasks-detail', kwargs={'project_pk': project.id, 'pk': task_id}) response = self.client_a.patch(detail_url, {'assigned_to_id': self.student_a.id}, format='json') self.assertEqual(response.status_code, status.HTTP_200_OK) task = Task.objects.get(id=task_id) self.assertEqual(task.assigned_to, self.student_a)