177 lines
5.8 KiB
Python
177 lines
5.8 KiB
Python
"""
|
|
Unit tests for gating.signals module
|
|
"""
|
|
from mock import patch
|
|
from nose.plugins.attrib import attr
|
|
from ddt import ddt, data, unpack
|
|
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
|
|
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
|
from courseware.tests.helpers import LoginEnrollmentTestCase
|
|
|
|
from milestones import api as milestones_api
|
|
from milestones.tests.utils import MilestonesTestCaseMixin
|
|
from openedx.core.lib.gating import api as gating_api
|
|
from gating.api import _get_xblock_parent, evaluate_prerequisite
|
|
|
|
|
|
class GatingTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase):
|
|
"""
|
|
Base TestCase class for setting up a basic course structure
|
|
and testing the gating feature
|
|
"""
|
|
|
|
def setUp(self):
|
|
"""
|
|
Initial data setup
|
|
"""
|
|
super(GatingTestCase, self).setUp()
|
|
|
|
# create course
|
|
self.course = CourseFactory.create(
|
|
org='edX',
|
|
number='EDX101',
|
|
run='EDX101_RUN1',
|
|
display_name='edX 101'
|
|
)
|
|
self.course.enable_subsection_gating = True
|
|
self.course.save()
|
|
self.store.update_item(self.course, 0)
|
|
|
|
# create chapter
|
|
self.chapter1 = ItemFactory.create(
|
|
parent_location=self.course.location,
|
|
category='chapter',
|
|
display_name='untitled chapter 1'
|
|
)
|
|
|
|
# create sequentials
|
|
self.seq1 = ItemFactory.create(
|
|
parent_location=self.chapter1.location,
|
|
category='sequential',
|
|
display_name='untitled sequential 1'
|
|
)
|
|
self.seq2 = ItemFactory.create(
|
|
parent_location=self.chapter1.location,
|
|
category='sequential',
|
|
display_name='untitled sequential 2'
|
|
)
|
|
|
|
# create vertical
|
|
self.vert1 = ItemFactory.create(
|
|
parent_location=self.seq1.location,
|
|
category='vertical',
|
|
display_name='untitled vertical 1'
|
|
)
|
|
|
|
# create problem
|
|
self.prob1 = ItemFactory.create(
|
|
parent_location=self.vert1.location,
|
|
category='problem',
|
|
display_name='untitled problem 1'
|
|
)
|
|
|
|
# create orphan
|
|
self.prob2 = ItemFactory.create(
|
|
parent_location=self.course.location,
|
|
category='problem',
|
|
display_name='untitled problem 2'
|
|
)
|
|
|
|
|
|
class TestGetXBlockParent(GatingTestCase):
|
|
"""
|
|
Tests for the get_xblock_parent function
|
|
"""
|
|
|
|
def test_get_direct_parent(self):
|
|
""" Test test_get_direct_parent """
|
|
|
|
result = _get_xblock_parent(self.vert1)
|
|
self.assertEqual(result.location, self.seq1.location)
|
|
|
|
def test_get_parent_with_category(self):
|
|
""" Test test_get_parent_of_category """
|
|
|
|
result = _get_xblock_parent(self.vert1, 'sequential')
|
|
self.assertEqual(result.location, self.seq1.location)
|
|
result = _get_xblock_parent(self.vert1, 'chapter')
|
|
self.assertEqual(result.location, self.chapter1.location)
|
|
|
|
def test_get_parent_none(self):
|
|
""" Test test_get_parent_none """
|
|
|
|
result = _get_xblock_parent(self.vert1, 'unit')
|
|
self.assertIsNone(result)
|
|
|
|
|
|
@attr(shard=3)
|
|
@ddt
|
|
class TestEvaluatePrerequisite(GatingTestCase, MilestonesTestCaseMixin):
|
|
"""
|
|
Tests for the evaluate_prerequisite function
|
|
"""
|
|
|
|
def setUp(self):
|
|
super(TestEvaluatePrerequisite, self).setUp()
|
|
self.user_dict = {'id': self.user.id}
|
|
self.prereq_milestone = None
|
|
|
|
def _setup_gating_milestone(self, min_score):
|
|
"""
|
|
Setup a gating milestone for testing
|
|
"""
|
|
|
|
gating_api.add_prerequisite(self.course.id, self.seq1.location)
|
|
gating_api.set_required_content(self.course.id, self.seq2.location, self.seq1.location, min_score)
|
|
self.prereq_milestone = gating_api.get_gating_milestone(self.course.id, self.seq1.location, 'fulfills')
|
|
|
|
@patch('gating.api.get_module_score')
|
|
@data((.5, True), (1, True), (0, False))
|
|
@unpack
|
|
def test_min_score_achieved(self, module_score, result, mock_module_score):
|
|
""" Test test_min_score_achieved """
|
|
|
|
self._setup_gating_milestone(50)
|
|
|
|
mock_module_score.return_value = module_score
|
|
evaluate_prerequisite(self.course, self.prob1, self.user.id)
|
|
self.assertEqual(milestones_api.user_has_milestone(self.user_dict, self.prereq_milestone), result)
|
|
|
|
@patch('gating.api.log.warning')
|
|
@patch('gating.api.get_module_score')
|
|
@data((.5, False), (1, True))
|
|
@unpack
|
|
def test_invalid_min_score(self, module_score, result, mock_module_score, mock_log):
|
|
""" Test test_invalid_min_score """
|
|
|
|
self._setup_gating_milestone(None)
|
|
|
|
mock_module_score.return_value = module_score
|
|
evaluate_prerequisite(self.course, self.prob1, self.user.id)
|
|
self.assertEqual(milestones_api.user_has_milestone(self.user_dict, self.prereq_milestone), result)
|
|
self.assertTrue(mock_log.called)
|
|
|
|
@patch('gating.api.get_module_score')
|
|
def test_orphaned_xblock(self, mock_module_score):
|
|
""" Test test_orphaned_xblock """
|
|
|
|
evaluate_prerequisite(self.course, self.prob2, self.user.id)
|
|
self.assertFalse(mock_module_score.called)
|
|
|
|
@patch('gating.api.get_module_score')
|
|
def test_no_prerequisites(self, mock_module_score):
|
|
""" Test test_no_prerequisites """
|
|
|
|
evaluate_prerequisite(self.course, self.prob1, self.user.id)
|
|
self.assertFalse(mock_module_score.called)
|
|
|
|
@patch('gating.api.get_module_score')
|
|
def test_no_gated_content(self, mock_module_score):
|
|
""" Test test_no_gated_content """
|
|
|
|
# Setup gating milestones data
|
|
gating_api.add_prerequisite(self.course.id, self.seq1.location)
|
|
|
|
evaluate_prerequisite(self.course, self.prob1, self.user.id)
|
|
self.assertFalse(mock_module_score.called)
|