import tempfile from unittest import mock from django.core.files.uploadedfile import SimpleUploadedFile from django.test import override_settings from django.urls import reverse from django.utils import timezone from rest_framework import status from rest_framework.test import APITestCase from apps.account.models import ProfessorUser, StudentUser from apps.course.models import ( Course, CourseCategory, CourseLiveSession, Participant, ) @override_settings( PLUGNMEET_SERVER_URL='https://meet.example.com', PLUGNMEET_API_KEY='test-key', PLUGNMEET_API_SECRET='test-secret', MEDIA_ROOT=tempfile.gettempdir(), ) class CourseLiveSessionAPITests(APITestCase): def setUp(self): self.professor = ProfessorUser.objects.create( email='prof@example.com', fullname='Professor Sample', experience_years=5, ) self.student = StudentUser.objects.create( email='student@example.com', fullname='Student Sample', ) self.category = CourseCategory.objects.create(name='Category', slug='category') thumbnail = SimpleUploadedFile('thumb.jpg', b'filecontent', content_type='image/jpeg') self.course = Course.objects.create( title='Sample Course', slug='sample-course', category=self.category, professor=self.professor, thumbnail=thumbnail, video_type=Course.VedioTypeChoices.YOUTUBE_LINK, video_link='https://example.com/video', is_online=True, online_link='https://example.com/live', level=Course.LevelChoices.BEGINNER, duration=10, lessons_count=2, description='Description', short_description='Short', status=Course.StatusChoices.ONGOING, is_free=True, ) professor_avatar = SimpleUploadedFile('prof-avatar.jpg', b'avatar', content_type='image/jpeg') self.professor.avatar = professor_avatar self.professor.save(update_fields=['avatar']) student_avatar = SimpleUploadedFile('student-avatar.jpg', b'avatar', content_type='image/jpeg') self.student.avatar = student_avatar self.student.save(update_fields=['avatar']) @mock.patch('apps.course.views.live_session.PlugNMeetClient') def test_professor_can_create_room(self, mock_client_cls): mock_client = mock_client_cls.return_value mock_client.create_room.return_value = {'status': 'success'} self.client.force_authenticate(user=self.professor) url = reverse('course-live-session-room-create', kwargs={'slug': self.course.slug}) payload = { 'room_id': 'custom-room-id', 'subject': 'Algebra Session', } response = self.client.post(url, payload, format='json') self.assertEqual(response.status_code, status.HTTP_201_CREATED) mock_client.create_room.assert_called_once() self.assertTrue( CourseLiveSession.objects.filter(course=self.course, room_id='custom-room-id').exists() ) @mock.patch('apps.course.views.live_session.PlugNMeetClient') def test_professor_receives_admin_token(self, mock_client_cls): mock_client = mock_client_cls.return_value mock_client.get_join_token.return_value = {'token': 'abc123'} session = CourseLiveSession.objects.create( course=self.course, subject='Session', started_at=timezone.now(), room_id='room-123', ) self.client.force_authenticate(user=self.professor) url = reverse('course-live-session-token') response = self.client.post(url, {'room_id': session.room_id}, format='json') self.assertEqual(response.status_code, status.HTTP_200_OK) args, _ = mock_client.get_join_token.call_args payload = args[0] self.assertTrue(payload['user_info']['is_admin']) profile_pic = payload['user_info']['user_metadata'].get('profilePic') self.assertEqual(profile_pic, f"http://testserver{self.professor.avatar.url}") self.assertEqual(response.data['token'], 'abc123') @mock.patch('apps.course.views.live_session.PlugNMeetClient') def test_student_participant_receives_limited_token(self, mock_client_cls): mock_client = mock_client_cls.return_value mock_client.get_join_token.return_value = {'token': 'student-token'} session = CourseLiveSession.objects.create( course=self.course, subject='Session', started_at=timezone.now(), room_id='room-456', ) Participant.objects.create(course=self.course, student=self.student) self.client.force_authenticate(user=self.student) url = reverse('course-live-session-token') response = self.client.post(url, {'room_id': session.room_id}, format='json') self.assertEqual(response.status_code, status.HTTP_200_OK) args, _ = mock_client.get_join_token.call_args payload = args[0] self.assertFalse(payload['user_info']['is_admin']) metadata = payload['user_info']['user_metadata'] self.assertIn('lock_microphone', metadata['lock_settings']) self.assertEqual(metadata.get('profilePic'), f"http://testserver{self.student.avatar.url}") self.assertEqual(response.data['token'], 'student-token') def test_student_without_access_cannot_get_token(self): session = CourseLiveSession.objects.create( course=self.course, subject='Session', started_at=timezone.now(), room_id='room-789', ) self.client.force_authenticate(user=self.student) url = reverse('course-live-session-token') response = self.client.post(url, {'room_id': session.room_id}, format='json') self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_validate_metadata_includes_active_room_for_student(self): session = CourseLiveSession.objects.create( course=self.course, subject='Session Live', started_at=timezone.now(), room_id='room-live-1', ) Participant.objects.create(course=self.course, student=self.student) self.client.force_authenticate(user=self.student) url = reverse('course-online-validate', kwargs={'slug': self.course.slug}) response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_200_OK) metadata = response.data['metadata'] self.assertTrue(metadata['is_online']) self.assertEqual(metadata['active_room_id'], session.room_id) self.assertTrue(metadata['can_join_live_session']) self.assertEqual(metadata['live_session']['room_id'], session.room_id) self.assertIsNotNone(metadata['live_session']['started_at']) def test_validate_metadata_for_professor_hides_creation_when_online(self): CourseLiveSession.objects.create( course=self.course, subject='Session Live', started_at=timezone.now(), room_id='room-live-2', ) self.client.force_authenticate(user=self.professor) url = reverse('course-online-validate', kwargs={'slug': self.course.slug}) response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_200_OK) metadata = response.data['metadata'] self.assertFalse(metadata['can_create_live_session'])