def setUpTestData(cls): cls.program, _ = create_program(past=True) cls.course_run = cls.program.course_set.first().courserun_set.first() cls.course = cls.course_run.course cls.program_enrollment = ProgramEnrollmentFactory.create( program=cls.program) cls.user = cls.program_enrollment.user with mute_signals(post_save): cls.final_grades = sorted( [ FinalGradeFactory.create(user=cls.user, course_run=cls.course_run, passed=False, status=FinalGradeStatus.PENDING), FinalGradeFactory.create(user=cls.user, course_run__course=cls.course, passed=True, status=FinalGradeStatus.COMPLETE), FinalGradeFactory.create(user=cls.user, course_run__course=cls.course, passed=True, status=FinalGradeStatus.COMPLETE), ], key=lambda final_grade: final_grade.course_run.end_date, reverse=True)
def test_count_courses_passed_normal(self): """ Assert that count_courses_passed works in case of normal program. """ mmtrack = MMTrack( user=self.user, program=self.program, edx_user_data=self.cached_edx_user_data ) assert mmtrack.count_courses_passed() == 0 course_run = self.cruns[0] FinalGradeFactory.create( user=self.user, course_run=course_run, passed=True ) assert mmtrack.count_courses_passed() == 1 course = CourseFactory.create(program=self.program) final_grade = FinalGradeFactory.create( user=self.user, course_run__course=course, passed=True ) mmtrack.edx_course_keys.add(final_grade.course_run.edx_course_key) assert mmtrack.count_courses_passed() == 2
def setUpTestData(cls): cls.program, _ = create_program(past=True) cls.course_run = cls.program.course_set.first().courserun_set.first() cls.course = cls.course_run.course cls.program_enrollment = ProgramEnrollmentFactory.create(program=cls.program) cls.user = cls.program_enrollment.user with mute_signals(post_save): cls.final_grades = sorted([ FinalGradeFactory.create( user=cls.user, course_run=cls.course_run, passed=False, status=FinalGradeStatus.PENDING ), FinalGradeFactory.create( user=cls.user, course_run__course=cls.course, passed=True, status=FinalGradeStatus.COMPLETE ), FinalGradeFactory.create( user=cls.user, course_run__course=cls.course, passed=True, status=FinalGradeStatus.COMPLETE ), ], key=lambda final_grade: final_grade.course_run.end_date, reverse=True)
def test_count_courses_mixed_fa(self): """ Test count_courses_passed with mixed course-exam configuration """ mmtrack = MMTrack( user=self.user, program=self.program_financial_aid, edx_user_data=self.cached_edx_user_data ) # this is course with exam run and the user has CombinedFinalGrade for it course_with_exam_1 = CourseFactory.create(program=self.program_financial_aid) ExamRunFactory.create(course=course_with_exam_1, date_grades_available=now_in_utc()-timedelta(weeks=1)) CombinedFinalGrade.objects.create(user=self.user, course=course_with_exam_1, grade=0.7) # create course with exam run the user did not pass ExamRunFactory.create( course__program=self.program_financial_aid, date_grades_available=now_in_utc() - timedelta(weeks=1) ) # another course with no exam FinalGradeFactory.create( user=self.user, course_run=self.crun_fa, passed=True ) assert mmtrack.count_courses_passed() == 2
def test_count_passing_courses_for_keys(self): """ Assert that count_courses_passed works in case of normal program. """ mmtrack = MMTrack( user=self.user, program=self.program, edx_user_data=self.cached_edx_user_data ) assert mmtrack.count_passing_courses_for_keys(mmtrack.edx_course_keys) == 0 for crun_index in [0, 1]: course_run = self.cruns[crun_index] FinalGradeFactory.create( user=self.user, course_run=course_run, passed=True ) assert mmtrack.count_passing_courses_for_keys(mmtrack.edx_course_keys) == 1 # now create a grade for another course final_grade = FinalGradeFactory.create( user=self.user, course_run__course__program=self.program, passed=True ) mmtrack.edx_course_keys.add(final_grade.course_run.edx_course_key) assert mmtrack.count_passing_courses_for_keys(mmtrack.edx_course_keys) == 2
def test_update_exam_authorization_final_grade(self): """ Verify that update_exam_authorization_final_grade is called when a FinalGrade saves """ create_order(self.profile.user, self.course_run) with mute_signals(post_save): # muted because enrollment also trigger signal for profile creation. right now we are just # looking final grades CachedEnrollmentFactory.create(user=self.profile.user, course_run=self.course_run) # There is no ExamProfile or ExamAuthorization before creating the FinalGrade. assert ExamProfile.objects.filter(profile=self.profile).exists() is False assert ExamAuthorization.objects.filter( user=self.profile.user, course=self.course_run.course ).exists() is False FinalGradeFactory.create( user=self.profile.user, course_run=self.course_run, passed=True, ) # assert Exam Authorization and profile created. assert ExamProfile.objects.filter(profile=self.profile).exists() is True assert ExamAuthorization.objects.filter( user=self.profile.user, course=self.course_run.course ).exists() is True
def test_combined_grade_created_updated(self): """ Test create and update """ combined_grade_qset = CombinedFinalGrade.objects.filter(user=self.user, course=self.course_run.course) # no passing final grade api.update_or_create_combined_final_grade(self.user, self.course_run.course) assert combined_grade_qset.exists() is False FinalGradeFactory.create(user=self.user, course_run__course=self.course_run.course, grade=0.6, passed=True) # no passing exam grade api.update_or_create_combined_final_grade(self.user, self.course_run.course) assert combined_grade_qset.exists() is False ProctoredExamGradeFactory.create( user=self.user, course=self.course_run.course, percentage_grade=0.8, passed=True, exam_run=self.exam_run ) # now should create combined grade api.update_or_create_combined_final_grade(self.user, self.course_run.course) assert combined_grade_qset.exists() is True # now update it with a new grade FinalGradeFactory.create(user=self.user, course_run__course=self.course_run.course, grade=0.8, passed=True) api.update_or_create_combined_final_grade(self.user, self.course_run.course) assert combined_grade_qset.first().grade == 80.0
def test_update_exam_authorization_final_grade(self): """ Verify that update_exam_authorization_final_grade is called when a FinalGrade saves """ create_order(self.profile.user, self.course_run) with mute_signals(post_save): # muted because enrollment also trigger signal for profile creation. right now we are just # looking final grades CachedEnrollmentFactory.create(user=self.profile.user, course_run=self.course_run) # There is no ExamProfile or ExamAuthorization before creating the FinalGrade. assert ExamProfile.objects.filter( profile=self.profile).exists() is False assert ExamAuthorization.objects.filter( user=self.profile.user, course=self.course_run.course).exists() is False FinalGradeFactory.create( user=self.profile.user, course_run=self.course_run, passed=True, ) # assert Exam Authorization and profile created. assert ExamProfile.objects.filter( profile=self.profile).exists() is True assert ExamAuthorization.objects.filter( user=self.profile.user, course=self.course_run.course).exists() is True
def test_update_exam_authorization_order(self, order_status): """ Verify that update_exam_authorization_final_grade is called when a fulfilled Order saves """ with mute_signals(post_save): # muted because enrollment also trigger signal for profile creation. right now we are just # looking final grades CachedEnrollmentFactory.create(user=self.profile.user, course_run=self.course_run) FinalGradeFactory.create( user=self.profile.user, course_run=self.course_run, passed=True, ) order = OrderFactory.create(user=self.profile.user, fulfilled=False) LineFactory.create(course_key=self.course_run.edx_course_key, order=order) # There is no ExamProfile or ExamAuthorization before creating the FinalGrade. assert ExamProfile.objects.filter(profile=self.profile).exists() is False assert ExamAuthorization.objects.filter( user=self.profile.user, course=self.course_run.course ).exists() is False order.status = order_status order.save() # assert Exam Authorization and profile created. assert ExamProfile.objects.filter(profile=self.profile).exists() is True assert ExamAuthorization.objects.filter( user=self.profile.user, course=self.course_run.course ).exists() is True
def test_update_exam_authorization_final_grade_when_user_not_paid(self): """ Verify that update_exam_authorization_final_grade is called and log exception when FinalGrade saves user dont match exam authorization criteria """ with mute_signals(post_save): # muting signal for CachedEnrollment. Because CachedEnrollment and FinalGrade both omits # signal, we want to see behaviour of FinalGrade here CachedEnrollmentFactory.create(user=self.profile.user, course_run=self.course_run) assert ExamProfile.objects.filter(profile=self.profile).exists() is False assert ExamAuthorization.objects.filter( user=self.profile.user, course=self.course_run.course ).exists() is False FinalGradeFactory.create( user=self.profile.user, course_run=self.course_run, passed=True, course_run_paid_on_edx=False, ) # assert Exam Authorization and profile not created. assert ExamProfile.objects.filter(profile=self.profile).exists() is False assert ExamAuthorization.objects.filter( user=self.profile.user, course=self.course_run.course ).exists() is False
def test_update_exam_authorization_final_grade_when_user_not_paid(self): """ Verify that update_exam_authorization_final_grade is called and log exception when FinalGrade saves user dont match exam authorization criteria """ with mute_signals(post_save): # muting signal for CachedEnrollment. Because CachedEnrollment and FinalGrade both omits # signal, we want to see behaviour of FinalGrade here CachedEnrollmentFactory.create(user=self.profile.user, course_run=self.course_run) assert ExamProfile.objects.filter( profile=self.profile).exists() is False assert ExamAuthorization.objects.filter( user=self.profile.user, course=self.course_run.course).exists() is False FinalGradeFactory.create( user=self.profile.user, course_run=self.course_run, passed=True, course_run_paid_on_edx=False, ) # assert Exam Authorization and profile not created. assert ExamProfile.objects.filter( profile=self.profile).exists() is False assert ExamAuthorization.objects.filter( user=self.profile.user, course=self.course_run.course).exists() is False
def test_create_final_grade_fa(self, generate_letter_mock, update_grade_mock, mock_on_commit): """ Test that final grades created for non-FA courses will try to update combined final grades. """ fa_course_run = CourseRunFactory.create(course__program__financial_aid_availability=True) FinalGradeFactory.create(user=self.user, course_run=fa_course_run, grade=0.9) update_grade_mock.assert_called_once_with(self.user, fa_course_run.course) generate_letter_mock.assert_not_called()
def test_course_final_grade_serialization(self): """ Tests that a user's final grades for a course run are properly serialized """ # Final grades should all be None since none have been created yet serialized_program_user = UserProgramSearchSerializer.serialize(self.fa_program_enrollment) assert all(enrollment['final_grade'] is None for enrollment in serialized_program_user['courses']) # Add some final grades and test that their values are properly serialized for enrollment in self.fa_enrollments: FinalGradeFactory.create(user=self.user, course_run=enrollment.course_run, grade=0.8, passed=True) serialized_program_user = UserProgramSearchSerializer.serialize(self.fa_program_enrollment) assert all(enrollment['final_grade'] == 80.0 for enrollment in serialized_program_user['courses'])
def test_create_final_grade_fa(self, generate_letter_mock, update_grade_mock, mock_on_commit): """ Test that final grades created for non-FA courses will try to update combined final grades. """ fa_course_run = CourseRunFactory.create( course__program__financial_aid_availability=True) FinalGradeFactory.create(user=self.user, course_run=fa_course_run, grade=0.9) update_grade_mock.assert_called_once_with(self.user, fa_course_run.course) generate_letter_mock.assert_not_called()
def test_final_grade_with_no_certificate(self): """ Test has a final grade but no certificate """ FinalGradeFactory.create( user=self.user, course_run=self.run_1, passed=True, status='complete', grade=0.8 ) CourseRunGradingStatus.objects.create(course_run=self.run_1, status='complete') cert_qset = MicromastersProgramCertificate.objects.filter(user=self.user, program=self.program) assert cert_qset.exists() is False api.generate_program_certificate(self.user, self.program) assert cert_qset.exists() is False
def test_get_overall_final_grade_for_course(self): """ Test for get_overall_final_grade_for_course to return CombinedFinalGrade for course """ mmtrack = MMTrack( user=self.user, program=self.program_financial_aid, edx_user_data=self.cached_edx_user_data ) finaid_course = self.crun_fa.course assert mmtrack.get_overall_final_grade_for_course(finaid_course) == "" FinalGradeFactory.create(user=self.user, course_run=self.crun_fa, passed=True, grade=0.8) assert mmtrack.get_overall_final_grade_for_course(finaid_course) == "80" ExamRunFactory.create(course=finaid_course) CombinedFinalGrade.objects.create(user=self.user, course=finaid_course, grade="74") assert mmtrack.get_overall_final_grade_for_course(finaid_course) == "74"
def test_successful_program_certificate_generation_with_electives(self): """ Test has final grade and a certificate with elective courses """ run_2 = CourseRunFactory.create( freeze_grade_date=now_in_utc() - timedelta(days=1), course__program=self.program, ) electives_set = ElectivesSet.objects.create(program=self.program, required_number=1) for run in [self.run_1, run_2]: final_grade = FinalGradeFactory.create( user=self.user, course_run=run, passed=True, status='complete', grade=0.7 ) CourseRunGradingStatus.objects.create(course_run=run, status='complete') ElectiveCourse.objects.create(course=run.course, electives_set=electives_set) with mute_signals(post_save): MicromastersCourseCertificate.objects.create(course=final_grade.course_run.course, user=self.user) cert_qset = MicromastersProgramCertificate.objects.filter(user=self.user, program=self.program) assert cert_qset.exists() is False api.generate_program_certificate(self.user, self.program) assert cert_qset.exists() is True
def test_has_paid_for_any_in_program(self): """ Assert that has_paid_for_any_in_program returns True if any CourseRun associated with a Program has been paid for. """ new_program = ProgramFactory.create() new_course_runs = CourseRunFactory.create_batch(2, course__program=new_program) mmtrack = MMTrack( user=self.user, program=new_program, edx_user_data=self.cached_edx_user_data ) assert mmtrack.has_paid_for_any_in_program() is False fg = FinalGradeFactory.create(user=self.user, course_run=new_course_runs[0], course_run_paid_on_edx=True) assert mmtrack.has_paid_for_any_in_program() is True fg.delete() FinalGradeFactory.create(user=self.user, course_run=new_course_runs[1], course_run_paid_on_edx=True) assert mmtrack.has_paid_for_any_in_program() is True
def test_with_fa_program(self): """ Test that letter won't be created if program is FA-enabled """ self.program.financial_aid_availability = True self.program.save() with mute_signals(post_save): FinalGradeFactory.create(user=self.user, course_run=self.run_1, passed=True, status='complete', grade=0.8) cert_qset = MicromastersProgramCommendation.objects.filter( user=self.user, program=self.program) assert cert_qset.exists() is False api.generate_program_letter(self.user, self.program) assert cert_qset.exists() is False
def test_successful_program_letter_generation(self): """ Test happy scenario """ self.program.financial_aid_availability = False self.program.save() with mute_signals(post_save): FinalGradeFactory.create(user=self.user, course_run=self.run_1, passed=True, status='complete', grade=0.8) cert_qset = MicromastersProgramCommendation.objects.filter( user=self.user, program=self.program) assert cert_qset.exists() is False api.generate_program_letter(self.user, self.program) assert cert_qset.exists() is True
def setUpTestData(cls): cls.user = SocialUserFactory.create() cls.course_run = CourseRunFactory.create( course__program__financial_aid_availability=True) cls.exam_run = ExamRunFactory.create( course=cls.course_run.course, date_grades_available=now_in_utc() - timedelta(weeks=1)) cls.not_passing_final_grade = FinalGradeFactory.create( user=cls.user, course_run=cls.course_run, grade=0.5, passed=False)
def test_successful_program_letter_generation(self): """ Test happy scenario """ self.program.financial_aid_availability = False self.program.save() with mute_signals(post_save): FinalGradeFactory.create( user=self.user, course_run=self.run_1, passed=True, status='complete', grade=0.8 ) cert_qset = MicromastersProgramCommendation.objects.filter(user=self.user, program=self.program) assert cert_qset.exists() is False api.generate_program_letter(self.user, self.program) assert cert_qset.exists() is True
def test_with_fa_program(self): """ Test that letter won't be created if program is FA-enabled """ self.program.financial_aid_availability = True self.program.save() with mute_signals(post_save): FinalGradeFactory.create( user=self.user, course_run=self.run_1, passed=True, status='complete', grade=0.8 ) cert_qset = MicromastersProgramCommendation.objects.filter(user=self.user, program=self.program) assert cert_qset.exists() is False api.generate_program_letter(self.user, self.program) assert cert_qset.exists() is False
def test_course_final_grade_serialization(self): """ Tests that a user's final grades for a course run are properly serialized """ # Final grades should all be None since none have been created yet serialized_program_user = UserProgramSearchSerializer.serialize( self.fa_program_enrollment) assert all(enrollment['final_grade'] is None for enrollment in serialized_program_user['courses']) # Add some final grades and test that their values are properly serialized for enrollment in self.fa_enrollments: FinalGradeFactory.create(user=self.user, course_run=enrollment.course_run, grade=0.8, passed=True) serialized_program_user = UserProgramSearchSerializer.serialize( self.fa_program_enrollment) assert all(enrollment['final_grade'] == 80.0 for enrollment in serialized_program_user['courses'])
def test_get_best_final_grade_for_course(self): """ Test for get_best_final_grade_for_course to return the highest grade over all course runs """ mmtrack = MMTrack( user=self.user, program=self.program_financial_aid, edx_user_data=self.cached_edx_user_data ) finaid_course = self.crun_fa.course FinalGradeFactory.create(user=self.user, course_run=self.crun_fa, grade=0.3, passed=False) assert mmtrack.get_best_final_grade_for_course(finaid_course) is None for grade in [0.3, 0.5, 0.8]: course_run = CourseRunFactory.create( course=finaid_course, ) FinalGradeFactory.create(user=self.user, course_run=course_run, grade=grade, passed=True) assert mmtrack.get_best_final_grade_for_course(finaid_course).grade == 0.8
def test_create_combined_final_grade(mocker): """ Test create_combined_final_grade creates the grade when it is missing """ update_mock = mocker.patch( 'grades.api.update_or_create_combined_final_grade', autospec=True) course_run = CourseRunFactory.create( freeze_grade_date=now_in_utc() - timedelta(days=1), course__program__financial_aid_availability=True, course__program__live=True) course = course_run.course CourseRunGradingStatus.objects.create(course_run=course_run, status='complete') # Create exam run for course with date_grades_available True exam_run_grades_available = ExamRunFactory.create( course=course, date_grades_available=now_in_utc() - timedelta(weeks=1)) exam_grades = ProctoredExamGradeFactory.create_batch( 5, course=course, exam_run=exam_run_grades_available, passed=True, ) for exam_grade in exam_grades[:3]: CombinedFinalGrade.objects.create(user=exam_grade.user, course=course, grade=0.7) # Only 3 users will have combined grades for exam_grade in exam_grades[3:]: FinalGradeFactory.create(user=exam_grade.user, course_run=course_run, passed=True) tasks.create_combined_final_grades.delay() assert update_mock.call_count == 2 update_mock.assert_has_calls( [call(exam_grades[3].user, course), call(exam_grades[4].user, course)], any_order=True)
def test_exam_authorization_for_inactive_user(self): """ test exam_authorization when inactive user passed and paid for course. """ with mute_signals(post_save): profile = ProfileFactory.create() user = profile.user user.is_active = False user.save() with mute_signals(post_save): CachedEnrollmentFactory.create(user=user, course_run=self.course_run) with mute_signals(post_save): FinalGradeFactory.create( user=user, course_run=self.course_run, passed=True, course_run_paid_on_edx=False, ) create_order(user, self.course_run) mmtrack = get_mmtrack(user, self.program) self.assertTrue(mmtrack.has_paid(self.course_run.edx_course_key)) self.assertTrue( mmtrack.has_passed_course(self.course_run.edx_course_key)) # Neither user has exam profile nor authorization. assert ExamProfile.objects.filter( profile=mmtrack.user.profile).exists() is False assert ExamAuthorization.objects.filter( user=mmtrack.user, course=self.course_run.course).exists() is False with self.assertRaises(ExamAuthorizationException): authorize_for_exam_run(self.user, self.course_run, self.exam_run) # Assert user doesn't have exam profile and authorization assert ExamProfile.objects.filter( profile=mmtrack.user.profile).exists() is False assert ExamAuthorization.objects.filter( user=mmtrack.user, course=self.course_run.course).exists() is False
def test_exam_authorization_for_inactive_user(self): """ test exam_authorization when inactive user passed and paid for course. """ with mute_signals(post_save): profile = ProfileFactory.create() user = profile.user user.is_active = False user.save() with mute_signals(post_save): CachedEnrollmentFactory.create(user=user, course_run=self.course_run) with mute_signals(post_save): FinalGradeFactory.create( user=user, course_run=self.course_run, passed=True, course_run_paid_on_edx=False, ) create_order(user, self.course_run) mmtrack = get_mmtrack(user, self.program) self.assertTrue(mmtrack.has_paid(self.course_run.edx_course_key)) self.assertTrue(mmtrack.has_passed_course(self.course_run.edx_course_key)) # Neither user has exam profile nor authorization. assert ExamProfile.objects.filter(profile=mmtrack.user.profile).exists() is False assert ExamAuthorization.objects.filter( user=mmtrack.user, course=self.course_run.course ).exists() is False with self.assertRaises(ExamAuthorizationException): authorize_for_exam_run(mmtrack, self.course_run, self.exam_run) # Assert user doesn't have exam profile and authorization assert ExamProfile.objects.filter(profile=mmtrack.user.profile).exists() is False assert ExamAuthorization.objects.filter( user=mmtrack.user, course=self.course_run.course ).exists() is False
def test_has_paid_final_grade(self, has_paid): """ Test that has_paid_final_grade returns True when the associated FinalGrade is paid """ final_grade = FinalGradeFactory.create(user=self.user, course_run=self.cruns[0], course_run_paid_on_edx=has_paid) mmtrack = MMTrack(user=self.user, program=self.program, edx_user_data=self.cached_edx_user_data) assert mmtrack.has_paid_final_grade( final_grade.course_run.edx_course_key) is has_paid
def test_has_final_grade(self): """ Test that has_final_grade returns True when a FinalGrade exists """ final_grade = FinalGradeFactory.create(user=self.user, course_run=self.cruns[0]) mmtrack = MMTrack(user=self.user, program=self.program, edx_user_data=self.cached_edx_user_data) assert mmtrack.has_final_grade( final_grade.course_run.edx_course_key) is True assert mmtrack.has_final_grade('random-course-id') is False
def test_has_passed_course(self, final_grade_passed): """ Test that has_passed_course returns True when a passed FinalGrade exists """ final_grade = FinalGradeFactory.create(user=self.user, course_run=self.cruns[0], passed=final_grade_passed) mmtrack = MMTrack(user=self.user, program=self.program, edx_user_data=self.cached_edx_user_data) assert mmtrack.has_passed_course( final_grade.course_run.edx_course_key) is final_grade_passed
def test_get_required_final_grade(self): """ Test that get_required_final_grade returns the FinalGrade associated with a user's course run """ final_grade = FinalGradeFactory.create( user=self.user, course_run=self.cruns[0], ) mmtrack = MMTrack(user=self.user, program=self.program, edx_user_data=self.cached_edx_user_data) assert mmtrack.get_required_final_grade( final_grade.course_run.edx_course_key) == final_grade
def test_get_required_final_grade(self): """ Test that get_required_final_grade returns the FinalGrade associated with a user's course run """ final_grade = FinalGradeFactory.create( user=self.user, course_run=self.cruns[0], ) mmtrack = MMTrack( user=self.user, program=self.program, edx_user_data=self.cached_edx_user_data ) assert mmtrack.get_required_final_grade(final_grade.course_run.edx_course_key) == final_grade
def test_get_final_grade_percent(self): """ Test that get_final_grade_percent returns a final grade in percent form """ final_grade = FinalGradeFactory.create(user=self.user, course_run=self.cruns[0], grade=0.57) mmtrack = MMTrack(user=self.user, program=self.program, edx_user_data=self.cached_edx_user_data) # calling round here because we do not want to add it in `get_final_grade` and let the frontend handle it assert round( mmtrack.get_final_grade_percent( final_grade.course_run.edx_course_key)) == 57.0
def setUpTestData(cls): cls.program, _ = create_program(past=True) cls.course_run = cls.program.course_set.first().courserun_set.first() cls.program_enrollment = ProgramEnrollmentFactory.create(program=cls.program) cls.user = cls.program_enrollment.user create_order(cls.user, cls.course_run) with mute_signals(post_save): CachedEnrollmentFactory.create(user=cls.user, course_run=cls.course_run) cls.final_grade = FinalGradeFactory.create( user=cls.user, course_run=cls.course_run, passed=True, course_run_paid_on_edx=False, )
def test_create_combined_final_grade(mocker): """ Test create_combined_final_grade creates the grade when it is missing """ update_mock = mocker.patch('grades.api.update_or_create_combined_final_grade', autospec=True) course_run = CourseRunFactory.create( freeze_grade_date=now_in_utc()-timedelta(days=1), course__program__financial_aid_availability=True, course__program__live=True ) course = course_run.course CourseRunGradingStatus.objects.create(course_run=course_run, status='complete') # Create exam run for course with date_grades_available True exam_run_grades_available = ExamRunFactory.create( course=course, date_grades_available=now_in_utc() - timedelta(weeks=1)) exam_grades = ProctoredExamGradeFactory.create_batch( 5, course=course, exam_run=exam_run_grades_available, passed=True, ) for exam_grade in exam_grades[:3]: CombinedFinalGrade.objects.create(user=exam_grade.user, course=course, grade=0.7) # Only 3 users will have combined grades for exam_grade in exam_grades[3:]: FinalGradeFactory.create(user=exam_grade.user, course_run=course_run, passed=True) tasks.create_combined_final_grades.delay() assert update_mock.call_count == 2 update_mock.assert_has_calls( [call(exam_grades[3].user, course), call(exam_grades[4].user, course)], any_order=True )
def test_has_final_grade(self): """ Test that has_final_grade returns True when a FinalGrade exists """ final_grade = FinalGradeFactory.create( user=self.user, course_run=self.cruns[0] ) mmtrack = MMTrack( user=self.user, program=self.program, edx_user_data=self.cached_edx_user_data ) assert mmtrack.has_final_grade(final_grade.course_run.edx_course_key) is True assert mmtrack.has_final_grade('random-course-id') is False
def test_update_exam_authorization_order(self, order_status): """ Verify that update_exam_authorization_final_grade is called when a fulfilled Order saves """ with mute_signals(post_save): # muted because enrollment also trigger signal for profile creation. right now we are just # looking final grades CachedEnrollmentFactory.create(user=self.profile.user, course_run=self.course_run) FinalGradeFactory.create( user=self.profile.user, course_run=self.course_run, passed=True, ) order = OrderFactory.create(user=self.profile.user, fulfilled=False) LineFactory.create(course_key=self.course_run.edx_course_key, order=order) # There is no ExamProfile or ExamAuthorization before creating the FinalGrade. assert ExamProfile.objects.filter( profile=self.profile).exists() is False assert ExamAuthorization.objects.filter( user=self.profile.user, course=self.course_run.course).exists() is False order.status = order_status order.save() # assert Exam Authorization and profile created. assert ExamProfile.objects.filter( profile=self.profile).exists() is True assert ExamAuthorization.objects.filter( user=self.profile.user, course=self.course_run.course).exists() is True
def test_has_passed_course(self, final_grade_passed): """ Test that has_passed_course returns True when a passed FinalGrade exists """ final_grade = FinalGradeFactory.create( user=self.user, course_run=self.cruns[0], passed=final_grade_passed ) mmtrack = MMTrack( user=self.user, program=self.program, edx_user_data=self.cached_edx_user_data ) assert mmtrack.has_passed_course(final_grade.course_run.edx_course_key) is final_grade_passed
def test_update_existing_combined_final_grade_for_exam_run(self, update_or_create_mock): """ Test update_existing_combined_final_grade_for_exam_run """ ProctoredExamGradeFactory.create( user=self.user, course=self.course_run.course, percentage_grade=0.6, passed=True, exam_run=self.exam_run ) FinalGradeFactory.create(user=self.user, course_run__course=self.course_run.course, grade=0.8, passed=True) # should only update if combined grade already exists for user api.update_existing_combined_final_grade_for_exam_run(self.exam_run) assert update_or_create_mock.called is False CombinedFinalGrade.objects.create(user=self.user, course=self.course_run.course, grade=0.7) # should call it once since there is an existing combined grade api.update_existing_combined_final_grade_for_exam_run(self.exam_run) update_or_create_mock.assert_called_once_with(self.user, self.course_run.course) exam_run = ExamRunFactory.create( course=self.course_run.course, date_grades_available=now_in_utc() - timedelta(weeks=1) ) ProctoredExamGradeFactory.create( user=self.user, course=self.course_run.course, percentage_grade=0.8, passed=True, exam_run=exam_run ) # should call it again for a different exam grade api.update_existing_combined_final_grade_for_exam_run(exam_run) assert update_or_create_mock.call_count == 2
def test_has_paid_final_grade(self, has_paid): """ Test that has_paid_final_grade returns True when the associated FinalGrade is paid """ final_grade = FinalGradeFactory.create( user=self.user, course_run=self.cruns[0], course_run_paid_on_edx=has_paid ) mmtrack = MMTrack( user=self.user, program=self.program, edx_user_data=self.cached_edx_user_data ) assert mmtrack.has_paid_final_grade(final_grade.course_run.edx_course_key) is has_paid
def test_get_final_grade_percent(self): """ Test that get_final_grade_percent returns a final grade in percent form """ final_grade = FinalGradeFactory.create( user=self.user, course_run=self.cruns[0], grade=0.57 ) mmtrack = MMTrack( user=self.user, program=self.program, edx_user_data=self.cached_edx_user_data ) # calling round here because we do not want to add it in `get_final_grade` and let the frontend handle it assert round(mmtrack.get_final_grade_percent(final_grade.course_run.edx_course_key)) == 57.0
def setUpTestData(cls): cls.user = SocialUserFactory.create() cls.course_run = CourseRunFactory.create( course__program__financial_aid_availability=True ) cls.exam_run = ExamRunFactory.create( course=cls.course_run.course, date_grades_available=now_in_utc() - timedelta(weeks=1) ) cls.not_passing_final_grade = FinalGradeFactory.create( user=cls.user, course_run=cls.course_run, grade=0.5, passed=False )
def test_has_paid_not_fa_with_final_grade(self): """ Assert that has_paid works for non-FA programs in case there is a final grade """ mmtrack = MMTrack( user=self.user, program=self.program, edx_user_data=self.cached_edx_user_data ) key = "course-v1:odl+FOO102+CR-FALL16" assert mmtrack.has_paid(key) is False course_run = self.cruns[-1] final_grade = FinalGradeFactory.create(user=self.user, course_run=course_run, course_run_paid_on_edx=True) assert mmtrack.has_paid(key) is True final_grade.course_run_paid_on_edx = False final_grade.save() assert mmtrack.has_paid(key) is False
def test_not_paid_fa_with_course_run_paid_on_edx(self): """ Test for has_paid is False for FA programs even in case there is a final grade with course_run_paid_on_edx=True """ mmtrack = MMTrack( user=self.user, program=self.program_financial_aid, edx_user_data=self.cached_edx_user_data ) key = self.crun_fa.edx_course_key assert mmtrack.has_paid(key) is False final_grade = FinalGradeFactory.create(user=self.user, course_run=self.crun_fa, course_run_paid_on_edx=True) assert mmtrack.has_paid(key) is False final_grade.course_run_paid_on_edx = False final_grade.save() assert mmtrack.has_paid(key) is False
def setUpTestData(cls): with mute_signals(post_save): profile = ProfileFactory.create() cls.program, _ = create_program(past=True) cls.user = profile.user cls.course_run = cls.program.course_set.first().courserun_set.first() with mute_signals(post_save): CachedEnrollmentFactory.create(user=cls.user, course_run=cls.course_run) cls.exam_run = ExamRunFactory.create(course=cls.course_run.course) with mute_signals(post_save): cls.final_grade = FinalGradeFactory.create( user=cls.user, course_run=cls.course_run, passed=True, course_run_paid_on_edx=False, )
def test_successful_program_certificate_generation(self): """ Test has final grade and a certificate """ final_grade = FinalGradeFactory.create( user=self.user, course_run=self.run_1, passed=True, status='complete', grade=0.8 ) CourseRunGradingStatus.objects.create(course_run=self.run_1, status='complete') with mute_signals(post_save): MicromastersCourseCertificate.objects.create(course=final_grade.course_run.course, user=self.user) cert_qset = MicromastersProgramCertificate.objects.filter(user=self.user, program=self.program) assert cert_qset.exists() is False api.generate_program_certificate(self.user, self.program) assert cert_qset.exists() is True
def setUpTestData(cls): with mute_signals(post_save): cls.profile = profile = ProfileFactory.create() cls.user = profile.user EducationFactory.create(profile=profile) EmploymentFactory.create(profile=profile) # create a normal program program = ProgramFactory.create() cls.enrollments = cls._generate_cached_enrollments(cls.user, program, num_course_runs=2) certificate_grades_vals = [0.7, 0.8] cls.current_grades_vals = [0.9, 1.0] cls.certificates = [] cls.current_grades = [] for i, enrollment in enumerate(cls.enrollments): cls.certificates.append( CachedCertificateFactory.create( user=cls.user, course_run=enrollment.course_run, data={ "grade": certificate_grades_vals[i], "certificate_type": "verified", "course_id": enrollment.course_run.edx_course_key, "status": "downloadable", } ) ) cls.current_grades.append( CachedCurrentGradeFactory.create( user=cls.user, course_run=enrollment.course_run, data={ "passed": True, "percent": cls.current_grades_vals[i], "course_key": enrollment.course_run.edx_course_key, } ) ) FinalGradeFactory.create( user=cls.user, course_run=enrollment.course_run, grade=certificate_grades_vals[i], passed=True, ) non_fa_cached_edx_data = CachedEdxUserData(cls.user, program=program) non_fa_mmtrack = MMTrack(cls.user, program, non_fa_cached_edx_data) cls.serialized_enrollments = UserProgramSearchSerializer.serialize_enrollments(non_fa_mmtrack) cls.serialized_course_enrollments = UserProgramSearchSerializer.serialize_course_enrollments(non_fa_mmtrack) cls.semester_enrollments = UserProgramSearchSerializer.serialize_course_runs_enrolled(non_fa_mmtrack) cls.program_enrollment = ProgramEnrollment.objects.create(user=cls.user, program=program) # create a financial aid program cls.fa_program, _ = create_program() cls.fa_program_enrollment = ProgramEnrollment.objects.create(user=cls.user, program=cls.fa_program) cls.fa_enrollments = cls._generate_cached_enrollments(cls.user, cls.fa_program, num_course_runs=2) cls.current_grades = [] for i, enrollment in enumerate(cls.fa_enrollments): order = OrderFactory.create(user=cls.user, status='fulfilled') LineFactory.create(order=order, course_key=enrollment.course_run.edx_course_key) cls.current_grades.append( CachedCurrentGradeFactory.create( user=cls.user, course_run=enrollment.course_run, data={ "passed": True, "percent": cls.current_grades_vals[i], "course_key": enrollment.course_run.edx_course_key, } ) ) FinalGradeFactory.create( user=cls.user, course_run=enrollment.course_run, grade=cls.current_grades_vals[i], passed=True, ) fa_cached_edx_data = CachedEdxUserData(cls.user, program=cls.fa_program) fa_mmtrack = MMTrack(cls.user, cls.fa_program, fa_cached_edx_data) cls.fa_serialized_course_enrollments = ( UserProgramSearchSerializer.serialize_course_enrollments(fa_mmtrack) ) cls.fa_serialized_enrollments = ( UserProgramSearchSerializer.serialize_enrollments(fa_mmtrack) )