def _create_from_course(course): """ Creates a CourseOverview object from a CourseDescriptor. Does not touch the database, simply constructs and returns an overview from the given course. Arguments: course (CourseDescriptor): any course descriptor object Returns: CourseOverview: overview extracted from the given course """ from lms.djangoapps.certificates.api import get_active_web_certificate from lms.djangoapps.courseware.courses import course_image_url # Workaround for a problem discovered in https://openedx.atlassian.net/browse/TNL-2806. # If the course has a malformed grading policy such that # course._grading_policy['GRADE_CUTOFFS'] = {}, then # course.lowest_passing_grade will raise a ValueError. # Work around this for now by defaulting to None. try: lowest_passing_grade = course.lowest_passing_grade except ValueError: lowest_passing_grade = None return CourseOverview( id=course.id, _location=course.location, display_name=course.display_name, display_number_with_default=course.display_number_with_default, display_org_with_default=course.display_org_with_default, start=course.start, end=course.end, advertised_start=course.advertised_start, course_image_url=course_image_url(course), facebook_url=course.facebook_url, social_sharing_url=course.social_sharing_url, certificates_display_behavior=course.certificates_display_behavior, certificates_show_before_end=course.certificates_show_before_end, cert_html_view_enabled=course.cert_html_view_enabled, has_any_active_web_certificate=(get_active_web_certificate(course) is not None), cert_name_short=course.cert_name_short, cert_name_long=course.cert_name_long, lowest_passing_grade=lowest_passing_grade, end_of_course_survey_url=course.end_of_course_survey_url, days_early_for_beta=course.days_early_for_beta, mobile_available=course.mobile_available, visible_to_staff_only=course.visible_to_staff_only, _pre_requisite_courses_json=json.dumps(course.pre_requisite_courses) )
def _create_from_course(course): """ Creates a CourseOverview object from a CourseDescriptor. Does not touch the database, simply constructs and returns an overview from the given course. Arguments: course (CourseDescriptor): any course descriptor object Returns: CourseOverview: overview extracted from the given course """ from lms.djangoapps.certificates.api import get_active_web_certificate from lms.djangoapps.courseware.courses import course_image_url # Workaround for a problem discovered in https://openedx.atlassian.net/browse/TNL-2806. # If the course has a malformed grading policy such that # course._grading_policy['GRADE_CUTOFFS'] = {}, then # course.lowest_passing_grade will raise a ValueError. # Work around this for now by defaulting to None. try: lowest_passing_grade = course.lowest_passing_grade except ValueError: lowest_passing_grade = None return CourseOverview( id=course.id, _location=course.location, display_name=course.display_name, display_number_with_default=course.display_number_with_default, display_org_with_default=course.display_org_with_default, start=course.start, end=course.end, advertised_start=course.advertised_start, course_image_url=course_image_url(course), facebook_url=course.facebook_url, social_sharing_url=course.social_sharing_url, certificates_display_behavior=course.certificates_display_behavior, certificates_show_before_end=course.certificates_show_before_end, cert_html_view_enabled=course.cert_html_view_enabled, has_any_active_web_certificate=(get_active_web_certificate(course) is not None), cert_name_short=course.cert_name_short, cert_name_long=course.cert_name_long, lowest_passing_grade=lowest_passing_grade, end_of_course_survey_url=course.end_of_course_survey_url, days_early_for_beta=course.days_early_for_beta, mobile_available=course.mobile_available, visible_to_staff_only=course.visible_to_staff_only, _pre_requisite_courses_json=json.dumps( course.pre_requisite_courses))
def _create_from_course(course): """ Creates a CourseOverview object from a CourseDescriptor. Does not touch the database, simply constructs and returns an overview from the given course. Arguments: course (CourseDescriptor): any course descriptor object Returns: CourseOverview: overview extracted from the given course """ from lms.djangoapps.certificates.api import get_active_web_certificate from lms.djangoapps.courseware.courses import course_image_url return CourseOverview( id=course.id, _location=course.location, display_name=course.display_name, display_number_with_default=course.display_number_with_default, display_org_with_default=course.display_org_with_default, start=course.start, end=course.end, advertised_start=course.advertised_start, course_image_url=course_image_url(course), facebook_url=course.facebook_url, social_sharing_url=course.social_sharing_url, certificates_display_behavior=course.certificates_display_behavior, certificates_show_before_end=course.certificates_show_before_end, cert_html_view_enabled=course.cert_html_view_enabled, has_any_active_web_certificate=(get_active_web_certificate(course) is not None), cert_name_short=course.cert_name_short, cert_name_long=course.cert_name_long, lowest_passing_grade=course.lowest_passing_grade, end_of_course_survey_url=course.end_of_course_survey_url, days_early_for_beta=course.days_early_for_beta, mobile_available=course.mobile_available, visible_to_staff_only=course.visible_to_staff_only, _pre_requisite_courses_json=json.dumps(course.pre_requisite_courses) )
def check_course_overview_against_course(self, course): """ Compares a CourseOverview object against its corresponding CourseDescriptor object. Specifically, given a course, test that data within the following three objects match each other: - the CourseDescriptor itself - a CourseOverview that was newly constructed from _create_from_course - a CourseOverview that was loaded from the MySQL database Arguments: course (CourseDescriptor): the course to be checked. """ def get_seconds_since_epoch(date_time): """ Returns the number of seconds between the Unix Epoch and the given datetime. If the given datetime is None, return None. Arguments: date_time (datetime): the datetime in question. """ if date_time is None: return None epoch = datetime.datetime.utcfromtimestamp(0).replace(tzinfo=pytz.utc) return math.floor((date_time - epoch).total_seconds()) # Load the CourseOverview from the cache twice. The first load will be a cache miss (because the cache # is empty) so the course will be newly created with CourseOverviewDescriptor.create_from_course. The second # load will be a cache hit, so the course will be loaded from the cache. course_overview_cache_miss = CourseOverview.get_from_id(course.id) course_overview_cache_hit = CourseOverview.get_from_id(course.id) # Test if value of these attributes match between the three objects fields_to_test = [ 'id', 'display_name', 'display_number_with_default', 'display_org_with_default', 'advertised_start', 'facebook_url', 'social_sharing_url', 'certificates_display_behavior', 'certificates_show_before_end', 'cert_name_short', 'cert_name_long', 'lowest_passing_grade', 'end_of_course_survey_url', 'mobile_available', 'visible_to_staff_only', 'location', 'number', 'url_name', 'display_name_with_default', 'start_date_is_still_default', 'pre_requisite_courses', ] for attribute_name in fields_to_test: course_value = getattr(course, attribute_name) cache_miss_value = getattr(course_overview_cache_miss, attribute_name) cache_hit_value = getattr(course_overview_cache_hit, attribute_name) self.assertEqual(course_value, cache_miss_value) self.assertEqual(cache_miss_value, cache_hit_value) # Test if return values for all methods are equal between the three objects methods_to_test = [ ('clean_id', ()), ('clean_id', ('#',)), ('has_ended', ()), ('has_started', ()), ('start_datetime_text', ('SHORT_DATE',)), ('start_datetime_text', ('DATE_TIME',)), ('end_datetime_text', ('SHORT_DATE',)), ('end_datetime_text', ('DATE_TIME',)), ('may_certify', ()), ] for method_name, method_args in methods_to_test: course_value = getattr(course, method_name)(*method_args) cache_miss_value = getattr(course_overview_cache_miss, method_name)(*method_args) cache_hit_value = getattr(course_overview_cache_hit, method_name)(*method_args) self.assertEqual(course_value, cache_miss_value) self.assertEqual(cache_miss_value, cache_hit_value) # Other values to test # Note: we test the start and end attributes here instead of in # fields_to_test, because I ran into trouble while testing datetimes # for equality. When writing and reading dates from databases, the # resulting values are often off by fractions of a second. So, as a # workaround, we simply test if the start and end times are the same # number of seconds from the Unix epoch. others_to_test = [( course_image_url(course), course_overview_cache_miss.course_image_url, course_overview_cache_hit.course_image_url ), ( get_active_web_certificate(course) is not None, course_overview_cache_miss.has_any_active_web_certificate, course_overview_cache_hit.has_any_active_web_certificate ), ( get_seconds_since_epoch(course.start), get_seconds_since_epoch(course_overview_cache_miss.start), get_seconds_since_epoch(course_overview_cache_hit.start), ), ( get_seconds_since_epoch(course.end), get_seconds_since_epoch(course_overview_cache_miss.end), get_seconds_since_epoch(course_overview_cache_hit.end), )] for (course_value, cache_miss_value, cache_hit_value) in others_to_test: self.assertEqual(course_value, cache_miss_value) self.assertEqual(cache_miss_value, cache_hit_value)
def check_course_overview_against_course(self, course): """ Compares a CourseOverview object against its corresponding CourseDescriptor object. Specifically, given a course, test that data within the following three objects match each other: - the CourseDescriptor itself - a CourseOverview that was newly constructed from _create_from_course - a CourseOverview that was loaded from the MySQL database Arguments: course (CourseDescriptor): the course to be checked. """ def get_seconds_since_epoch(date_time): """ Returns the number of seconds between the Unix Epoch and the given datetime. If the given datetime is None, return None. Arguments: date_time (datetime): the datetime in question. """ if date_time is None: return None epoch = datetime.datetime.utcfromtimestamp(0).replace(tzinfo=pytz.utc) return math.floor((date_time - epoch).total_seconds()) # Load the CourseOverview from the cache twice. The first load will be a cache miss (because the cache # is empty) so the course will be newly created with CourseOverviewDescriptor.create_from_course. The second # load will be a cache hit, so the course will be loaded from the cache. course_overview_cache_miss = CourseOverview.get_from_id(course.id) course_overview_cache_hit = CourseOverview.get_from_id(course.id) # Test if value of these attributes match between the three objects fields_to_test = [ 'id', 'display_name', 'display_number_with_default', 'display_org_with_default', 'advertised_start', 'facebook_url', 'social_sharing_url', 'certificates_display_behavior', 'certificates_show_before_end', 'cert_name_short', 'cert_name_long', 'lowest_passing_grade', 'end_of_course_survey_url', 'mobile_available', 'visible_to_staff_only', 'location', 'number', 'url_name', 'display_name_with_default', 'start_date_is_still_default', 'pre_requisite_courses', 'enrollment_domain', 'invitation_only', 'max_student_enrollments_allowed', ] for attribute_name in fields_to_test: course_value = getattr(course, attribute_name) cache_miss_value = getattr(course_overview_cache_miss, attribute_name) cache_hit_value = getattr(course_overview_cache_hit, attribute_name) self.assertEqual(course_value, cache_miss_value) self.assertEqual(cache_miss_value, cache_hit_value) # Test if return values for all methods are equal between the three objects methods_to_test = [ ('clean_id', ()), ('clean_id', ('#',)), ('has_ended', ()), ('has_started', ()), ('start_datetime_text', ('SHORT_DATE',)), ('start_datetime_text', ('DATE_TIME',)), ('end_datetime_text', ('SHORT_DATE',)), ('end_datetime_text', ('DATE_TIME',)), ('may_certify', ()), ] for method_name, method_args in methods_to_test: course_value = getattr(course, method_name)(*method_args) cache_miss_value = getattr(course_overview_cache_miss, method_name)(*method_args) cache_hit_value = getattr(course_overview_cache_hit, method_name)(*method_args) self.assertEqual(course_value, cache_miss_value) self.assertEqual(cache_miss_value, cache_hit_value) # Other values to test # Note: we test the start and end attributes here instead of in # fields_to_test, because I ran into trouble while testing datetimes # for equality. When writing and reading dates from databases, the # resulting values are often off by fractions of a second. So, as a # workaround, we simply test if the start and end times are the same # number of seconds from the Unix epoch. others_to_test = [ ( course_image_url(course), course_overview_cache_miss.course_image_url, course_overview_cache_hit.course_image_url ), ( get_active_web_certificate(course) is not None, course_overview_cache_miss.has_any_active_web_certificate, course_overview_cache_hit.has_any_active_web_certificate ), ( get_seconds_since_epoch(course.start), get_seconds_since_epoch(course_overview_cache_miss.start), get_seconds_since_epoch(course_overview_cache_hit.start), ), ( get_seconds_since_epoch(course.end), get_seconds_since_epoch(course_overview_cache_miss.end), get_seconds_since_epoch(course_overview_cache_hit.end), ), ( get_seconds_since_epoch(course.enrollment_start), get_seconds_since_epoch(course_overview_cache_miss.enrollment_start), get_seconds_since_epoch(course_overview_cache_hit.enrollment_start), ), ( get_seconds_since_epoch(course.enrollment_end), get_seconds_since_epoch(course_overview_cache_miss.enrollment_end), get_seconds_since_epoch(course_overview_cache_hit.enrollment_end), ), ] for (course_value, cache_miss_value, cache_hit_value) in others_to_test: self.assertEqual(course_value, cache_miss_value) self.assertEqual(cache_miss_value, cache_hit_value) # test tabs for both cached miss and cached hit courses for course_overview in [course_overview_cache_miss, course_overview_cache_hit]: course_overview_tabs = course_overview.tabs.all() course_resp_tabs = {tab.tab_id for tab in course_overview_tabs} self.assertEqual(self.COURSE_OVERVIEW_TABS, course_resp_tabs)