def test_program_prereq_course_scores(mocker, user_application, percent, courses): """ Test that the `program_prereq_course_scores` property returns the correct program prerequisite course names and respective scores of the applicant in those courses, in the correct format. """ mocker.patch('lms.djangoapps.grades.models.emit_course_progress_event') test_course_1 = courses['test_course1'] test_course_2 = courses['test_course2'] for course in courses.values(): PersistentCourseGrade.update_or_create( user_id=user_application.user_id, course_id=course.id, percent_grade=percent, passed=True) MultilingualCourseFactory(course=test_course_1) bu_prereq_course = MultilingualCourseGroupFactory( is_program_prerequisite=False, is_common_business_line_prerequisite=True) MultilingualCourseFactory(course=test_course_2, multilingual_course_group=bu_prereq_course) score = int(round_away_from_zero(percent * 100)) course_score_1 = CourseScore(test_course_1.display_name, score) expected_prereq_course_scores = [course_score_1] actual_prereq_course_scores = user_application.program_prereq_course_scores assert expected_prereq_course_scores == actual_prereq_course_scores
def test_update(self): created_grade = PersistentCourseGrade.update_or_create(**self.params) self.params["percent_grade"] = 88.8 self.params["letter_grade"] = "Better job" updated_grade = PersistentCourseGrade.update_or_create(**self.params) assert updated_grade.percent_grade == 88.8 assert updated_grade.letter_grade == 'Better job' assert created_grade.id == updated_grade.id
def test_update(self): created_grade = PersistentCourseGrade.update_or_create_course_grade(**self.params) self.params["percent_grade"] = 88.8 self.params["letter_grade"] = "Better job" updated_grade = PersistentCourseGrade.update_or_create_course_grade(**self.params) self.assertEqual(updated_grade.percent_grade, 88.8) self.assertEqual(updated_grade.letter_grade, "Better job") self.assertEqual(created_grade.id, updated_grade.id)
def test_update(self): created_grade = PersistentCourseGrade.update_or_create(**self.params) self.params["percent_grade"] = 88.8 self.params["letter_grade"] = "Better job" updated_grade = PersistentCourseGrade.update_or_create(**self.params) self.assertEqual(updated_grade.percent_grade, 88.8) self.assertEqual(updated_grade.letter_grade, "Better job") self.assertEqual(created_grade.id, updated_grade.id)
def __init__(self, context, users): self.certs = _CertificateBulkContext(context, users) self.teams = _TeamBulkContext(context, users) self.enrollments = _EnrollmentBulkContext(context, users) bulk_cache_cohorts(context.course_id, users) BulkRoleCache.prefetch(users) PersistentCourseGrade.prefetch(context.course_id, users) BulkCourseTags.prefetch(context.course_id, users)
def test_dashboard_view_context_data(user_with_profile, courses, webinar, mocker, request): """ Test dashboard page context data """ mocker.patch( 'openedx.adg.lms.student.views.DashboardView.get_filtered_enrolled_courses' ) mocker.patch('openedx.adg.lms.student.views.get_course_by_id', return_value=courses['test_course1']) mocker.patch('openedx.adg.lms.student.views.reverse', return_value='/account/settings') dashboard_request = request user_with_profile.is_active = False dashboard_request.user = user_with_profile CourseEnrollment.enroll(user=user_with_profile, course_key=courses['test_course1'].id) CourseEnrollment.enroll(user=user_with_profile, course_key=courses['test_course2'].id) PersistentCourseGrade.update_or_create( user_id=user_with_profile.id, course_id=courses['test_course1'].id, percent_grade=0.8, passed=True) WebinarRegistrationFactory(email=user_with_profile.email, webinar=webinar, is_registered=True) GeneratedCertificateFactory(user=user_with_profile, course_id=courses['test_course1'].id, status=CertificateStatuses.downloadable) context_data = DashboardView(request=dashboard_request).get_context_data() assert 'user' in context_data assert 'user_profile' in context_data assert 'profile_image_url' in context_data assert 'edit_account_link' in context_data assert 'application_link' in context_data assert 'courses' in context_data assert 'courses_filter_options' in context_data assert 'courses_filter' in context_data assert 'webinars' in context_data assert 'webinars_filter_options' in context_data assert 'webinars_filter' in context_data assert 'certificates' in context_data assert 'activate_account_message' in context_data assert 'account_activation_messages' in context_data assert context_data[ 'profile_image_url'] == get_profile_image_urls_for_user( user_with_profile)['full'] assert context_data['edit_account_link'] == '/account/settings' assert context_data['user'] == user_with_profile assert len(context_data['webinars']) == 1
def test_persistent_grades_not_enabled_on_course(self, default_store, num_mongo_queries, num_sql_queries): with self.store.default_store(default_store): self.set_up_course(enable_persistent_grades=False) with check_mongo_calls(num_mongo_queries): with self.assertNumQueries(num_sql_queries): self._apply_recalculate_subsection_grade() with self.assertRaises(PersistentCourseGrade.DoesNotExist): PersistentCourseGrade.read(self.user.id, self.course.id) self.assertEqual(len(PersistentSubsectionGrade.bulk_read_grades(self.user.id, self.course.id)), 0)
def test_create_and_read_grade(self): created_grade = PersistentCourseGrade.update_or_create(**self.params) read_grade = PersistentCourseGrade.read(self.params["user_id"], self.params["course_id"]) for param in self.params: if param == 'passed': continue # passed/passed_timestamp takes special handling, and is tested separately assert self.params[param] == getattr(created_grade, param) assert isinstance(created_grade.passed_timestamp, datetime) assert created_grade == read_grade
def bulk_course_grade_context(course_key, users): """ Prefetches grades for the given users in the given course within a context, storing in a RequestCache and deleting on context exit. """ PersistentCourseGrade.prefetch(course_key, users) yield PersistentCourseGrade.clear_prefetched_data(course_key)
def bulk_course_grade_context(course_key, users): """ Prefetches grades for the given users in the given course within a context, storing in a RequestCache and deleting on context exit. """ PersistentCourseGrade.prefetch(course_key, users) yield PersistentCourseGrade.clear_prefetched_data(course_key)
def test_create_and_read_grade(self): created_grade = PersistentCourseGrade.update_or_create_course_grade(**self.params) read_grade = PersistentCourseGrade.read_course_grade(self.params["user_id"], self.params["course_id"]) for param in self.params: if param == u'passed': continue # passed/passed_timestamp takes special handling, and is tested separately self.assertEqual(self.params[param], getattr(created_grade, param)) self.assertIsInstance(created_grade.passed_timestamp, datetime) self.assertEqual(created_grade, read_grade)
def test_persistent_grades_not_enabled_on_course(self, default_store, num_mongo_queries, num_sql_queries): with self.store.default_store(default_store): self.set_up_course(enable_persistent_grades=False) with check_mongo_calls(num_mongo_queries): with self.assertNumQueries(num_sql_queries): self._apply_recalculate_subsection_grade() with self.assertRaises(PersistentCourseGrade.DoesNotExist): PersistentCourseGrade.read(self.user.id, self.course.id) self.assertEqual(len(PersistentSubsectionGrade.bulk_read_grades(self.user.id, self.course.id)), 0)
def _assert_grades_absent_for_courses(self, course_keys): """ Assert grades for given courses do not exist. """ for course_key in course_keys: with self.assertRaises(PersistentCourseGrade.DoesNotExist): PersistentCourseGrade.read_course_grade(self.user_ids[0], course_key) for subsection_key in self.subsection_keys_by_course[course_key]: with self.assertRaises(PersistentSubsectionGrade.DoesNotExist): PersistentSubsectionGrade.read_grade(self.user_ids[0], subsection_key)
def _assert_grades_absent_for_courses(self, course_keys, db_table=None): """ Assert grades for given courses do not exist. """ for course_key in course_keys: if db_table == "course" or db_table is None: with self.assertRaises(PersistentCourseGrade.DoesNotExist): PersistentCourseGrade.read(self.user_ids[0], course_key) if db_table == "subsection" or db_table is None: for subsection_key in self.subsection_keys_by_course[course_key]: with self.assertRaises(PersistentSubsectionGrade.DoesNotExist): PersistentSubsectionGrade.read_grade(self.user_ids[0], subsection_key)
def _assert_grades_absent_for_courses(self, course_keys, db_table=None): """ Assert grades for given courses do not exist. """ for course_key in course_keys: if db_table == "course" or db_table is None: with self.assertRaises(PersistentCourseGrade.DoesNotExist): PersistentCourseGrade.read_course_grade(self.user_ids[0], course_key) if db_table == "subsection" or db_table is None: for subsection_key in self.subsection_keys_by_course[course_key]: with self.assertRaises(PersistentSubsectionGrade.DoesNotExist): PersistentSubsectionGrade.read_grade(self.user_ids[0], subsection_key)
def bulk_gradebook_view_context(course_key, users): """ Prefetches all course and subsection grades in the given course for the given list of users, also, fetch all the score relavant data, storing the result in a RequestCache and deleting grades on context exit. """ PersistentSubsectionGrade.prefetch(course_key, users) PersistentCourseGrade.prefetch(course_key, users) CourseEnrollment.bulk_fetch_enrollment_states(users, course_key) cohorts.bulk_cache_cohorts(course_key, users) BulkRoleCache.prefetch(users) yield PersistentSubsectionGrade.clear_prefetched_data(course_key) PersistentCourseGrade.clear_prefetched_data(course_key)
def bulk_gradebook_view_context(course_key, users): """ Prefetches all course and subsection grades in the given course for the given list of users, also, fetch all the score relavant data, storing the result in a RequestCache and deleting grades on context exit. """ PersistentSubsectionGrade.prefetch(course_key, users) PersistentCourseGrade.prefetch(course_key, users) CourseEnrollment.bulk_fetch_enrollment_states(users, course_key) cohorts.bulk_cache_cohorts(course_key, users) BulkRoleCache.prefetch(users) yield PersistentSubsectionGrade.clear_prefetched_data(course_key) PersistentCourseGrade.clear_prefetched_data(course_key)
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)
def test_persistent_grades_enabled_on_course(self, default_store, num_mongo_queries, num_sql_queries): with self.store.default_store(default_store): self.set_up_course(enable_persistent_grades=True) with check_mongo_calls(num_mongo_queries): with self.assertNumQueries(num_sql_queries): self._apply_recalculate_subsection_grade() self.assertIsNotNone(PersistentCourseGrade.read(self.user.id, self.course.id)) self.assertGreater(len(PersistentSubsectionGrade.bulk_read_grades(self.user.id, self.course.id)), 0)
def _assert_grades_exist_for_courses(self, course_keys): """ Assert grades for given courses exist. """ for course_key in course_keys: self.assertIsNotNone(PersistentCourseGrade.read_course_grade(self.user_ids[0], course_key)) for subsection_key in self.subsection_keys_by_course[course_key]: self.assertIsNotNone(PersistentSubsectionGrade.read_grade(self.user_ids[0], subsection_key))
def test_persistent_grades_enabled_on_course(self, default_store, num_mongo_queries, num_sql_queries): with self.store.default_store(default_store): self.set_up_course(enable_persistent_grades=True) with check_mongo_calls(num_mongo_queries): with self.assertNumQueries(num_sql_queries): self._apply_recalculate_subsection_grade() self.assertIsNotNone(PersistentCourseGrade.read(self.user.id, self.course.id)) self.assertGreater(len(PersistentSubsectionGrade.bulk_read_grades(self.user.id, self.course.id)), 0)
def test_passed_timestamp(self): # When the user has not passed, passed_timestamp is None self.params.update({ u'percent_grade': 25.0, u'letter_grade': u'', u'passed': False, }) grade = PersistentCourseGrade.update_or_create_course_grade( **self.params) self.assertIsNone(grade.passed_timestamp) # After the user earns a passing grade, the passed_timestamp is set self.params.update({ u'percent_grade': 75.0, u'letter_grade': u'C', u'passed': True, }) grade = PersistentCourseGrade.update_or_create_course_grade( **self.params) passed_timestamp = grade.passed_timestamp self.assertEqual(grade.letter_grade, u'C') self.assertIsInstance(passed_timestamp, datetime) # After the user improves their score, the new grade is reflected, but # the passed_timestamp remains the same. self.params.update({ u'percent_grade': 95.0, u'letter_grade': u'A', u'passed': True, }) grade = PersistentCourseGrade.update_or_create_course_grade( **self.params) self.assertEqual(grade.letter_grade, u'A') self.assertEqual(grade.passed_timestamp, passed_timestamp) # If the grade later reverts to a failing grade, they keep their passed_timestamp self.params.update({ u'percent_grade': 20.0, u'letter_grade': u'', u'passed': False, }) grade = PersistentCourseGrade.update_or_create_course_grade( **self.params) self.assertEqual(grade.letter_grade, u'') self.assertEqual(grade.passed_timestamp, passed_timestamp)
def _assert_grades_exist_for_courses(self, course_keys, db_table=None): """ Assert grades for given courses exist. """ for course_key in course_keys: if db_table == "course" or db_table is None: self.assertIsNotNone(PersistentCourseGrade.read_course_grade(self.user_ids[0], course_key)) if db_table == "subsection" or db_table is None: for subsection_key in self.subsection_keys_by_course[course_key]: self.assertIsNotNone(PersistentSubsectionGrade.read_grade(self.user_ids[0], subsection_key))
def _assert_grades_exist_for_courses(self, course_keys, db_table=None): """ Assert grades for given courses exist. """ for course_key in course_keys: if db_table == "course" or db_table is None: self.assertIsNotNone(PersistentCourseGrade.read(self.user_ids[0], course_key)) if db_table == "subsection" or db_table is None: for subsection_key in self.subsection_keys_by_course[course_key]: self.assertIsNotNone(PersistentSubsectionGrade.read_grade(self.user_ids[0], subsection_key))
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)
def test_passed_timestamp(self): # When the user has not passed, passed_timestamp is None self.params.update({ 'percent_grade': 25.0, 'letter_grade': '', 'passed': False, }) grade = PersistentCourseGrade.update_or_create(**self.params) assert grade.passed_timestamp is None # After the user earns a passing grade, the passed_timestamp is set self.params.update({ 'percent_grade': 75.0, 'letter_grade': 'C', 'passed': True, }) grade = PersistentCourseGrade.update_or_create(**self.params) passed_timestamp = grade.passed_timestamp assert grade.letter_grade == 'C' assert isinstance(passed_timestamp, datetime) # After the user improves their score, the new grade is reflected, but # the passed_timestamp remains the same. self.params.update({ 'percent_grade': 95.0, 'letter_grade': 'A', 'passed': True, }) grade = PersistentCourseGrade.update_or_create(**self.params) assert grade.letter_grade == 'A' assert grade.passed_timestamp == passed_timestamp # If the grade later reverts to a failing grade, passed_timestamp remains the same. self.params.update({ 'percent_grade': 20.0, 'letter_grade': '', 'passed': False, }) grade = PersistentCourseGrade.update_or_create(**self.params) assert grade.letter_grade == '' assert grade.passed_timestamp == passed_timestamp
def test_passed_timestamp(self): # When the user has not passed, passed_timestamp is None self.params.update({ u'percent_grade': 25.0, u'letter_grade': u'', u'passed': False, }) grade = PersistentCourseGrade.update_or_create_course_grade(**self.params) self.assertIsNone(grade.passed_timestamp) # After the user earns a passing grade, the passed_timestamp is set self.params.update({ u'percent_grade': 75.0, u'letter_grade': u'C', u'passed': True, }) grade = PersistentCourseGrade.update_or_create_course_grade(**self.params) passed_timestamp = grade.passed_timestamp self.assertEqual(grade.letter_grade, u'C') self.assertIsInstance(passed_timestamp, datetime) # After the user improves their score, the new grade is reflected, but # the passed_timestamp remains the same. self.params.update({ u'percent_grade': 95.0, u'letter_grade': u'A', u'passed': True, }) grade = PersistentCourseGrade.update_or_create_course_grade(**self.params) self.assertEqual(grade.letter_grade, u'A') self.assertEqual(grade.passed_timestamp, passed_timestamp) # If the grade later reverts to a failing grade, they keep their passed_timestamp self.params.update({ u'percent_grade': 20.0, u'letter_grade': u'', u'passed': False, }) grade = PersistentCourseGrade.update_or_create_course_grade(**self.params) self.assertEqual(grade.letter_grade, u'') self.assertEqual(grade.passed_timestamp, passed_timestamp)
def test_passed_timestamp_is_now(self, mock): with freeze_time(now()): grade = PersistentCourseGrade.update_or_create(**self.params) assert now() == grade.passed_timestamp self.assertEqual(mock.call_count, 1)
def test_grade_does_not_exist(self): with self.assertRaises(PersistentCourseGrade.DoesNotExist): PersistentCourseGrade.read(self.params["user_id"], self.params["course_id"])
def test_update_or_create_event(self): with patch('lms.djangoapps.grades.events.tracker') as tracker_mock: grade = PersistentCourseGrade.update_or_create(**self.params) self._assert_tracker_emitted_event(tracker_mock, grade)
def test_optional_fields(self, field): del self.params[field] grade = PersistentCourseGrade.update_or_create(**self.params) self.assertFalse(getattr(grade, field))
def test_update_or_create_with_bad_params(self, param, val, error): self.params[param] = val with self.assertRaises(error): PersistentCourseGrade.update_or_create(**self.params)
def test_create_and_read_grade(self): created_grade = PersistentCourseGrade.update_or_create_course_grade(**self.params) read_grade = PersistentCourseGrade.read_course_grade(self.params["user_id"], self.params["course_id"]) for param in self.params: self.assertEqual(self.params[param], getattr(created_grade, param)) self.assertEqual(created_grade, read_grade)
def test_passed_timestamp_is_now(self): with freeze_time(now()): grade = PersistentCourseGrade.update_or_create(**self.params) self.assertEqual(now(), grade.passed_timestamp)
def test_update_or_create_event(self): with patch('lms.djangoapps.grades.models.tracker') as tracker_mock: grade = PersistentCourseGrade.update_or_create(**self.params) self._assert_tracker_emitted_event(tracker_mock, grade)
def test_optional_fields(self, field): del self.params[field] grade = PersistentCourseGrade.update_or_create(**self.params) self.assertFalse(getattr(grade, field))
def test_course_version_optional(self): del self.params["course_version"] grade = PersistentCourseGrade.update_or_create_course_grade(**self.params) self.assertEqual("", grade.course_version)
def test_passed_timestamp_is_now(self): grade = PersistentCourseGrade.update_or_create_course_grade(**self.params) self.assertEqual(now(), grade.passed_timestamp)
def test_update_or_create_with_bad_params(self, param, val, error): self.params[param] = val with self.assertRaises(error): PersistentCourseGrade.update_or_create_course_grade(**self.params)
def clear_prefetched_course_and_subsection_grades(course_key): _PersistentCourseGrade.clear_prefetched_data(course_key)
def prefetch_course_and_subsection_grades(course_key, users): _PersistentCourseGrade.prefetch(course_key, users) _PersistentSubsectionGrade.prefetch(course_key, users)
def prefetch_course_grades(course_key, users): _PersistentCourseGrade.prefetch(course_key, users)
def test_grade_does_not_exist(self): with self.assertRaises(PersistentCourseGrade.DoesNotExist): PersistentCourseGrade.read_course_grade(self.params["user_id"], self.params["course_id"])