test: 🚑 add test to catch recursion when persistent grades disabled

This commit is contained in:
dyudyunov
2022-01-20 12:45:49 +02:00
committed by Eugene Dyudyunov
parent c4bc6e29ea
commit 956c985508
2 changed files with 38 additions and 3 deletions

View File

@@ -53,7 +53,7 @@ def generate_allowlist_certificate_task(user, course_key, generation_mode=None,
Create a task to generate an allowlist certificate for this user in this course run.
"""
enrollment_mode = _get_enrollment_mode(user, course_key)
course_grade = _get_course_grade(user, course_key)
course_grade = _get_course_grade(user, course_key, send_grade_signals=False)
if _can_generate_allowlist_certificate(user, course_key, enrollment_mode):
return _generate_certificate_task(user=user, course_key=course_key, enrollment_mode=enrollment_mode,
course_grade=course_grade, generation_mode=generation_mode,
@@ -377,9 +377,12 @@ def _get_grade_value(course_grade):
return ''
def _get_course_grade(user, course_key, send_grade_signals=False):
def _get_course_grade(user, course_key, send_grade_signals=True):
"""
Get the user's course grade in this course run. Note that this may be None.
Use send_grade_signals=False to avoid firing the course grade signals recursively.
See details in lms/djangoapps/grades/course_grade_factory.py _update method.
"""
return CourseGradeFactory().read(user, course_key=course_key, send_grade_signals=send_grade_signals)

View File

@@ -2,16 +2,19 @@
Tests for the CourseGradeFactory class.
"""
import itertools
from unittest.mock import patch
from unittest.mock import patch, Mock
import ddt
from django.conf import settings
from edx_toggles.toggles.testutils import override_waffle_switch
import pytest
from common.djangoapps.student.tests.factories import UserFactory
from lms.djangoapps.certificates.config import AUTO_CERTIFICATE_GENERATION
from lms.djangoapps.courseware.access import has_access
from lms.djangoapps.grades.config.tests.utils import persistent_grades_feature_flags
from openedx.core.djangoapps.content.block_structure.factory import BlockStructureFactory
from openedx.core.djangoapps.signals.signals import COURSE_GRADE_NOW_PASSED
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase # lint-amnesty, pylint: disable=wrong-import-order
from xmodule.modulestore.tests.factories import CourseFactory # lint-amnesty, pylint: disable=wrong-import-order
@@ -73,6 +76,35 @@ class TestCourseGradeFactory(GradeTestBase):
grade_factory.read(self.request.user, self.course)
assert mock_read_grade.called == (feature_flag and course_setting)
@patch.dict(settings.FEATURES, {'PERSISTENT_GRADES_ENABLED_FOR_ALL_TESTS': False})
def test_no_recursion_without_persistent_grades(self):
"""
Course grade signals should not be fired recursively when persistent grades are disabled.
"""
self.mock_process_signal = Mock() # pylint: disable=attribute-defined-outside-init
def handler(**kwargs):
"""
Mock signal receiver.
"""
self.mock_process_signal()
with persistent_grades_feature_flags(
global_flag=False,
enabled_for_all_courses=False,
course_id=self.course.id,
enabled_for_course=False
):
with override_waffle_switch(AUTO_CERTIFICATE_GENERATION, active=True), mock_get_score(2, 2):
COURSE_GRADE_NOW_PASSED.connect(handler)
try:
CourseGradeFactory().update(self.request.user, self.course)
except RecursionError:
pytest.fail("The COURSE_GRADE_NOW_PASSED signal fired recursively.")
self.mock_process_signal.assert_called_once()
COURSE_GRADE_NOW_PASSED.disconnect(handler)
def test_read_and_update(self):
grade_factory = CourseGradeFactory()