Esempio n. 1
0
 def test_grade_override(self):
     grade = PersistentSubsectionGrade.update_or_create_grade(**self.params)
     override = PersistentSubsectionGradeOverride(grade=grade, earned_all_override=0.0, earned_graded_override=0.0)
     override.save()
     grade = PersistentSubsectionGrade.update_or_create_grade(**self.params)
     self.assertEqual(grade.earned_all, 0.0)
     self.assertEqual(grade.earned_graded, 0.0)
Esempio n. 2
0
    def test_grade_override(self):
        """
        Creating a subsection grade override should NOT change the score values
        of the related PersistentSubsectionGrade.
        """
        grade = PersistentSubsectionGrade.update_or_create_grade(**self.params)
        override = PersistentSubsectionGradeOverride.update_or_create_override(
            requesting_user=self.user,
            subsection_grade_model=grade,
            earned_all_override=0.0,
            earned_graded_override=0.0,
            feature=PersistentSubsectionGradeOverrideHistory.GRADEBOOK,
        )

        grade = PersistentSubsectionGrade.update_or_create_grade(**self.params)
        self.assertEqual(self.params['earned_all'], grade.earned_all)
        self.assertEqual(self.params['earned_graded'], grade.earned_graded)

        # Any score values that aren't specified should use the values from grade as defaults
        self.assertEqual(0, override.earned_all_override)
        self.assertEqual(0, override.earned_graded_override)
        self.assertEqual(grade.possible_all, override.possible_all_override)
        self.assertEqual(grade.possible_graded, override.possible_graded_override)

        # An override history record should be created
        self.assertEqual(1, PersistentSubsectionGradeOverrideHistory.objects.filter(override_id=override.id).count())
 def update_or_create_model(self, student):
     """
     Saves or updates the subsection grade in a persisted model.
     """
     if self._should_persist_per_attempted:
         self._log_event(log.debug, u"update_or_create_model", student)
         return PersistentSubsectionGrade.update_or_create_grade(**self._persisted_model_params(student))
Esempio n. 4
0
 def test_update_or_create_attempted(self, is_active, expected_first_attempted):
     with freeze_time(now()):
         if expected_first_attempted is None:
             expected_first_attempted = now()
         with waffle.waffle().override(waffle.ESTIMATE_FIRST_ATTEMPTED, active=is_active):
             grade = PersistentSubsectionGrade.update_or_create_grade(**self.params)
             self.assertEqual(grade.first_attempted, expected_first_attempted)
 def setUp(self, **kwargs):
     super(GradesServiceTests, self).setUp()
     self.service = GradesService()
     self.course = CourseFactory.create(org='edX', number='DemoX', display_name='Demo_Course')
     self.subsection = ItemFactory.create(parent=self.course, category="subsection", display_name="Subsection")
     self.user = UserFactory()
     self.grade = PersistentSubsectionGrade.update_or_create_grade(
         user_id=self.user.id,
         course_id=self.course.id,
         usage_key=self.subsection.location,
         first_attempted=None,
         visible_blocks=[],
         earned_all=6.0,
         possible_all=6.0,
         earned_graded=5.0,
         possible_graded=5.0
     )
     self.signal_patcher = patch('lms.djangoapps.grades.signals.signals.SUBSECTION_OVERRIDE_CHANGED.send')
     self.mock_signal = self.signal_patcher.start()
     self.id_patcher = patch('lms.djangoapps.grades.services.create_new_event_transaction_id')
     self.mock_create_id = self.id_patcher.start()
     self.mock_create_id.return_value = 1
     self.type_patcher = patch('lms.djangoapps.grades.services.set_event_transaction_type')
     self.mock_set_type = self.type_patcher.start()
     self.flag_patcher = patch('lms.djangoapps.grades.services.waffle_flags')
     self.mock_waffle_flags = self.flag_patcher.start()
     self.mock_waffle_flags.return_value = {
         REJECTED_EXAM_OVERRIDES_GRADE: MockWaffleFlag(True)
     }
Esempio n. 6
0
 def test_unattempted(self):
     self.params['first_attempted'] = None
     self.params['earned_all'] = 0.0
     self.params['earned_graded'] = 0.0
     grade = PersistentSubsectionGrade.update_or_create_grade(**self.params)
     self.assertIsNone(grade.first_attempted)
     self.assertEqual(grade.earned_all, 0.0)
     self.assertEqual(grade.earned_graded, 0.0)
Esempio n. 7
0
    def test_update_or_create_grade(self, already_created):
        created_grade = PersistentSubsectionGrade.update_or_create_grade(**self.params) if already_created else None

        self.params["earned_all"] = 7
        updated_grade = PersistentSubsectionGrade.update_or_create_grade(**self.params)
        self.assertEqual(updated_grade.earned_all, 7)
        if already_created:
            self.assertEqual(created_grade.id, updated_grade.id)
            self.assertEqual(created_grade.earned_all, 6)

        with self.assertNumQueries(1):
            read_grade = PersistentSubsectionGrade.read_grade(
                user_id=self.params["user_id"],
                usage_key=self.params["usage_key"],
            )
            self.assertEqual(updated_grade, read_grade)
            self.assertEqual(read_grade.visible_blocks.blocks, self.block_records)
Esempio n. 8
0
    def test_update_or_create_grade(self, already_created):
        created_grade = PersistentSubsectionGrade.create_grade(**self.params) if already_created else None

        self.params["earned_all"] = 7
        updated_grade = PersistentSubsectionGrade.update_or_create_grade(**self.params)
        self.assertEqual(updated_grade.earned_all, 7)
        if already_created:
            self.assertEqual(created_grade.id, updated_grade.id)
            self.assertEqual(created_grade.earned_all, 6)
Esempio n. 9
0
    def test_update_or_create_grade(self, already_created):
        created_grade = PersistentSubsectionGrade.create_grade(**self.params) if already_created else None

        self.params["earned_all"] = 7
        updated_grade = PersistentSubsectionGrade.update_or_create_grade(**self.params)
        self.assertEqual(updated_grade.earned_all, 7)
        if already_created:
            self.assertEqual(created_grade.id, updated_grade.id)
            self.assertEqual(created_grade.earned_all, 6)
Esempio n. 10
0
    def test_update_or_create_grade(self, already_created):
        created_grade = PersistentSubsectionGrade.update_or_create_grade(
            **self.params) if already_created else None

        self.params["earned_all"] = 7
        updated_grade = PersistentSubsectionGrade.update_or_create_grade(
            **self.params)
        assert updated_grade.earned_all == 7
        if already_created:
            assert created_grade.id == updated_grade.id
            assert created_grade.earned_all == 6

        with self.assertNumQueries(1):
            read_grade = PersistentSubsectionGrade.read_grade(
                user_id=self.params["user_id"],
                usage_key=self.params["usage_key"],
            )
            assert updated_grade == read_grade
            assert read_grade.visible_blocks.blocks == self.block_records
Esempio n. 11
0
    def _update_or_create_grades(self, courses_keys=None):
        """
        Creates grades for all courses and subsections.
        """
        if courses_keys is None:
            courses_keys = self.course_keys

        course_grade_params = {
            "course_version": "JoeMcEwing",
            "course_edited_timestamp": datetime(
                year=2016,
                month=8,
                day=1,
                hour=18,
                minute=53,
                second=24,
                microsecond=354741,
            ),
            "percent_grade": 77.7,
            "letter_grade": "Great job",
            "passed": True,
        }
        subsection_grade_params = {
            "course_version": "deadbeef",
            "subtree_edited_timestamp": "2016-08-01 18:53:24.354741",
            "earned_all": 6.0,
            "possible_all": 12.0,
            "earned_graded": 6.0,
            "possible_graded": 8.0,
            "visible_blocks": MagicMock(),
            "attempted": True,
        }

        for course_key in courses_keys:
            for user_id in self.user_ids:
                course_grade_params['user_id'] = user_id
                course_grade_params['course_id'] = course_key
                PersistentCourseGrade.update_or_create_course_grade(**course_grade_params)
                for subsection_key in self.subsection_keys_by_course[course_key]:
                    subsection_grade_params['user_id'] = user_id
                    subsection_grade_params['usage_key'] = subsection_key
                    PersistentSubsectionGrade.update_or_create_grade(**subsection_grade_params)
Esempio n. 12
0
    def _update_or_create_grades(self, courses_keys=None):
        """
        Creates grades for all courses and subsections.
        """
        if courses_keys is None:
            courses_keys = self.course_keys

        course_grade_params = {
            "course_version": "JoeMcEwing",
            "course_edited_timestamp": datetime(
                year=2016,
                month=8,
                day=1,
                hour=18,
                minute=53,
                second=24,
                microsecond=354741,
            ),
            "percent_grade": 77.7,
            "letter_grade": "Great job",
            "passed": True,
        }
        subsection_grade_params = {
            "course_version": "deadbeef",
            "subtree_edited_timestamp": "2016-08-01 18:53:24.354741",
            "earned_all": 6.0,
            "possible_all": 12.0,
            "earned_graded": 6.0,
            "possible_graded": 8.0,
            "visible_blocks": MagicMock(),
            "first_attempted": datetime.now(),
        }

        for course_key in courses_keys:
            for user_id in self.user_ids:
                course_grade_params['user_id'] = user_id
                course_grade_params['course_id'] = course_key
                PersistentCourseGrade.update_or_create(**course_grade_params)
                for subsection_key in self.subsection_keys_by_course[course_key]:
                    subsection_grade_params['user_id'] = user_id
                    subsection_grade_params['usage_key'] = subsection_key
                    PersistentSubsectionGrade.update_or_create_grade(**subsection_grade_params)
 def update_or_create_model(self,
                            student,
                            score_deleted=False,
                            force_update_subsections=False):
     """
     Saves or updates the subsection grade in a persisted model.
     """
     if self._should_persist_per_attempted(score_deleted,
                                           force_update_subsections):
         return PersistentSubsectionGrade.update_or_create_grade(
             **self._persisted_model_params(student))
Esempio n. 14
0
 def test_update_or_create_attempted(self, is_active,
                                     expected_first_attempted):
     with freeze_time(now()):
         if expected_first_attempted is None:
             expected_first_attempted = now()
         with waffle.waffle().override(waffle.ESTIMATE_FIRST_ATTEMPTED,
                                       active=is_active):
             grade = PersistentSubsectionGrade.update_or_create_grade(
                 **self.params)
             self.assertEqual(grade.first_attempted,
                              expected_first_attempted)
Esempio n. 15
0
    def test_update_or_create_grade(self, already_created):
        created_grade = PersistentSubsectionGrade.update_or_create_grade(
            **self.params) if already_created else None

        self.params["earned_all"] = 7
        updated_grade = PersistentSubsectionGrade.update_or_create_grade(
            **self.params)
        self.assertEqual(updated_grade.earned_all, 7)
        if already_created:
            self.assertEqual(created_grade.id, updated_grade.id)
            self.assertEqual(created_grade.earned_all, 6)

        with self.assertNumQueries(1):
            read_grade = PersistentSubsectionGrade.read_grade(
                user_id=self.params["user_id"],
                usage_key=self.params["usage_key"],
            )
            self.assertEqual(updated_grade, read_grade)
            self.assertEqual(read_grade.visible_blocks.blocks,
                             self.block_records)
Esempio n. 16
0
 def setUp(self):
     super(OverrideSubsectionGradeTests, self).setUp()
     self.course = CourseFactory.create(org='edX', number='DemoX', display_name='Demo_Course', run='Spring2019')
     self.subsection = ItemFactory.create(parent=self.course, category="subsection", display_name="Subsection")
     self.grade = PersistentSubsectionGrade.update_or_create_grade(
         user_id=self.user.id,
         course_id=self.course.id,
         usage_key=self.subsection.location,
         first_attempted=None,
         visible_blocks=[],
         earned_all=6.0,
         possible_all=6.0,
         earned_graded=5.0,
         possible_graded=5.0
     )
Esempio n. 17
0
    def test_grade_override(self):
        """
        Creating a subsection grade override should NOT change the score values
        of the related PersistentSubsectionGrade.
        """
        grade = PersistentSubsectionGrade.update_or_create_grade(**self.params)
        override = PersistentSubsectionGradeOverride.update_or_create_override(
            requesting_user=self.user,
            subsection_grade_model=grade,
            earned_all_override=0.0,
            earned_graded_override=0.0,
            feature=GradeOverrideFeatureEnum.gradebook,
        )

        grade = PersistentSubsectionGrade.update_or_create_grade(**self.params)
        self.assertEqual(self.params['earned_all'], grade.earned_all)
        self.assertEqual(self.params['earned_graded'], grade.earned_graded)

        # Any score values that aren't specified should use the values from grade as defaults
        self.assertEqual(0, override.earned_all_override)
        self.assertEqual(0, override.earned_graded_override)
        self.assertEqual(grade.possible_all, override.possible_all_override)
        self.assertEqual(grade.possible_graded,
                         override.possible_graded_override)
Esempio n. 18
0
    def update_or_create_model(self, student, score_deleted=False, force_update_subsections=False):
        """
        Saves or updates the subsection grade in a persisted model.
        """
        if self._should_persist_per_attempted(score_deleted, force_update_subsections):
            model = PersistentSubsectionGrade.update_or_create_grade(**self._persisted_model_params(student))

            if hasattr(model, 'override'):
                # When we're doing an update operation, the PersistentSubsectionGrade model
                # will be updated based on the problem_scores, but if a grade override
                # exists that's related to the updated persistent grade, we need to update
                # the aggregated scores for this object to reflect the override.
                self.all_total = self._aggregated_score_from_model(model, is_graded=False)
                self.graded_total = self._aggregated_score_from_model(model, is_graded=True)

            return model
Esempio n. 19
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
Esempio n. 20
0
 def setUp(self):
     super(GradesServiceTests, self).setUp()
     self.service = GradesService()
     self.course = CourseFactory.create(org='edX',
                                        number='DemoX',
                                        display_name='Demo_Course',
                                        run='Spring2019')
     self.subsection = ItemFactory.create(parent=self.course,
                                          category="subsection",
                                          display_name="Subsection")
     self.subsection_without_grade = ItemFactory.create(
         parent=self.course,
         category="subsection",
         display_name="Subsection without grade")
     self.user = UserFactory()
     self.grade = PersistentSubsectionGrade.update_or_create_grade(
         user_id=self.user.id,
         course_id=self.course.id,
         usage_key=self.subsection.location,
         first_attempted=None,
         visible_blocks=[],
         earned_all=6.0,
         possible_all=6.0,
         earned_graded=5.0,
         possible_graded=5.0)
     self.signal_patcher = patch(
         'lms.djangoapps.grades.signals.signals.SUBSECTION_OVERRIDE_CHANGED.send'
     )
     self.mock_signal = self.signal_patcher.start()
     self.id_patcher = patch(
         'lms.djangoapps.grades.api.create_new_event_transaction_id')
     self.mock_create_id = self.id_patcher.start()
     self.mock_create_id.return_value = 1
     self.type_patcher = patch(
         'lms.djangoapps.grades.api.set_event_transaction_type')
     self.mock_set_type = self.type_patcher.start()
     self.flag_patcher = patch(
         'lms.djangoapps.grades.config.waffle.waffle_flags')
     self.mock_waffle_flags = self.flag_patcher.start()
     self.mock_waffle_flags.return_value = {
         REJECTED_EXAM_OVERRIDES_GRADE: MockWaffleFlag(True)
     }
    def update_or_create_model(self, student, score_deleted=False, force_update_subsections=False):
        """
        Saves or updates the subsection grade in a persisted model.
        """
        if self._should_persist_per_attempted(score_deleted, force_update_subsections):
            # TODO: Remove as part of EDUCATOR-4602.
            if str(self.location.course_key) == 'course-v1:UQx+BUSLEAD5x+2T2019':
                log.info('Updating PersistentSubsectionGrade for student ***{}*** in'
                         ' subsection ***{}*** with params ***{}***.'
                         .format(student.id, self.location, self._persisted_model_params(student)))
            model = PersistentSubsectionGrade.update_or_create_grade(**self._persisted_model_params(student))

            if hasattr(model, 'override'):
                # When we're doing an update operation, the PersistentSubsectionGrade model
                # will be updated based on the problem_scores, but if a grade override
                # exists that's related to the updated persistent grade, we need to update
                # the aggregated scores for this object to reflect the override.
                self.all_total = self._aggregated_score_from_model(model, is_graded=False)
                self.graded_total = self._aggregated_score_from_model(model, is_graded=True)

            return model
Esempio n. 22
0
 def test_update_or_create_inconsistent_unattempted(self):
     self.params['attempted'] = False
     self.params['earned_all'] = 1.0
     self.params['earned_graded'] = 1.0
     with self.assertRaises(ValidationError):
         PersistentSubsectionGrade.update_or_create_grade(**self.params)
Esempio n. 23
0
 def test_first_attempted_not_changed_on_update(self):
     PersistentSubsectionGrade.create_grade(**self.params)
     moment = now()
     grade = PersistentSubsectionGrade.update_or_create_grade(**self.params)
     self.assertLess(grade.first_attempted, moment)
Esempio n. 24
0
 def update_or_create_model(self, student, score_deleted=False):
     """
     Saves or updates the subsection grade in a persisted model.
     """
     if self._should_persist_per_attempted(score_deleted):
         return PersistentSubsectionGrade.update_or_create_grade(**self._persisted_model_params(student))
Esempio n. 25
0
 def update_or_create_model(self, student):
     """
     Saves or updates the subsection grade in a persisted model.
     """
     self._log_event(log.info, u"update_or_create_model", student)
     return PersistentSubsectionGrade.update_or_create_grade(**self._persisted_model_params(student))
Esempio n. 26
0
 def test_update_or_create_attempted(self):
     grade = PersistentSubsectionGrade.update_or_create_grade(**self.params)
     self.assertIsInstance(grade.first_attempted, datetime)
Esempio n. 27
0
 def test_update_or_create_attempted(self):
     grade = PersistentSubsectionGrade.update_or_create_grade(**self.params)
     self.assertIsInstance(grade.first_attempted, datetime)
Esempio n. 28
0
 def test_unattempted_save_does_not_remove_attempt(self):
     PersistentSubsectionGrade.update_or_create_grade(**self.params)
     self.params['first_attempted'] = None
     grade = PersistentSubsectionGrade.update_or_create_grade(**self.params)
     self.assertIsInstance(grade.first_attempted, datetime)
     self.assertEqual(grade.earned_all, 6.0)
Esempio n. 29
0
 def test_optional_fields(self, field):
     del self.params[field]
     PersistentSubsectionGrade.update_or_create_grade(**self.params)
Esempio n. 30
0
 def test_optional_fields(self, field):
     del self.params[field]
     PersistentSubsectionGrade.update_or_create_grade(**self.params)
Esempio n. 31
0
 def test_update_or_create_inconsistent_unattempted(self):
     self.params['attempted'] = False
     self.params['earned_all'] = 1.0
     self.params['earned_graded'] = 1.0
     with self.assertRaises(ValidationError):
         PersistentSubsectionGrade.update_or_create_grade(**self.params)
Esempio n. 32
0
 def update_or_create_model(self, student):
     """
     Saves or updates the subsection grade in a persisted model.
     """
     self._log_event(log.info, u"update_or_create_model", student)
     return PersistentSubsectionGrade.update_or_create_grade(**self._persisted_model_params(student))
Esempio n. 33
0
 def test_non_optional_fields(self, field, error):
     del self.params[field]
     with self.assertRaises(error):
         PersistentSubsectionGrade.update_or_create_grade(**self.params)
Esempio n. 34
0
 def test_unattempted_save_does_not_remove_attempt(self):
     PersistentSubsectionGrade.create_grade(**self.params)
     self.params['first_attempted'] = None
     grade = PersistentSubsectionGrade.update_or_create_grade(**self.params)
     self.assertIsInstance(grade.first_attempted, datetime)
     self.assertEqual(grade.earned_all, 6.0)
Esempio n. 35
0
 def test_first_attempted_not_changed_on_update(self):
     PersistentSubsectionGrade.update_or_create_grade(**self.params)
     moment = now()
     grade = PersistentSubsectionGrade.update_or_create_grade(**self.params)
     self.assertLess(grade.first_attempted, moment)
Esempio n. 36
0
 def test_update_or_create_event(self):
     with patch('lms.djangoapps.grades.models.tracker') as tracker_mock:
         grade = PersistentSubsectionGrade.update_or_create_grade(**self.params)
     self._assert_tracker_emitted_event(tracker_mock, grade)
Esempio n. 37
0
 def test_create_event(self):
     with patch('lms.djangoapps.grades.events.tracker') as tracker_mock:
         grade = PersistentSubsectionGrade.update_or_create_grade(
             **self.params)
     self._assert_tracker_emitted_event(tracker_mock, grade)
Esempio n. 38
0
 def test_non_optional_fields(self, field, error):
     del self.params[field]
     with self.assertRaises(error):
         PersistentSubsectionGrade.update_or_create_grade(**self.params)