""" Tests for the milestones helpers library, which is the integration point for the edx_milestones API """ from unittest.mock import patch import ddt import pytest from django.conf import settings from django.contrib.auth.models import AnonymousUser from milestones import api as milestones_api from milestones.exceptions import InvalidCourseKeyException, InvalidUserException from milestones.models import MilestoneRelationshipType from common.djangoapps.util import milestones_helpers from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory @patch.dict(settings.FEATURES, {'MILESTONES_APP': False}) @ddt.ddt class MilestonesHelpersTestCase(ModuleStoreTestCase): """ Main test suite for Milestones API client library """ CREATE_USER = False def setUp(self): """ Test case scaffolding """ super().setUp() self.course = CourseFactory.create( metadata={ 'entrance_exam_enabled': True, } ) self.user = {'id': '123'} self.milestone = milestones_api.add_milestone({ 'name': 'Test Milestone', 'namespace': 'doesnt.matter', 'description': 'Testing Milestones Helpers Library', }) MilestoneRelationshipType.objects.get_or_create(name='requires') MilestoneRelationshipType.objects.get_or_create(name='fulfills') @ddt.data( (False, False, False), (True, False, False), (False, True, False), (True, True, True), ) def test_pre_requisite_courses_enabled(self, feature_flags): """ Tests is_prerequisite_courses_enabled function with a set of possible values for ENABLE_PREREQUISITE_COURSES and MILESTONES_APP feature flags. """ with patch.dict("django.conf.settings.FEATURES", { 'ENABLE_PREREQUISITE_COURSES': feature_flags[0], 'MILESTONES_APP': feature_flags[1] }): assert feature_flags[2] == milestones_helpers.is_prerequisite_courses_enabled() def test_add_milestone_returns_none_when_app_disabled(self): response = milestones_helpers.add_milestone(milestone_data=self.milestone) assert response is None def test_get_milestones_returns_none_when_app_disabled(self): response = milestones_helpers.get_milestones(namespace="whatever") assert len(response) == 0 def test_get_milestone_relationship_types_returns_none_when_app_disabled(self): response = milestones_helpers.get_milestone_relationship_types() assert len(response) == 0 def test_add_course_milestone_returns_none_when_app_disabled(self): response = milestones_helpers.add_course_milestone(str(self.course.id), 'requires', self.milestone) assert response is None def test_get_course_milestones_returns_none_when_app_disabled(self): response = milestones_helpers.get_course_milestones(str(self.course.id)) assert len(response) == 0 def test_add_course_content_milestone_returns_none_when_app_disabled(self): response = milestones_helpers.add_course_content_milestone( str(self.course.id), 'i4x://any/content/id', 'requires', self.milestone ) assert response is None def test_get_course_content_milestones_returns_none_when_app_disabled(self): response = milestones_helpers.get_course_content_milestones( str(self.course.id), 'i4x://doesnt/matter/for/this/test', 'requires' ) assert len(response) == 0 def test_remove_content_references_returns_none_when_app_disabled(self): response = milestones_helpers.remove_content_references("i4x://any/content/id/will/do") assert response is None def test_get_namespace_choices_returns_values_when_app_disabled(self): response = milestones_helpers.get_namespace_choices() assert 'ENTRANCE_EXAM' in response def test_get_course_milestones_fulfillment_paths_returns_none_when_app_disabled(self): response = milestones_helpers.get_course_milestones_fulfillment_paths(str(self.course.id), self.user) assert response is None def test_add_user_milestone_returns_none_when_app_disabled(self): response = milestones_helpers.add_user_milestone(self.user, self.milestone) assert response is None def test_get_service_returns_none_when_app_disabled(self): """MilestonesService is None when app disabled""" response = milestones_helpers.get_service() assert response is None @patch.dict(settings.FEATURES, {'MILESTONES_APP': True}) def test_any_unfulfilled_milestones(self): """ Tests any_unfulfilled_milestones for invalid arguments with the app enabled. """ # Should not raise any exceptions milestones_helpers.any_unfulfilled_milestones(self.course.id, self.user['id']) with pytest.raises(InvalidCourseKeyException): milestones_helpers.any_unfulfilled_milestones(None, self.user['id']) with pytest.raises(InvalidUserException): milestones_helpers.any_unfulfilled_milestones(self.course.id, None) @patch.dict(settings.FEATURES, {'MILESTONES_APP': True}) def test_get_required_content_with_anonymous_user(self): course = CourseFactory() required_content = milestones_helpers.get_required_content(course.id, AnonymousUser()) assert required_content == [] # NOTE (CCB): The initial version of anonymous courseware access is very simple. We avoid accidentally # exposing locked content by simply avoiding anonymous access altogether for courses runs with milestones. milestone = milestones_api.add_milestone({ 'name': 'test', 'namespace': 'test', }) milestones_helpers.add_course_milestone(str(course.id), 'requires', milestone) with pytest.raises(InvalidUserException): milestones_helpers.get_required_content(course.id, AnonymousUser())