def _create_override(self, request_user, subsection_grade_model, **override_data): """ Helper method to create a `PersistentSubsectionGradeOverride` object and send a `SUBSECTION_OVERRIDE_CHANGED` signal. """ override = PersistentSubsectionGradeOverride.update_or_create_override( requesting_user=request_user, subsection_grade_model=subsection_grade_model, feature=grades_constants.GradeOverrideFeatureEnum.gradebook, **override_data ) set_event_transaction_type(grades_events.SUBSECTION_GRADE_CALCULATED) create_new_event_transaction_id() recalculate_subsection_grade_v3.apply( kwargs=dict( user_id=subsection_grade_model.user_id, anonymous_user_id=None, course_id=text_type(subsection_grade_model.course_id), usage_id=text_type(subsection_grade_model.usage_key), only_if_higher=False, expected_modified_time=to_timestamp(override.modified), score_deleted=False, event_transaction_id=six.text_type(get_event_transaction_id()), event_transaction_type=six.text_type(get_event_transaction_type()), score_db_table=grades_constants.ScoreDatabaseTableEnum.overrides, force_update_subsections=True, ) ) # Emit events to let our tracking system to know we updated subsection grade grades_events.subsection_grade_calculated(subsection_grade_model) return override
def test_retry_when_db_not_updated(self, score_db_table, mock_log, mock_retry): self.set_up_course() self.recalculate_subsection_grade_kwargs[ 'score_db_table'] = score_db_table modified_datetime = datetime.utcnow().replace( tzinfo=pytz.UTC) - timedelta(days=1) if score_db_table == ScoreDatabaseTableEnum.submissions: with patch('lms.djangoapps.grades.tasks.sub_api.get_score' ) as mock_sub_score: mock_sub_score.return_value = {'created_at': modified_datetime} self._apply_recalculate_subsection_grade(mock_score=MagicMock( module_type='any_block_type')) elif score_db_table == ScoreDatabaseTableEnum.courseware_student_module: self._apply_recalculate_subsection_grade(mock_score=MagicMock( modified=modified_datetime)) else: with patch('lms.djangoapps.grades.api') as mock_grade_service: mock_grade_service.get_subsection_grade_override = MagicMock( return_value=MagicMock(modified=modified_datetime)) recalculate_subsection_grade_v3.apply( kwargs=self.recalculate_subsection_grade_kwargs) self._assert_retry_called(mock_retry) self.assertIn( u"Grades: tasks._has_database_updated_with_new_score is False.", mock_log.info.call_args_list[0][0][0])
def test_when_no_score_found(self, score_deleted, score_db_table, mock_log, mock_retry): self.set_up_course() self.recalculate_subsection_grade_kwargs[ 'score_deleted'] = score_deleted self.recalculate_subsection_grade_kwargs[ 'score_db_table'] = score_db_table if score_db_table == ScoreDatabaseTableEnum.submissions: with patch('lms.djangoapps.grades.tasks.sub_api.get_score' ) as mock_sub_score: mock_sub_score.return_value = None self._apply_recalculate_subsection_grade(mock_score=MagicMock( module_type='any_block_type')) elif score_db_table == ScoreDatabaseTableEnum.overrides: with patch('lms.djangoapps.grades.api') as mock_grade_service: mock_grade_service.get_subsection_grade_override.return_value = None recalculate_subsection_grade_v3.apply( kwargs=self.recalculate_subsection_grade_kwargs) else: self._apply_recalculate_subsection_grade(mock_score=None) if score_deleted: self._assert_retry_not_called(mock_retry) else: self._assert_retry_called(mock_retry) self.assertIn( u"Grades: tasks._has_database_updated_with_new_score is False.", mock_log.info.call_args_list[0][0][0])
def test_retry_when_db_not_updated(self, score_db_table, mock_log, mock_retry): self.set_up_course() self.recalculate_subsection_grade_kwargs['score_db_table'] = score_db_table modified_datetime = datetime.utcnow().replace(tzinfo=pytz.UTC) - timedelta(days=1) if score_db_table == ScoreDatabaseTableEnum.submissions: with patch('lms.djangoapps.grades.tasks.sub_api.get_score') as mock_sub_score: mock_sub_score.return_value = { 'created_at': modified_datetime } self._apply_recalculate_subsection_grade( mock_score=MagicMock(module_type='any_block_type') ) elif score_db_table == ScoreDatabaseTableEnum.courseware_student_module: self._apply_recalculate_subsection_grade( mock_score=MagicMock(modified=modified_datetime) ) else: with patch( 'lms.djangoapps.grades.tasks.GradesService', return_value=MockGradesService(mocked_return_value=MagicMock(modified=modified_datetime)) ): recalculate_subsection_grade_v3.apply(kwargs=self.recalculate_subsection_grade_kwargs) self._assert_retry_called(mock_retry) self.assertIn( u"Grades: tasks._has_database_updated_with_new_score is False.", mock_log.info.call_args_list[0][0][0] )
def test_when_no_score_found(self, score_deleted, score_db_table, mock_log, mock_retry): self.set_up_course() self.recalculate_subsection_grade_kwargs['score_deleted'] = score_deleted self.recalculate_subsection_grade_kwargs['score_db_table'] = score_db_table if score_db_table == ScoreDatabaseTableEnum.submissions: with patch('lms.djangoapps.grades.tasks.sub_api.get_score') as mock_sub_score: mock_sub_score.return_value = None self._apply_recalculate_subsection_grade( mock_score=MagicMock(module_type='any_block_type') ) elif score_db_table == ScoreDatabaseTableEnum.overrides: with patch('lms.djangoapps.grades.tasks.GradesService', return_value=MockGradesService(mocked_return_value=None)) as mock_service: mock_service.get_subsection_grade_override.return_value = None recalculate_subsection_grade_v3.apply(kwargs=self.recalculate_subsection_grade_kwargs) else: self._apply_recalculate_subsection_grade(mock_score=None) if score_deleted: self._assert_retry_not_called(mock_retry) else: self._assert_retry_called(mock_retry) self.assertIn( u"Grades: tasks._has_database_updated_with_new_score is False.", mock_log.info.call_args_list[0][0][0] )
def _create_override(self, request_user, subsection_grade_model, **override_data): """ Helper method to create a `PersistentSubsectionGradeOverride` object and send a `SUBSECTION_OVERRIDE_CHANGED` signal. """ override_data[ 'system'] = grades_constants.GradeOverrideFeatureEnum.gradebook override = PersistentSubsectionGradeOverride.update_or_create_override( requesting_user=request_user, subsection_grade_model=subsection_grade_model, feature=grades_constants.GradeOverrideFeatureEnum.gradebook, **override_data) set_event_transaction_type(grades_events.SUBSECTION_GRADE_CALCULATED) create_new_event_transaction_id() recalculate_subsection_grade_v3.apply(kwargs=dict( user_id=subsection_grade_model.user_id, anonymous_user_id=None, course_id=text_type(subsection_grade_model.course_id), usage_id=text_type(subsection_grade_model.usage_key), only_if_higher=False, expected_modified_time=to_timestamp(override.modified), score_deleted=False, event_transaction_id=six.text_type(get_event_transaction_id()), event_transaction_type=six.text_type(get_event_transaction_type()), score_db_table=grades_constants.ScoreDatabaseTableEnum.overrides, force_update_subsections=True, )) # Emit events to let our tracking system to know we updated subsection grade grades_events.subsection_grade_calculated(subsection_grade_model) return override
def _create_override(self, subsection_grade_model, **override_data): """ Helper method to create a `PersistentSubsectionGradeOverride` object and send a `SUBSECTION_OVERRIDE_CHANGED` signal. """ override, _ = PersistentSubsectionGradeOverride.objects.update_or_create( grade=subsection_grade_model, defaults=self._clean_override_data(override_data), ) set_event_transaction_type(SUBSECTION_GRADE_CALCULATED) create_new_event_transaction_id() recalculate_subsection_grade_v3.apply(kwargs=dict( user_id=subsection_grade_model.user_id, anonymous_user_id=None, course_id=text_type(subsection_grade_model.course_id), usage_id=text_type(subsection_grade_model.usage_key), only_if_higher=False, expected_modified_time=to_timestamp(override.modified), score_deleted=False, event_transaction_id=unicode(get_event_transaction_id()), event_transaction_type=unicode(get_event_transaction_type()), score_db_table=ScoreDatabaseTableEnum.overrides, force_update_subsections=True, )) # Emit events to let our tracking system to know we updated subsection grade subsection_grade_calculated(subsection_grade_model)
def _apply_recalculate_subsection_grade( self, mock_score=MagicMock(modified=datetime.utcnow().replace(tzinfo=pytz.UTC) + timedelta(days=1)) ): """ Calls the recalculate_subsection_grade task with necessary mocking in place. """ with self.mock_get_score(mock_score): recalculate_subsection_grade_v3.apply(kwargs=self.recalculate_subsection_grade_kwargs)
def _apply_recalculate_subsection_grade( self, mock_score=MagicMock(modified=datetime.utcnow().replace(tzinfo=pytz.UTC) + timedelta(days=1)) ): """ Calls the recalculate_subsection_grade task with necessary mocking in place. """ with self.mock_get_score(mock_score): recalculate_subsection_grade_v3.apply(kwargs=self.recalculate_subsection_grade_kwargs)
def _create_override(self, request_user, subsection_grade_model, **override_data): """ Helper method to create a `PersistentSubsectionGradeOverride` object and send a `SUBSECTION_OVERRIDE_CHANGED` signal. """ override, _ = PersistentSubsectionGradeOverride.objects.update_or_create( grade=subsection_grade_model, defaults=self._clean_override_data(override_data), ) _ = PersistentSubsectionGradeOverrideHistory.objects.create( override_id=override.id, user=request_user, feature=PersistentSubsectionGradeOverrideHistory.GRADEBOOK, action=PersistentSubsectionGradeOverrideHistory.CREATE_OR_UPDATE, ) set_event_transaction_type(SUBSECTION_GRADE_CALCULATED) create_new_event_transaction_id() recalculate_subsection_grade_v3.apply( kwargs=dict( user_id=subsection_grade_model.user_id, anonymous_user_id=None, course_id=text_type(subsection_grade_model.course_id), usage_id=text_type(subsection_grade_model.usage_key), only_if_higher=False, expected_modified_time=to_timestamp(override.modified), score_deleted=False, event_transaction_id=unicode(get_event_transaction_id()), event_transaction_type=unicode(get_event_transaction_type()), score_db_table=ScoreDatabaseTableEnum.overrides, force_update_subsections=True, ) ) # Emit events to let our tracking system to know we updated subsection grade subsection_grade_calculated(subsection_grade_model)