diff --git a/openedx/core/djangoapps/course_live/tests/test_tab.py b/openedx/core/djangoapps/course_live/tests/test_tab.py new file mode 100644 index 0000000000..eb0954d956 --- /dev/null +++ b/openedx/core/djangoapps/course_live/tests/test_tab.py @@ -0,0 +1,91 @@ +""" +Tests for course live tab. +""" +import itertools +from unittest.mock import Mock, patch + +import ddt +from django.test import RequestFactory +from edx_toggles.toggles.testutils import override_waffle_flag +from lti_consumer.models import CourseAllowPIISharingInLTIFlag, LtiConfiguration + +from lms.djangoapps.courseware.tests.test_tabs import TabTestCase +from openedx.core.djangoapps.course_live.config.waffle import ENABLE_COURSE_LIVE +from openedx.core.djangoapps.course_live.models import CourseLiveConfiguration +from openedx.core.djangoapps.course_live.tab import CourseLiveTab + + +@ddt.ddt +class CourseLiveTabTestCase(TabTestCase): + """Test cases for LTI CourseLive Tab.""" + + def setUp(self): + super().setUp() + self.course_live_config = CourseLiveConfiguration.objects.create( + course_key=self.course.id, + enabled=False, + provider_type="zoom", + ) + self.course_live_config.lti_configuration = LtiConfiguration.objects.create( + config_store=LtiConfiguration.CONFIG_ON_DB, + lti_1p1_launch_url='http://test.url', + lti_1p1_client_key='test_client_key', + lti_1p1_client_secret='test_client_secret', + ) + self.course_live_config.save() + self.url = self.reverse('course_tab_view', args=[str(self.course.id), CourseLiveTab.type]) + + def check_course_live_tab(self): + """ + Helper function for verifying the LTI course live tab. + """ + return self.check_tab( + tab_class=CourseLiveTab, + dict_tab={'type': CourseLiveTab.type, 'name': 'same'}, + expected_link=self.url, + expected_tab_id=CourseLiveTab.type, + invalid_dict_tab=None, + ) + + @ddt.data(True, False) + @patch('common.djangoapps.student.models.CourseEnrollment.is_enrolled', Mock(return_value=True)) + def test_user_can_access_course_live_tab(self, course_live_config_enabled): + """ + Test if tab is accessible to users with different roles + """ + self.course_live_config.enabled = course_live_config_enabled + self.course_live_config.save() + tab = self.check_course_live_tab() + with override_waffle_flag(ENABLE_COURSE_LIVE, True): + self.check_can_display_results( + tab, + for_staff_only=True, + for_enrolled_users_only=True, + expected_value=course_live_config_enabled, + ) + + @ddt.data(*itertools.product((True, False), repeat=3)) + @ddt.unpack + def test_course_live_lti_tab_pii(self, enable_sending_pii, share_username, share_email): + """ + Test course Live is sharing pii data as expected + """ + CourseAllowPIISharingInLTIFlag.objects.create(course_id=self.course.id, enabled=enable_sending_pii) + self.course_live_config.lti_configuration.lti_config = { + "pii_share_username": share_username, + "pii_share_email": share_email, + } + self.course_live_config.lti_configuration.save() + tab = self.check_course_live_tab() + request = RequestFactory().get(self.url) + user = self.create_mock_user(is_enrolled=True) + request.user = user + embed_code = tab._get_lti_embed_code(self.course, request) # pylint: disable=protected-access + if enable_sending_pii and share_username: + assert user.username in embed_code + else: + assert user.username not in embed_code + if enable_sending_pii and share_email: + assert user.email in embed_code + else: + assert user.email not in embed_code diff --git a/openedx/core/djangoapps/course_live/tests/test_views.py b/openedx/core/djangoapps/course_live/tests/test_views.py index eae02fc869..dbc4bdd304 100644 --- a/openedx/core/djangoapps/course_live/tests/test_views.py +++ b/openedx/core/djangoapps/course_live/tests/test_views.py @@ -4,12 +4,14 @@ Test for course live app views import json from django.urls import reverse +from edx_toggles.toggles.testutils import override_waffle_flag from lti_consumer.models import CourseAllowPIISharingInLTIFlag from rest_framework.test import APITestCase from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore.tests.django_utils import CourseUserType, ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory +from ..config.waffle import ENABLE_COURSE_LIVE from ..models import AVAILABLE_PROVIDERS, CourseLiveConfiguration @@ -144,6 +146,50 @@ class TestCourseLiveConfigurationView(ModuleStoreTestCase, APITestCase): self.assertEqual(response.status_code, 200) self.assertEqual(content, expected_data) + def test_update_configurations_response(self): + """ + Create, update & test POST request response data + """ + self.create_course_live_config() + updated_data = { + 'enabled': False, + 'provider_type': 'zoom', + 'lti_configuration': { + 'lti_1p1_client_key': 'new_key', + 'lti_1p1_client_secret': 'new_secret', + 'lti_1p1_launch_url': 'example01.com', + 'lti_config': { + 'additional_parameters': { + 'custom_instructor_email': 'new_email@example.com' + }, + }, + }, + } + response = self._post(updated_data) + content = json.loads(response.content.decode('utf-8')) + self.assertEqual(response.status_code, 200) + expected_data = { + 'course_key': str(self.course.id), + 'provider_type': 'zoom', + 'enabled': False, + 'lti_configuration': { + 'lti_1p1_client_key': 'new_key', + 'lti_1p1_client_secret': 'new_secret', + 'lti_1p1_launch_url': 'example01.com', + 'version': 'lti_1p1', + 'lti_config': { + 'pii_share_username': True, + 'pii_share_email': True, + 'additional_parameters': { + 'custom_instructor_email': + 'new_email@example.com' + } + } + }, + 'pii_sharing_allowed': True + } + self.assertEqual(content, expected_data) + def test_post_error_messages(self): """ Test all related validation messages are recived @@ -158,6 +204,37 @@ class TestCourseLiveConfigurationView(ModuleStoreTestCase, APITestCase): self.assertEqual(content, expected_data) self.assertEqual(response.status_code, 400) + def test_non_staff_user_access(self): + """ + Test non staff user has no access to API + """ + self.user = self.create_user_for_course(self.course, user_type=CourseUserType.UNENROLLED) + response = self._get() + content = json.loads(response.content.decode('utf-8')) + self.assertEqual(response.status_code, 403) + self.assertEqual(content, {'detail': 'You do not have permission to perform this action.'}) + + response = self._post({}) + content = json.loads(response.content.decode('utf-8')) + self.assertEqual(response.status_code, 403) + self.assertEqual(content, {'detail': 'You do not have permission to perform this action.'}) + + def test_courseware_api_has_live_tab(self): + """ + Test if courseware api has live-tab after ENABLE_COURSE_LIVE flag is enabled + """ + self.create_course_live_config() + with override_waffle_flag(ENABLE_COURSE_LIVE, True): + url = reverse('course-home:course-metadata', args=[self.course.id]) + response = self.client.get(url) + content = json.loads(response.content.decode('utf-8')) + data = next((tab for tab in content['tabs'] if tab['tab_id'] == 'lti_live'), None) + self.assertEqual(data, { + 'tab_id': 'lti_live', + 'title': 'Live', + 'url': f'http://testserver/courses/{self.course.id}/tab/lti_live/' + }) + class TestCourseLiveProvidersView(ModuleStoreTestCase, APITestCase): """