def test_enable_disable_globally(self):
     """
     Ensures that the flag, once enabled globally, can also be disabled.
     """
     with persistent_grades_feature_flags(
             global_flag=True,
             enabled_for_all_courses=True,
     ):
         self.assertTrue(PersistentGradesEnabledFlag.feature_enabled())
         self.assertTrue(
             PersistentGradesEnabledFlag.feature_enabled(self.course_id_1))
         with persistent_grades_feature_flags(
                 global_flag=True,
                 enabled_for_all_courses=False,
         ):
             self.assertTrue(PersistentGradesEnabledFlag.feature_enabled())
             self.assertFalse(
                 PersistentGradesEnabledFlag.feature_enabled(
                     self.course_id_1))
             with persistent_grades_feature_flags(global_flag=False, ):
                 self.assertFalse(
                     PersistentGradesEnabledFlag.feature_enabled())
                 self.assertFalse(
                     PersistentGradesEnabledFlag.feature_enabled(
                         self.course_id_1))
    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)
Example #3
0
    def test_create(self):
        """
        Tests to ensure that a persistent subsection grade is created, saved, then fetched on re-request.
        """
        with persistent_grades_feature_flags(global_flag=True,
                                             enabled_for_all_courses=False,
                                             course_id=self.course.id,
                                             enabled_for_course=True):
            with patch(
                    'lms.djangoapps.grades.new.subsection_grade.SubsectionGradeFactory._save_grade',
                    wraps=self.subsection_grade_factory._save_grade  # pylint: disable=protected-access
            ) as mock_save_grades:
                with patch(
                        'lms.djangoapps.grades.new.subsection_grade.SubsectionGradeFactory._get_saved_grade',
                        wraps=self.subsection_grade_factory._get_saved_grade  # pylint: disable=protected-access
                ) as mock_get_saved_grade:
                    with self.assertNumQueries(22):
                        grade_a = self.subsection_grade_factory.create(
                            self.sequence, self.course_structure, self.course)
                    self.assertTrue(mock_get_saved_grade.called)
                    self.assertTrue(mock_save_grades.called)

                    mock_get_saved_grade.reset_mock()
                    mock_save_grades.reset_mock()

                    with self.assertNumQueries(4):
                        grade_b = self.subsection_grade_factory.create(
                            self.sequence, self.course_structure, self.course)
                    self.assertTrue(mock_get_saved_grade.called)
                    self.assertFalse(mock_save_grades.called)

        self.assertEqual(grade_a.url_name, grade_b.url_name)
        self.assertEqual(grade_a.all_total, grade_b.all_total)
Example #4
0
    def test_course_grade_logging(self):
        grade_factory = CourseGradeFactory(self.request.user)
        with persistent_grades_feature_flags(global_flag=True,
                                             enabled_for_all_courses=False,
                                             course_id=self.course.id,
                                             enabled_for_course=True):
            with patch(
                    'lms.djangoapps.grades.new.course_grade.log') as log_mock:
                # the course grade has not been created, so we expect each grade to be created
                log_statement = u''.join((
                    u"compute_and_update, read_only: {0}, subsections read/created: {1}/{2}, blocks ",
                    u"accessed: {3}, total graded subsections: {4}")).format(
                        False, 0, 3, 3, 2)
                self._create_course_grade_and_check_logging(
                    grade_factory, log_mock.warning, log_statement)
                log_mock.reset_mock()

                # the course grade has been created, so we expect to read it from the db
                log_statement = u"load_persisted_grade"
                self._create_course_grade_and_check_logging(
                    grade_factory, log_mock.info, log_statement)
                log_mock.reset_mock()

                # only problem submission, a subsection grade update triggers
                # a course grade update
                self.submit_question_answer(u'test_problem_1',
                                            {u'2_1': u'choice_choice_2'})
                log_statement = u''.join((
                    u"compute_and_update, read_only: {0}, subsections read/created: {1}/{2}, blocks ",
                    u"accessed: {3}, total graded subsections: {4}")).format(
                        False, 3, 0, 3, 2)
                self._create_course_grade_and_check_logging(
                    grade_factory, log_mock.warning, log_statement)
Example #5
0
    def test_course_grade_logging(self):
        grade_factory = CourseGradeFactory()
        with persistent_grades_feature_flags(global_flag=True,
                                             enabled_for_all_courses=False,
                                             course_id=self.course.id,
                                             enabled_for_course=True):
            with patch('lms.djangoapps.grades.new.course_grade_factory.log'
                       ) as log_mock:
                # returns Zero when no grade, with ASSUME_ZERO_GRADE_IF_ABSENT
                with waffle().override(ASSUME_ZERO_GRADE_IF_ABSENT,
                                       active=True):
                    self._create_course_grade_and_check_logging(
                        grade_factory.create, log_mock, u'CreateZero')

                # read, but not persisted
                self._create_course_grade_and_check_logging(
                    grade_factory.create, log_mock, u'Update')

                # update and persist
                self._create_course_grade_and_check_logging(
                    grade_factory.update, log_mock, u'Update')

                # read from persistence, using create
                self._create_course_grade_and_check_logging(
                    grade_factory.create, log_mock, u'Read')

                # read from persistence, using read
                self._create_course_grade_and_check_logging(
                    grade_factory.read, log_mock, u'Read')
Example #6
0
 def test_course_grade_logging(self):
     grade_factory = CourseGradeFactory(self.request.user)
     with persistent_grades_feature_flags(
         global_flag=True,
         enabled_for_all_courses=False,
         course_id=self.course.id,
         enabled_for_course=True
     ):
         with patch('lms.djangoapps.grades.new.course_grade.log') as log_mock:
             # the course grade has not been created, so we expect each grade to be created
             self._create_course_grade_and_check_logging(
                 grade_factory,
                 log_mock,
                 read_only=False,
                 subsections_read=0,
                 subsections_created=3,
                 blocks_accessed=3,
                 total_graded_subsections=2)
             # the course grade has been created, so we expect each grade to be read
             self._create_course_grade_and_check_logging(
                 grade_factory,
                 log_mock,
                 read_only=False,
                 subsections_read=3,
                 subsections_created=0,
                 blocks_accessed=3,
                 total_graded_subsections=2,
             )
 def test_enable_disable_course_flag(self):
     """
     Ensures that the flag, once enabled for a course, can also be disabled.
     """
     with persistent_grades_feature_flags(global_flag=True,
                                          enabled_for_all_courses=False,
                                          course_id=self.course_id_1,
                                          enabled_for_course=True):
         self.assertTrue(
             PersistentGradesEnabledFlag.feature_enabled(self.course_id_1))
         # Prior to TNL-5698, creating a second object would fail due to db constraints
         with persistent_grades_feature_flags(global_flag=True,
                                              enabled_for_all_courses=False,
                                              course_id=self.course_id_1,
                                              enabled_for_course=False):
             self.assertFalse(
                 PersistentGradesEnabledFlag.feature_enabled(
                     self.course_id_1))
 def test_enable_disable_course_flag(self):
     """
     Ensures that the flag, once enabled for a course, can also be disabled.
     """
     with persistent_grades_feature_flags(
         global_flag=True,
         enabled_for_all_courses=False,
         course_id=self.course_id_1,
         enabled_for_course=True
     ):
         self.assertTrue(PersistentGradesEnabledFlag.feature_enabled(self.course_id_1))
         # Prior to TNL-5698, creating a second object would fail due to db constraints
         with persistent_grades_feature_flags(
             global_flag=True,
             enabled_for_all_courses=False,
             course_id=self.course_id_1,
             enabled_for_course=False
         ):
             self.assertFalse(PersistentGradesEnabledFlag.feature_enabled(self.course_id_1))
 def test_enable_disable_globally(self):
     """
     Ensures that the flag, once enabled globally, can also be disabled.
     """
     with persistent_grades_feature_flags(
         global_flag=True,
         enabled_for_all_courses=True,
     ):
         self.assertTrue(PersistentGradesEnabledFlag.feature_enabled())
         self.assertTrue(PersistentGradesEnabledFlag.feature_enabled(self.course_id_1))
         with persistent_grades_feature_flags(
             global_flag=True,
             enabled_for_all_courses=False,
         ):
             self.assertTrue(PersistentGradesEnabledFlag.feature_enabled())
             self.assertFalse(PersistentGradesEnabledFlag.feature_enabled(self.course_id_1))
             with persistent_grades_feature_flags(
                 global_flag=False,
             ):
                 self.assertFalse(PersistentGradesEnabledFlag.feature_enabled())
                 self.assertFalse(PersistentGradesEnabledFlag.feature_enabled(self.course_id_1))
 def test_course_grade_feature_gating(self, feature_flag, course_setting):
     # Grades are only saved if the feature flag and the advanced setting are
     # both set to True.
     grade_factory = CourseGradeFactory()
     with persistent_grades_feature_flags(
         global_flag=feature_flag,
         enabled_for_all_courses=False,
         course_id=self.course.id,
         enabled_for_course=course_setting
     ):
         with patch('lms.djangoapps.grades.models.PersistentCourseGrade.read') as mock_read_grade:
             grade_factory.read(self.request.user, self.course)
     self.assertEqual(mock_read_grade.called, feature_flag and course_setting)
Example #11
0
 def test_course_grade_feature_gating(self, feature_flag, course_setting):
     # Grades are only saved if the feature flag and the advanced setting are
     # both set to True.
     grade_factory = CourseGradeFactory(self.request.user)
     with persistent_grades_feature_flags(
         global_flag=feature_flag,
         enabled_for_all_courses=False,
         course_id=self.course.id,
         enabled_for_course=course_setting
     ):
         with patch('lms.djangoapps.grades.new.course_grade._pretend_to_save_course_grades') as mock_save_grades:
             grade_factory.create(self.course)
     self.assertEqual(mock_save_grades.called, feature_flag and course_setting)
 def test_subsection_grade_feature_gating(self, feature_flag, course_setting):
     # Grades are only saved if the feature flag and the advanced setting are
     # both set to True.
     with patch(
         'lms.djangoapps.grades.models.PersistentSubsectionGrade.bulk_read_grades'
     ) as mock_read_saved_grade:
         with persistent_grades_feature_flags(
             global_flag=feature_flag,
             enabled_for_all_courses=False,
             course_id=self.course.id,
             enabled_for_course=course_setting
         ):
             self.subsection_grade_factory.create(self.sequence)
     self.assertEqual(mock_read_saved_grade.called, feature_flag and course_setting)
Example #13
0
 def test_subsection_grade_feature_gating(self, feature_flag, course_setting):
     # Grades are only saved if the feature flag and the advanced setting are
     # both set to True.
     with patch(
         'lms.djangoapps.grades.models.PersistentSubsectionGrade.bulk_read_grades'
     ) as mock_read_saved_grade:
         with persistent_grades_feature_flags(
             global_flag=feature_flag,
             enabled_for_all_courses=False,
             course_id=self.course.id,
             enabled_for_course=course_setting
         ):
             self.subsection_grade_factory.create(self.sequence)
     self.assertEqual(mock_read_saved_grade.called, feature_flag and course_setting)
Example #14
0
 def test_persistent_grades_feature_flags(self, global_flag, enabled_for_all_courses, enabled_for_course_1):
     with persistent_grades_feature_flags(
         global_flag=global_flag,
         enabled_for_all_courses=enabled_for_all_courses,
         course_id=self.course_id_1,
         enabled_for_course=enabled_for_course_1
     ):
         assert PersistentGradesEnabledFlag.feature_enabled() == global_flag
         assert PersistentGradesEnabledFlag.feature_enabled(
             self.course_id_1
         ) == (global_flag and (enabled_for_all_courses or enabled_for_course_1))
         assert PersistentGradesEnabledFlag.feature_enabled(
             self.course_id_2
         ) == (global_flag and enabled_for_all_courses)
 def test_persistent_grades_feature_flags(self, global_flag, enabled_for_all_courses, enabled_for_course_1):
     with persistent_grades_feature_flags(
         global_flag=global_flag,
         enabled_for_all_courses=enabled_for_all_courses,
         course_id=self.course_id_1,
         enabled_for_course=enabled_for_course_1
     ):
         self.assertEqual(PersistentGradesEnabledFlag.feature_enabled(), global_flag)
         self.assertEqual(
             PersistentGradesEnabledFlag.feature_enabled(self.course_id_1),
             global_flag and (enabled_for_all_courses or enabled_for_course_1)
         )
         self.assertEqual(
             PersistentGradesEnabledFlag.feature_enabled(self.course_id_2),
             global_flag and enabled_for_all_courses
         )
Example #16
0
    def test_override_is_visible(self):
        with persistent_grades_feature_flags(global_flag=True):
            chapter = ItemFactory(parent=self.course, category='chapter')
            subsection = ItemFactory.create(parent=chapter,
                                            category="sequential",
                                            display_name="Subsection")

            CourseEnrollment.enroll(self.user, self.course.id)

            params = {
                "user_id": self.user.id,
                "usage_key": subsection.location,
                "course_version": self.course.course_version,
                "subtree_edited_timestamp": "2016-08-01 18:53:24.354741Z",
                "earned_all": 6.0,
                "possible_all": 12.0,
                "earned_graded": 6.0,
                "possible_graded": 8.0,
                "visible_blocks": [],
                "first_attempted": datetime.now(),
            }

            created_grade = PersistentSubsectionGrade.update_or_create_grade(
                **params)
            proctoring_failure_comment = "Failed Test Proctoring"
            PersistentSubsectionGradeOverride.update_or_create_override(
                requesting_user=self.staff_user,
                subsection_grade_model=created_grade,
                earned_all_override=0.0,
                earned_graded_override=0.0,
                system=GradeOverrideFeatureEnum.proctoring,
                feature=GradeOverrideFeatureEnum.proctoring,
                comment=proctoring_failure_comment)

            response = self.client.get(self.url)
            assert response.status_code == 200

            sections = response.data['section_scores']
            overridden_subsection = sections[1]['subsections'][0]
            override_entry = overridden_subsection["override"]

            assert override_entry[
                'system'] == GradeOverrideFeatureEnum.proctoring
            assert override_entry['reason'] == proctoring_failure_comment
Example #17
0
    def test_course_grade_logging(self):
        grade_factory = CourseGradeFactory()
        with persistent_grades_feature_flags(
            global_flag=True,
            enabled_for_all_courses=False,
            course_id=self.course.id,
            enabled_for_course=True
        ):
            with patch('lms.djangoapps.grades.new.course_grade.log') as log_mock:
                # the course grade has not been created, so we expect each grade to be created
                log_statement = u''.join((
                    u"compute_and_update, read_only: {0}, subsections read/created: {1}/{2}, blocks ",
                    u"accessed: {3}, total graded subsections: {4}"
                )).format(False, 0, 3, 3, 2)
                self._create_course_grade_and_check_logging(
                    grade_factory,
                    log_mock.warning,
                    log_statement
                )
                log_mock.reset_mock()

                # the course grade has been created, so we expect to read it from the db
                log_statement = u"load_persisted_grade"
                self._create_course_grade_and_check_logging(
                    grade_factory,
                    log_mock.info,
                    log_statement
                )
                log_mock.reset_mock()

                # only problem submission, a subsection grade update triggers
                # a course grade update
                self.submit_question_answer(u'test_problem_1', {u'2_1': u'choice_choice_2'})
                log_statement = u''.join((
                    u"compute_and_update, read_only: {0}, subsections read/created: {1}/{2}, blocks ",
                    u"accessed: {3}, total graded subsections: {4}"
                )).format(False, 3, 0, 3, 2)
                self._create_course_grade_and_check_logging(
                    grade_factory,
                    log_mock.warning,
                    log_statement
                )
Example #18
0
    def test_course_grade_logging(self):
        grade_factory = CourseGradeFactory()
        with persistent_grades_feature_flags(
            global_flag=True,
            enabled_for_all_courses=False,
            course_id=self.course.id,
            enabled_for_course=True
        ):
            with patch('lms.djangoapps.grades.new.course_grade_factory.log') as log_mock:
                # read, but not persisted
                self._create_course_grade_and_check_logging(grade_factory.create, log_mock.info, u'Update')

                # update and persist
                self._create_course_grade_and_check_logging(grade_factory.update, log_mock.info, u'Update')

                # read from persistence, using create
                self._create_course_grade_and_check_logging(grade_factory.create, log_mock.debug, u'Read')

                # read from persistence, using read
                self._create_course_grade_and_check_logging(grade_factory.read, log_mock.debug, u'Read')
Example #19
0
    def test_course_grade_logging(self):
        grade_factory = CourseGradeFactory()
        with persistent_grades_feature_flags(
            global_flag=True,
            enabled_for_all_courses=False,
            course_id=self.course.id,
            enabled_for_course=True
        ):
            with patch('lms.djangoapps.grades.new.course_grade_factory.log') as log_mock:
                # read, but not persisted
                self._create_course_grade_and_check_logging(grade_factory.create, log_mock.info, u'Update')

                # update and persist
                self._create_course_grade_and_check_logging(grade_factory.update, log_mock.info, u'Update')

                # read from persistence, using create
                self._create_course_grade_and_check_logging(grade_factory.create, log_mock.debug, u'Read')

                # read from persistence, using read
                self._create_course_grade_and_check_logging(grade_factory.read, log_mock.debug, u'Read')
Example #20
0
    def test_create(self):
        """
        Tests to ensure that a persistent subsection grade is created, saved, then fetched on re-request.
        """
        with persistent_grades_feature_flags(
            global_flag=True,
            enabled_for_all_courses=False,
            course_id=self.course.id,
            enabled_for_course=True
        ):
            with patch(
                'lms.djangoapps.grades.new.subsection_grade.SubsectionGradeFactory._save_grade',
                wraps=self.subsection_grade_factory._save_grade  # pylint: disable=protected-access
            ) as mock_save_grades:
                with patch(
                    'lms.djangoapps.grades.new.subsection_grade.SubsectionGradeFactory._get_saved_grade',
                    wraps=self.subsection_grade_factory._get_saved_grade  # pylint: disable=protected-access
                ) as mock_get_saved_grade:
                    with self.assertNumQueries(22):
                        grade_a = self.subsection_grade_factory.create(
                            self.sequence,
                            self.course_structure,
                            self.course
                        )
                    self.assertTrue(mock_get_saved_grade.called)
                    self.assertTrue(mock_save_grades.called)

                    mock_get_saved_grade.reset_mock()
                    mock_save_grades.reset_mock()

                    with self.assertNumQueries(4):
                        grade_b = self.subsection_grade_factory.create(
                            self.sequence,
                            self.course_structure,
                            self.course
                        )
                    self.assertTrue(mock_get_saved_grade.called)
                    self.assertFalse(mock_save_grades.called)

        self.assertEqual(grade_a.url_name, grade_b.url_name)
        self.assertEqual(grade_a.all_total, grade_b.all_total)
Example #21
0
    def test_course_grade_logging(self):
        grade_factory = CourseGradeFactory()
        with persistent_grades_feature_flags(
            global_flag=True,
            enabled_for_all_courses=False,
            course_id=self.course.id,
            enabled_for_course=True
        ):
            with patch('lms.djangoapps.grades.new.course_grade_factory.log') as log_mock:
                # returns Zero when no grade, with ASSUME_ZERO_GRADE_IF_ABSENT
                with waffle().override(ASSUME_ZERO_GRADE_IF_ABSENT, active=True):
                    self._create_course_grade_and_check_logging(grade_factory.create, log_mock, u'CreateZero')

                # read, but not persisted
                self._create_course_grade_and_check_logging(grade_factory.create, log_mock, u'Update')

                # update and persist
                self._create_course_grade_and_check_logging(grade_factory.update, log_mock, u'Update')

                # read from persistence, using create
                self._create_course_grade_and_check_logging(grade_factory.create, log_mock, u'Read')

                # read from persistence, using read
                self._create_course_grade_and_check_logging(grade_factory.read, log_mock, u'Read')