예제 #1
0
    def test_get_best_proctored_exam_grade(self):
        """
        Test get_best_proctorate_exam_grade to return a passed exam with the highest score
        """
        mmtrack = MMTrack(
            user=self.user,
            program=self.program_financial_aid,
            edx_user_data=self.cached_edx_user_data
        )
        finaid_course = self.crun_fa.course
        last_week = now_in_utc() - timedelta(weeks=1)

        ProctoredExamGradeFactory.create(user=self.user, course=finaid_course, passed=False, percentage_grade=0.6)
        assert mmtrack.get_best_proctored_exam_grade(finaid_course) is None
        best_exam = ProctoredExamGradeFactory.create(
            user=self.user, course=finaid_course, passed=True, percentage_grade=0.9,
            exam_run__date_grades_available=last_week
        )
        assert mmtrack.get_best_proctored_exam_grade(finaid_course) == best_exam

        ProctoredExamGradeFactory.create(
            user=self.user, course=finaid_course, passed=True, percentage_grade=0.8,
            exam_run__date_grades_available=last_week
        )
        assert mmtrack.get_best_proctored_exam_grade(finaid_course) == best_exam
예제 #2
0
    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
예제 #3
0
    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
예제 #4
0
    def test_get_best_proctored_exam_grade(self):
        """
        Test get_best_proctorate_exam_grade to return a passed exam with the highest score
        """
        mmtrack = MMTrack(
            user=self.user,
            program=self.program_financial_aid,
            edx_user_data=self.cached_edx_user_data
        )
        finaid_course = self.crun_fa.course
        last_week = now_in_utc() - timedelta(weeks=1)

        ProctoredExamGradeFactory.create(user=self.user, course=finaid_course, passed=False, percentage_grade=0.6)
        assert mmtrack.get_best_proctored_exam_grade(finaid_course) is None
        best_exam = ProctoredExamGradeFactory.create(
            user=self.user, course=finaid_course, passed=True, percentage_grade=0.9,
            exam_run__date_grades_available=last_week
        )
        assert mmtrack.get_best_proctored_exam_grade(finaid_course) == best_exam

        ProctoredExamGradeFactory.create(
            user=self.user, course=finaid_course, passed=True, percentage_grade=0.8,
            exam_run__date_grades_available=last_week
        )
        assert mmtrack.get_best_proctored_exam_grade(finaid_course) == best_exam
예제 #5
0
 def test_create_exam_grade(self, update_grade_mock, mock_on_commit):
     """
     Test that update_or_create_combined_final_grade is called when a proctored exam
     grade is created or updated
     """
     exam_grade = ProctoredExamGradeFactory.create(user=self.user, course=self.course)
     update_grade_mock.assert_called_once_with(self.user, self.course)
     exam_grade.save()
     assert update_grade_mock.call_count == 2
     # create another exam grade for a different exam run
     ProctoredExamGradeFactory.create(user=self.user, course=self.course)
     assert update_grade_mock.call_count == 3
예제 #6
0
 def test_create_exam_grade(self, update_grade_mock, mock_on_commit):
     """
     Test that update_or_create_combined_final_grade is called when a proctored exam
     grade is created or updated
     """
     exam_grade = ProctoredExamGradeFactory.create(user=self.user,
                                                   course=self.course)
     update_grade_mock.assert_called_once_with(self.user, self.course)
     exam_grade.save()
     assert update_grade_mock.call_count == 2
     # create another exam grade for a different exam run
     ProctoredExamGradeFactory.create(user=self.user, course=self.course)
     assert update_grade_mock.call_count == 3
예제 #7
0
    def setUpTestData(cls):
        cls.proct_grade = ProctoredExamGradeFactory()
        cls.proct_grade_2 = ProctoredExamGradeFactory(
            user=cls.proct_grade.user, course=cls.proct_grade.course)

        cls.expected_fields = sorted([
            'exam_date',
            'passing_score',
            'score',
            'grade',
            'client_authorization_id',
            'passed',
            'percentage_grade',
        ])
예제 #8
0
    def test_for_user_course(self):
        """Tests that for_user_course() does not return unavailable grades"""
        user = UserFactory.create()
        course = CourseFactory.create()
        available_grade = ProctoredExamGradeFactory.create(
            user=user,
            course=course,
            exam_run__course=course,
            exam_run__eligibility_past=True)
        ProctoredExamGradeFactory.create(user=user,
                                         course=course,
                                         exam_run__course=course,
                                         exam_run__eligibility_future=True)
        grades = ProctoredExamGrade.for_user_course(user, course)

        assert list(grades) == [available_grade]
예제 #9
0
 def test_create_exam_grade(self, update_grade_mock, mock_on_commit):
     """
     Test that update_existing_combined_final_grade_for_exam_run is called when a proctored exam
     grade is created and ExamRun updated
     """
     exam_grade = ProctoredExamGradeFactory.create(user=self.user,
                                                   course=self.course)
     assert update_grade_mock.call_count == 0
     exam_grade.exam_run.save()
     assert update_grade_mock.call_count == 1
     # create another exam grade for a different exam run
     exam_grade = ProctoredExamGradeFactory.create(user=self.user,
                                                   course=self.course)
     assert update_grade_mock.call_count == 1
     exam_grade.exam_run.save()
     assert update_grade_mock.call_count == 2
예제 #10
0
    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
예제 #11
0
 def test_set_score(self, grade_adjust, expected_passed_value,
                    expected_grade_str):
     """Tests that the set_score helper method sets score-related fields appropriately"""
     passing_score = 60.0
     grade = ProctoredExamGradeFactory.build(
         passing_score=passing_score,
         score=None,
         percentage_grade=None,
         passed=None,
     )
     grade.set_score(passing_score + grade_adjust)
     assert grade.score == passing_score + grade_adjust
     assert grade.percentage_grade == grade.score / 100.0
     assert grade.passed == expected_passed_value
     assert grade.grade == expected_grade_str
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)
예제 #13
0
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
    )
예제 #14
0
    def create_exams(self, current, edx_passed, exam_passed, new_offering, can_schedule, future_exam, need_to_pay):
        """Create an exam and mark it and the related course as passed or not passed"""
        # pylint: disable-msg=too-many-arguments
        self.make_fa_program_enrollment(FinancialAidStatus.AUTO_APPROVED)
        course = Course.objects.get(title='Digital Learning 200')
        if current:
            course_run = CourseRunFactory(course=course)
            call_command(
                "alter_data", 'set_to_enrolled', '--username', 'staff',
                '--course-run-key', course_run.edx_course_key
            )
            FinalGradeFactory.create(
                user=self.user, course_run=course_run, grade=0.8 if edx_passed else 0.2, passed=True
            )
        else:
            if edx_passed:
                call_command(
                    "alter_data", 'set_to_passed', '--username', 'staff',
                    '--course-title', 'Digital Learning 200', '--grade', '75',
                )
            else:
                call_command(
                    "alter_data", 'set_to_failed', '--username', 'staff',
                    '--course-title', 'Digital Learning 200', '--grade', '45',
                )
            course_run = course.courserun_set.first()

        ExamProfileFactory.create(status='success', profile=self.user.profile)
        exam_run = ExamRunFactory.create(course=course, eligibility_past=True, scheduling_past=True)
        ExamAuthorizationFactory.create(
            user=self.user, course=course, exam_run=exam_run, status='success', exam_taken=True
        )
        LineFactory.create(
            order__status=Order.FULFILLED,
            course_key=course_run
        )

        ProctoredExamGradeFactory.create(
            user=self.user,
            course=course,
            exam_run=exam_run,
            passed=exam_passed,
            percentage_grade=0.8 if exam_passed else 0.3
        )
        if new_offering:
            CourseRunFactory.create(course=course)

        if can_schedule:
            exam_run = ExamRunFactory.create(
                scheduling_past=False,
                scheduling_future=False,
                authorized=True,
                course=course
            )
            ExamAuthorizationFactory.create(
                user=self.user, course=course, exam_run=exam_run, status='success',
            )

        if future_exam:
            ExamRunFactory.create(
                scheduling_past=False,
                scheduling_future=True,
                authorized=True,
                course=course
            )
        if need_to_pay:
            exam_run = ExamRunFactory.create(course=course, eligibility_past=True, scheduling_past=True)
            ExamAuthorizationFactory.create(
                user=self.user, course=course, exam_run=exam_run, status='success', exam_taken=True
            )
            ProctoredExamGradeFactory.create(
                user=self.user,
                course=course,
                exam_run=exam_run,
                passed=False,
                percentage_grade=0.3
            )
예제 #15
0
 def test_set_score_none(self):
     """Tests that set_score fails if the provided score is None"""
     grade = ProctoredExamGradeFactory.build()
     with self.assertRaises(TypeError):
         grade.set_score(None)
def test_generate_course_certificates():
    """
    Test that generate_course_certificates_for_fa_students creates certificates for appropriate FinalGrades
    """
    program = ProgramFactory.create(financial_aid_availability=True, live=True)
    week_ago = now_in_utc() - timedelta(weeks=1)
    # Course without exams
    course = CourseFactory.create(program=program)
    passed_final_grades = FinalGradeFactory.create_batch(
        4,
        course_run__course=course,
        course_run__freeze_grade_date=week_ago,
        passed=True
    )
    # create a duplicate final grade for course for user
    FinalGradeFactory.create(
        user=passed_final_grades[0].user,
        course_run__course=course,
        course_run__freeze_grade_date=week_ago,
        passed=True
    )
    # 2nd course for user
    course_2 = CourseFactory.create(program=program)
    FinalGradeFactory.create(
        course_run__course=course_2,
        course_run__freeze_grade_date=week_ago,
        passed=True,
        user=passed_final_grades[1].user
    )

    # Another non-fa course
    non_fa_course = CourseFactory.create(program__financial_aid_availability=False)

    # Course with exams
    # Create two exam runs for course with different date_grades_available
    exam_run_grades_available = ExamRunFactory.create(
        course__program=program,
        date_grades_available=now_in_utc() - timedelta(weeks=1))
    course_with_exams = exam_run_grades_available.course
    exam_run_no_grades = ExamRunFactory.create(
        course=course_with_exams,
        date_grades_available=now_in_utc() + timedelta(weeks=1))
    passed_final_grades_with_exam = FinalGradeFactory.create_batch(
        6,
        course_run__course=course_with_exams,
        passed=True
    )

    # Create ProctoredExamGrade records with a mix of passed and failed outcomes, and exam grade availability
    final_grades_with_passed_exam = passed_final_grades_with_exam[:2]

    ProctoredExamGradeFactory.create_batch(
        2,
        user=factory.Iterator([final_grade.user for final_grade in final_grades_with_passed_exam]),
        course=course_with_exams,
        exam_run=exam_run_grades_available,
        passed=True,
    )
    ProctoredExamGradeFactory.create_batch(
        2,
        user=factory.Iterator([final_grade.user for final_grade in passed_final_grades_with_exam[2:4]]),
        course=course_with_exams,
        exam_run=exam_run_no_grades,
        passed=True,
    )
    ProctoredExamGradeFactory.create_batch(
        2,
        user=factory.Iterator([final_grade.user for final_grade in passed_final_grades_with_exam[4:6]]),
        course=course_with_exams,
        passed=False,
    )
    # course runs need to have CourseRunGradingStatus to get certificates
    all_grades = FinalGrade.objects.filter(course_run__course__in=[course, course_2, course_with_exams, non_fa_course])
    for final_grade in all_grades:
        CourseRunGradingStatus.objects.create(course_run=final_grade.course_run, status='complete')
    tasks.generate_course_certificates_for_fa_students.delay()

    # Make sure that certificates were created only for passed and 'complete' status FinalGrades that either
    # had no course exam, or had a passed ProctoredExamGrade.
    certificates = MicromastersCourseCertificate.objects.filter(course__in=[course, course_2, course_with_exams])
    assert certificates.count() == 7
    expected_certificate_final_grades = passed_final_grades + final_grades_with_passed_exam
    assert set(certificates.values_list('user', flat=True)) == {
        final_grade.user.id for final_grade in expected_certificate_final_grades
    }
예제 #17
0
def test_generate_course_certificates():
    """
    Test that generate_course_certificates_for_fa_students creates certificates for appropriate FinalGrades
    """
    program = ProgramFactory.create(financial_aid_availability=True, live=True)
    week_ago = now_in_utc() - timedelta(weeks=1)
    # Course without exams
    course = CourseFactory.create(program=program)
    passed_final_grades = FinalGradeFactory.create_batch(
        4,
        course_run__course=course,
        course_run__freeze_grade_date=week_ago,
        passed=True
    )
    # create a duplicate final grade for course for user
    FinalGradeFactory.create(
        user=passed_final_grades[0].user,
        course_run__course=course,
        course_run__freeze_grade_date=week_ago,
        passed=True
    )
    # 2nd course for user
    course_2 = CourseFactory.create(program=program)
    FinalGradeFactory.create(
        course_run__course=course_2,
        course_run__freeze_grade_date=week_ago,
        passed=True,
        user=passed_final_grades[1].user
    )

    # Another non-fa course
    non_fa_course = CourseFactory.create(program__financial_aid_availability=False)

    # Course with exams
    # Create two exam runs for course with different date_grades_available
    exam_run_grades_available = ExamRunFactory.create(
        course__program=program,
        date_grades_available=now_in_utc() - timedelta(weeks=1))
    course_with_exams = exam_run_grades_available.course
    exam_run_no_grades = ExamRunFactory.create(
        course=course_with_exams,
        date_grades_available=now_in_utc() + timedelta(weeks=1))
    passed_final_grades_with_exam = FinalGradeFactory.create_batch(
        6,
        course_run__course=course_with_exams,
        passed=True
    )

    # Create ProctoredExamGrade records with a mix of passed and failed outcomes, and exam grade availability
    final_grades_with_passed_exam = passed_final_grades_with_exam[:2]

    ProctoredExamGradeFactory.create_batch(
        2,
        user=factory.Iterator([final_grade.user for final_grade in final_grades_with_passed_exam]),
        course=course_with_exams,
        exam_run=exam_run_grades_available,
        passed=True,
    )
    ProctoredExamGradeFactory.create_batch(
        2,
        user=factory.Iterator([final_grade.user for final_grade in passed_final_grades_with_exam[2:4]]),
        course=course_with_exams,
        exam_run=exam_run_no_grades,
        passed=True,
    )
    ProctoredExamGradeFactory.create_batch(
        2,
        user=factory.Iterator([final_grade.user for final_grade in passed_final_grades_with_exam[4:6]]),
        course=course_with_exams,
        passed=False,
    )
    # course runs need to have CourseRunGradingStatus to get certificates
    all_grades = FinalGrade.objects.filter(course_run__course__in=[course, course_2, course_with_exams, non_fa_course])
    for final_grade in all_grades:
        CourseRunGradingStatus.objects.create(course_run=final_grade.course_run, status='complete')
    tasks.generate_course_certificates_for_fa_students.delay()

    # Make sure that certificates were created only for passed and 'complete' status FinalGrades that either
    # had no course exam, or had a passed ProctoredExamGrade.
    certificates = MicromastersCourseCertificate.objects.filter(course__in=[course, course_2, course_with_exams])
    assert certificates.count() == 7
    expected_certificate_final_grades = passed_final_grades + final_grades_with_passed_exam
    assert set(certificates.values_list('user', flat=True)) == set(
        [final_grade.user.id for final_grade in expected_certificate_final_grades]
    )