def test_retrieve_with_sorting_flag(self, order_courses_by_start_date): """ Verify the number of queries is the same with sorting flag set to true. """ course_list = CourseFactory.create_batch(3) for course in course_list: CourseRunFactory(course=course) program = ProgramFactory(courses=course_list, order_courses_by_start_date=order_courses_by_start_date) with self.assertNumQueries(90): self.assert_retrieve_success(program) self.assertEqual(course_list, list(program.courses.all())) # pylint: disable=no-member
def test_list_query(self): """ Verify the endpoint returns a filtered list of courses """ title = 'Some random title' courses = CourseFactory.create_batch(3, title=title) courses = sorted(courses, key=lambda course: course.key.lower()) query = 'title:' + title url = '{root}?q={query}'.format(root=reverse('api:v1:course-list'), query=query) response = self.client.get(url) self.assertListEqual(response.data['results'], self.serialize_course(courses, many=True))
def test_get_distinct_count_runs_query_when_cache_empty(self): """ Verify that get_distinct_count runs the query and caches/returns the distinct_count.""" course = CourseFactory() CourseRunFactory(title='foo', course=course) CourseRunFactory(title='foo', course=course) query = DistinctCountsSearchQuery() query.aggregation_key = 'aggregation_key' query.add_filter(SQ(title='foo')) query.add_model(CourseRun) assert query._distinct_hit_count is None assert query.get_distinct_count() == 1 assert query._distinct_hit_count == 1
def create_curriculum(self, parent_program): person = PersonFactory() course = CourseFactory(partner=self.partner) CourseRunFactory(course=course, staff=[person]) CourseRunFactory(course=course, staff=[person]) curriculum = CurriculumFactory( program=parent_program ) CurriculumCourseMembershipFactory( course=course, curriculum=curriculum ) return curriculum
def test_ensure_draft_world_not_draft_course_run_given(self): course = CourseFactory() course_run = CourseRunFactory(course=course) verified_seat = SeatFactory(type='verified', course_run=course_run) audit_seat = SeatFactory(type='audit', course_run=course_run) course_run.seats.add(verified_seat, audit_seat) ensured_draft_course_run = utils.ensure_draft_world(course_run) not_draft_course_run = CourseRun.objects.get(uuid=course_run.uuid) self.assertNotEqual(ensured_draft_course_run, not_draft_course_run) self.assertEqual(ensured_draft_course_run.uuid, not_draft_course_run.uuid) self.assertTrue(ensured_draft_course_run.draft) self.assertNotEqual(ensured_draft_course_run.course, not_draft_course_run.course) self.assertEqual(ensured_draft_course_run.course.uuid, not_draft_course_run.course.uuid) # Check slugs are equal self.assertEqual(ensured_draft_course_run.slug, not_draft_course_run.slug) # Seat checks draft_seats = ensured_draft_course_run.seats.all() not_draft_seats = Seat.objects.filter(course_run=not_draft_course_run) self.assertNotEqual(draft_seats, not_draft_seats) for i, __ in enumerate(draft_seats): self.assertEqual(draft_seats[i].price, not_draft_seats[i].price) self.assertEqual(draft_seats[i].sku, not_draft_seats[i].sku) self.assertNotEqual(draft_seats[i].course_run, not_draft_seats[i].course_run) self.assertEqual(draft_seats[i].course_run.uuid, not_draft_seats[i].course_run.uuid) self.assertEqual(draft_seats[i].official_version, not_draft_seats[i]) self.assertEqual(not_draft_seats[i].draft_version, draft_seats[i]) # Check draft course is also created not_draft_course = Course.objects.get(uuid=course.uuid) draft_course = ensured_draft_course_run.course self.assertNotEqual(draft_course, not_draft_course) self.assertEqual(draft_course.uuid, not_draft_course.uuid) self.assertTrue(draft_course.draft) # Check official and draft versions match up self.assertEqual(ensured_draft_course_run.official_version, not_draft_course_run) self.assertEqual(not_draft_course_run.draft_version, ensured_draft_course_run)
def test_get(self): """ Verify that GET request works as expected for `AggregateSearchViewSet` """ CourseFactory(key='course:edX+DemoX', title='ABCs of Ͳҽʂէìղց') expected = {'previous': None, 'results': [], 'next': None, 'count': 0} query = { 'content_type': 'course', 'aggregation_key': ['course:edX+DemoX'] } qs = urllib.parse.urlencode(query) url = '{path}?{qs}'.format(path=self.path, qs=qs) response = self.client.get(url) assert response.json() == expected
def test_facet_counts_includes_distinct_counts(self): """ Verify that facet_counts include distinct counts. """ course = CourseFactory() CourseRunFactory(title='foo', pacing_type='self_paced', hidden=True, course=course) CourseRunFactory(title='foo', pacing_type='self_paced', hidden=True, course=course) CourseRunFactory(title='foo', pacing_type='instructor_paced', hidden=False, course=course) # Make sure to add both a field facet and a query facet so that we can be sure that both work. queryset = DSLFacetedSearch( index=CourseRunDocument._index._name).filter('term', title='foo') facet_field = 'pacing_type' agg_filter = ESDSLQ('match_all') agg = TermsFacet(field=facet_field) queryset.aggs.bucket('_filter_' + facet_field, 'filter', filter=agg_filter).bucket(facet_field, agg.get_aggregation()) queryset.aggs.bucket('_query_{0}'.format('hidden'), 'filter', filter=ESDSLQ('bool', filter=ESDSLQ('term', hidden=True))) dc_queryset = DistinctCountsSearchQuerySet.from_queryset( queryset).with_distinct_counts('aggregation_key') facet_counts = dc_queryset.facet_counts() # Field facets are expected to be formatted as a list of three-tuples (field_value, count, distinct_count) for val, count, distinct_count in facet_counts['fields'][ 'pacing_type']: assert val in {'self_paced', 'instructor_paced'} if val == 'self_paced': assert count == 2 assert distinct_count == 1 elif val == 'instructor_paced': assert count == 1 assert distinct_count == 1 # Query facets are expected to be formatted as a dictionary mapping facet_names to two-tuples (count, # distinct_count) hidden_count, hidden_distinct_count = facet_counts['queries']['hidden'] assert hidden_count == 2 assert hidden_distinct_count == 1
def test_retrieve_with_sorting_flag(self, order_courses_by_start_date): """ Verify the number of queries is the same with sorting flag set to true. """ course_list = CourseFactory.create_batch(3) for course in course_list: CourseRunFactory(course=course) program = ProgramFactory( courses=course_list, order_courses_by_start_date=order_courses_by_start_date) # property does not have the right values while being indexed del program._course_run_weeks_to_complete with self.assertNumQueries(26): response = self.assert_retrieve_success(program) assert response.data == self.serialize_program(program) self.assertEqual(course_list, list(program.courses.all())) # pylint: disable=no-member
def test_selected_query_facet(self): """ Verify that the response is accurate when a query facet is selected.""" now = datetime.datetime.now(pytz.UTC) current = (now - datetime.timedelta(days=1), now + datetime.timedelta(days=1)) archived = (now - datetime.timedelta(days=2), now - datetime.timedelta(days=1)) course = CourseFactory(partner=self.partner) run_1 = self.build_courserun(course=course, start=current[0], end=current[1], pacing_type='self_paced') run_2 = self.build_courserun(course=course, start=current[0], end=current[1], pacing_type='self_paced') self.build_courserun(course=course, start=archived[0], end=archived[1], pacing_type='self_paced') self.build_courserun(course=course, start=archived[0], end=archived[1], pacing_type='instructor_paced') response = self.get_response( {'selected_query_facets': 'availability_current'}) assert response.status_code == 200 assert response.data['objects']['count'] == 2 assert response.data['objects']['distinct_count'] == 1 expected = sorted([run_1.key, run_2.key]) actual = sorted( [run['key'] for run in response.data['objects']['results']]) assert expected == actual pacing_types = { facet['text']: facet for facet in response.data['fields']['pacing_type'] } assert pacing_types['self_paced']['count'] == 2 assert pacing_types['self_paced']['distinct_count'] == 1 expected_query_params = { 'selected_query_facets': ['availability_current'], 'selected_facets': ['pacing_type_exact:self_paced'], } self.assert_url_path_and_query( pacing_types['self_paced']['narrow_url'], self.path, expected_query_params)
def test_editable_get_gives_drafts(self): draft = CourseFactory(partner=self.partner, uuid=self.course.uuid, key=self.course.key, draft=True) self.course.draft_version = draft self.course.save() extra = CourseFactory(partner=self.partner) response = self.client.get( reverse('api:v1:course-detail', kwargs={'key': self.course.uuid}) + '?editable=1') self.assertEqual(response.status_code, 200) self.assertEqual(response.data, self.serialize_course(draft, many=False)) response = self.client.get( reverse('api:v1:course-detail', kwargs={'key': extra.uuid}) + '?editable=1') # TODO: Swap commented lines with one below it when completing DISCO-818 # self.assertEqual(response.status_code, 200) # self.assertEqual(response.data, self.serialize_course(extra, many=False)) self.assertEqual(response.status_code, 404)
def test_update_fails_with_multiple_errors(self, course_data, expected_error_message): # TODO: Swap commented line with one below it when completing DISCO-818 # course = CourseFactory(partner=self.partner, key='Org/Course/Number') course = CourseFactory(partner=self.partner, key='Org/Course/Number', draft=True) url = reverse('api:v1:course-detail', kwargs={'key': course.uuid}) mode1 = SeatTypeFactory(name='Mode1') SeatTypeFactory(name='Mode2') CourseEntitlementFactory(course=course, mode=mode1, sku=None) response = self.client.patch(url, course_data, format='json') self.assertEqual(response.status_code, 400) self.assertEqual(response.data, expected_error_message)
def test_list_with_org_multiple(self): org1 = OrganizationFactory() org2 = OrganizationFactory() course1 = CourseFactory(authoring_organizations=[org1]) course2 = CourseFactory(authoring_organizations=[org2]) with mock.patch.object(MarketingSitePeople, 'update_or_publish_person'): person1 = PersonFactory(partner=self.partner) person2 = PersonFactory(partner=self.partner) PersonFactory(partner=self.partner) CourseRunFactory(staff=[person1], course=course1) CourseRunFactory(staff=[person2], course=course2) url = '{url}?org={org1_key}&org={org2_key}'.format( url=self.people_list_url, org1_key=org1.key, org2_key=org2.key, ) response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertEqual(len(response.data['results']), 2) self.assertCountEqual( response.data['results'], self.serialize_person([person1, person2], many=True))
def test_data(self): user = UserFactory() catalog = CatalogFactory(query='*:*', viewers=[user]) # We intentionally use a query for all Courses. courses = CourseFactory.create_batch(10) serializer = CatalogSerializer(catalog) expected = { 'id': catalog.id, 'name': catalog.name, 'query': catalog.query, 'courses_count': len(courses), 'viewers': [user.username] } self.assertDictEqual(serializer.data, expected)
def test_field_facet_response(self): """ Verify that field facets are included in the response and that they are properly formatted.""" for course in [CourseFactory(partner=self.partner), CourseFactory(partner=self.partner)]: self.build_courserun(course=course) self.build_courserun(course=course) self.build_program(partner=self.partner) response = self.get_response() assert response.status_code == 200 expected_facets = DistinctCountsAggregateFacetSearchSerializer.Meta.field_options.keys() assert sorted(expected_facets) == sorted(response.data['fields'].keys()) content_types = {facet['text']: facet for facet in response.data['fields']['content_type']} assert content_types['courserun']['count'] == 4 assert content_types['courserun']['distinct_count'] == 2 narrow_url = content_types['courserun']['narrow_url'] self.assert_url_path_and_query(narrow_url, self.path, {'selected_facets': ['content_type_exact:courserun']}) assert content_types['program']['count'] == 1 assert content_types['program']['distinct_count'] == 1 narrow_url = content_types['program']['narrow_url'] self.assert_url_path_and_query(narrow_url, self.path, {'selected_facets': ['content_type_exact:program']})
def create_mock_courses_and_runs(self, programs): for program in programs: for course_code in program.get('course_codes', []): key = '{org}+{course}'.format( org=course_code['organization']['key'], course=course_code['key']) course = CourseFactory(key=key, partner=self.partner) for course_run in course_code['run_modes']: CourseRunFactory(course=course, key=course_run['course_key']) # Add an additional course run that should be excluded CourseRunFactory(course=course)
def setUpClass(cls): super().setUpClass() cls.user = UserFactory(is_staff=True) cls.courses = factories.CourseFactory.create_batch( 3, title='Some random course title') first_instructor = PersonFactory(given_name="First", family_name="Instructor") second_instructor = PersonFactory(given_name="Second", family_name="Instructor") cls.instructors = [first_instructor, second_instructor] cls.organizations = OrganizationFactory.create_batch(3) cls.organization_extensions = [] for instructor in cls.instructors: PositionFactory(organization=cls.organizations[0], title="professor", person=instructor) cls.course_runs = [ factories.CourseRunFactory(course=course) for course in cls.courses ] for organization in cls.organizations: cls.organization_extensions.append( factories.OrganizationExtensionFactory( organization=organization)) disco_course = CourseFactory( authoring_organizations=[cls.organizations[0]]) disco_course2 = CourseFactory( authoring_organizations=[cls.organizations[1]]) CourseRunFactory(course=disco_course, staff=[first_instructor]) CourseRunFactory(course=disco_course2, staff=[second_instructor]) cls.user.groups.add(cls.organization_extensions[0].group)
def setUp(self): super(CourseRunViewSetTests, self).setUp() self.user = UserFactory(is_staff=True) self.client.force_authenticate(self.user) self.course_run = CourseRunFactory(course__partner=self.partner) self.course_run_2 = CourseRunFactory(course__key='Test+Course', course__partner=self.partner) self.draft_course = CourseFactory(partner=self.partner, draft=True) self.draft_course_run = CourseRunFactory(course=self.draft_course, draft=True) self.draft_course_run.course.authoring_organizations.add( OrganizationFactory(key='course-id')) self.refresh_index() self.request = APIRequestFactory().get('/') self.request.user = self.user
def test_editable_list_gives_drafts(self): draft = CourseFactory(partner=self.partner, uuid=self.course.uuid, key=self.course.key, draft=True) draft_course_run = CourseRunFactory( status=CourseRunStatus.Published, end=datetime.datetime.now(pytz.UTC) + datetime.timedelta(days=10), course=draft, draft=True, ) self.course.draft_version = draft self.course.save() extra = CourseFactory(partner=self.partner, key=self.course.key + 'Z') # set key so it sorts later response = self.client.get( reverse('api:v1:course-list') + '?editable=1') self.assertEqual(response.status_code, 200) self.assertEqual(response.data['results'], self.serialize_course([draft, extra], many=True)) self.assertEqual(len(response.data['results'][0]['course_runs']), 1) self.assertEqual(response.data['results'][0]['course_runs'][0]['uuid'], str(draft_course_run.uuid))
def test_list_with_org_single(self): org1 = OrganizationFactory() course = CourseFactory(authoring_organizations=[org1]) with mock.patch.object(MarketingSitePeople, 'update_or_publish_person'): person1 = PersonFactory(partner=self.partner) PersonFactory(partner=self.partner) PersonFactory(partner=self.partner) CourseRunFactory(staff=[person1], course=course) url = f'{self.people_list_url}?org={org1.key}' response = self.client.get(url) assert response.status_code == 200 assert len(response.data['results']) == 1 assert response.data['results'] == self.serialize_person([person1], many=True)
def setUp(self): super(CreateCoursesTests, self).setUp() transcript_languages = LanguageTag.objects.all()[:2] self.subjects = SubjectFactory.create_batch(3) self.test_image = make_image_file('testimage.jpg') self.course = CourseFactory( subjects=self.subjects, image__from_file=self.test_image ) self.command_name = 'import_metadata_courses' self.command_args = ['--start_id={}'.format(self.course.id), '--end_id={}'.format(self.course.id)] # create multiple course-runs against course. course_runs = CourseRunFactory.create_batch( 3, course=self.course, transcript_languages=transcript_languages, language=transcript_languages[0], short_description_override='Testing description' ) canonical_course_run = course_runs[0] for seat_type in ['honor', 'credit', 'verified']: # to avoid same type seat creation. seat_type_obj = getattr(SeatTypeFactory, seat_type)() SeatFactory(course_run=canonical_course_run, type=seat_type_obj) staff = PersonFactory.create_batch(2) canonical_course_run.staff.add(*staff) self.course.canonical_course_run = canonical_course_run self.course.save() # create org and assign to the course-metadata self.forganization_extension = factories.OrganizationExtensionFactory() self.organization = self.forganization_extension.organization self.course.authoring_organizations.add(self.organization)
def test_course_autocomplete(self, admin_client): """ Verify course autocomplete returns the data. """ courses = CourseFactory.create_batch(3) path = reverse('admin_metadata:course-autocomplete') response = admin_client.get(path) data = json.loads(response.content.decode('utf-8')) assert response.status_code == 200 assert len(data['results']) == 3 # Search for substrings of course keys and titles course = courses[0] self.assert_valid_query_result(admin_client, path, course.key[12:], course) self.assert_valid_query_result(admin_client, path, course.title[12:], course)
def test_retrieve_with_sorting_flag(self, order_courses_by_start_date, django_assert_num_queries): """ Verify the number of queries is the same with sorting flag set to true. """ course_list = CourseFactory.create_batch(3, partner=self.partner) for course in course_list: CourseRunFactory(course=course) program = ProgramFactory( courses=course_list, order_courses_by_start_date=order_courses_by_start_date, partner=self.partner) # property does not have the right values while being indexed del program._course_run_weeks_to_complete with django_assert_num_queries(FuzzyInt(40, 1)): # CI is often 41 response = self.assert_retrieve_success(program) assert response.data == self.serialize_program(program) assert course_list == list(program.courses.all())
def test_course_ordering_with_exclusions(self): """ Verify that excluded course runs aren't used when ordering courses. """ request = make_request() course_list = CourseFactory.create_batch(3) # Create a course run with arbitrary start and empty enrollment_start. # This run will be excluded from the program. If it wasn't excluded, # the expected course ordering, by index, would be: 0, 2, 1. excluded_run = CourseRunFactory( course=course_list[0], enrollment_start=None, start=datetime(2014, 1, 1), ) # Create a run with later start and empty enrollment_start. CourseRunFactory( course=course_list[2], enrollment_start=None, start=datetime(2014, 2, 1), ) # Create a run with matching start, but later enrollment_start. CourseRunFactory( course=course_list[1], enrollment_start=datetime(2014, 1, 2), start=datetime(2014, 2, 1), ) # Create a run with later start and enrollment_start. CourseRunFactory( course=course_list[0], enrollment_start=datetime(2014, 2, 1), start=datetime(2014, 3, 1), ) program = ProgramFactory(courses=course_list, excluded_course_runs=[excluded_run]) serializer = self.serializer_class(program, context={'request': request}) expected = MinimalProgramCourseSerializer( # The expected ordering is the reverse of course_list. course_list[::-1], many=True, context={'request': request, 'program': program, 'course_runs': list(program.course_runs)} ).data self.assertEqual(serializer.data['courses'], expected)
def mock_products_api(self, alt_course=None, alt_currency=None, alt_mode=None, has_stockrecord=True, valid_stockrecord=True): """ Return a new Course Entitlement to be added by ingest """ course = CourseFactory() bodies = [{ "structure": "child", "product_class": "Course Entitlement", "title": "Course Intro to Everything", "price": "10.00", "expires": None, "attribute_values": [{ "name": "certificate_type", "value": alt_mode if alt_mode else "verified", }, { "name": "UUID", "value": alt_course if alt_course else str(course.uuid), }], "is_available_to_buy": True, "stockrecords": [] }] stockrecord = { "price_currency": alt_currency if alt_currency else "USD", "price_excl_tax": "10.00", } if valid_stockrecord: stockrecord.update({"partner_sku": "sku132"}) if has_stockrecord: bodies[0]["stockrecords"].append(stockrecord) url = '{url}products/'.format(url=self.api_url) responses.add_callback(responses.GET, url, callback=mock_api_callback(url, bodies), content_type=JSON) return bodies
def test_download_with_unexpected_error(self): image_url, __ = self.mock_image_response() course = CourseFactory(card_image_url=image_url, image=None) with mock.patch('stdimage.models.StdImageFieldFile.save', side_effect=Exception) as mock_save: with mock.patch(self.LOGGER_PATH) as mock_logger: call_command('download_course_images') mock_logger.exception.assert_called_once_with( 'An unknown exception occurred while downloading image for course [%s]', course.key) mock_save.assert_called_once() assert len(responses.calls) == 1 self.assert_course_has_no_image(course)
def test_data(self): user = UserFactory() catalog = CatalogFactory( query='*:*', viewers=[user]) # We intentionally use a query for all Courses. courses = CourseFactory.create_batch(10) serializer = CatalogSerializer(catalog) expected = { 'id': catalog.id, 'name': catalog.name, 'query': catalog.query, 'courses_count': len(courses), 'viewers': [user.username] } self.assertDictEqual(serializer.data, expected)
def test_download_with_invalid_content_type(self): content_type = 'text/plain' image_url, __ = self.mock_image_response(content_type=content_type) course = CourseFactory(card_image_url=image_url, image=None) with mock.patch(self.LOGGER_PATH) as mock_logger: call_command('download_course_images') mock_logger.error.assert_called_with( 'Image retrieved for course [%s] from [%s] has an unknown content type [%s] and will not be saved.', course.key, image_url, content_type ) assert len(responses.calls) == 1 self.assert_course_has_no_image(course)
def setUp(self): super(RefreshCourseMetadataCommandTests, self).setUp() self.partner = PartnerFactory() partner = self.partner self.pipeline = [ (CoursesApiDataLoader, partner.courses_api_url, None), (EcommerceApiDataLoader, partner.ecommerce_api_url, 1), (ProgramsApiDataLoader, partner.programs_api_url, None), (AnalyticsAPIDataLoader, partner.analytics_url, 1), ] # Courses must exist for the refresh_course_metadata command to use multiple threads. If there are no # courses, the command won't risk race conditions between threads trying to create the same course. CourseFactory(partner=self.partner) self.mock_access_token()
def test_create_for_self_and_draft_course(self, is_staff, is_draft): """Verify can make self an editor. Test cases: as staff and non-staff, on official and draft course""" self.user.is_staff = is_staff self.user.save() partner = Partner.objects.first() course = CourseFactory(draft=is_draft, partner=partner) self.user.groups.add(self.org_ext.group) course.authoring_organizations.add(self.org_ext.organization) self.client.login(username=self.user.username, password=USER_PASSWORD) self.client.post(self.list_path, {'course': course.uuid}, format='json') course_editor = CourseEditor.objects.first() assert course_editor.course == course assert course_editor.user == self.user
def setUp(self): """ Test set up """ super().setUp() self.user = UserFactory.create(is_staff=True, is_active=True) self.user.set_password('QWERTY') self.user.save() self.course = CourseFactory() self.admin_context = { 'has_permission': True, 'opts': self.course._meta, } self.client = Client() self.view_url = reverse("admin:" + COURSE_SKILLS_URL_NAME, args=(self.course.pk, )) self.context_parameters = CourseSkillsView.ContextParameters
def test_facet_counts_caches_results(self): """ Verify that facet_counts cache results when it is forced to run the query.""" course = CourseFactory() runs = [ CourseRunFactory(title='foo', pacing_type='self_paced', hidden=True, course=course), CourseRunFactory(title='foo', pacing_type='self_paced', hidden=True, course=course), CourseRunFactory(title='foo', pacing_type='instructor_paced', hidden=False, course=course), ] queryset = SearchQuerySet().filter(title='foo').models(CourseRun) queryset = queryset.facet('pacing_type').query_facet( 'hidden', 'hidden:true') dc_queryset = DistinctCountsSearchQuerySet.from_queryset( queryset).with_distinct_counts('aggregation_key') # This should force the query to run and the results to be cached facet_counts = dc_queryset.facet_counts() with mock.patch.object(DistinctCountsSearchQuery, 'run') as mock_run: # Calling facet_counts again shouldn't result in an additional query cached_facet_counts = dc_queryset.facet_counts() assert not mock_run.called assert facet_counts == cached_facet_counts # Calling count shouldn't result in another query, as we should have already cached it with the # first request. count = dc_queryset.count() assert not mock_run.called assert count == len(runs) # Fetching the results shouldn't result in another query, as we should have already cached them # with the initial request. results = dc_queryset[:] assert not mock_run.called expected = {run.key for run in runs} actual = {run.key for run in results} assert expected == actual
def test_download_with_invalid_status_code(self): status = 500 body = b'Oops!' image_url, __ = self.mock_image_response(status=status, body=body) course = CourseFactory(card_image_url=image_url, image=None) with mock.patch(self.LOGGER_PATH) as mock_logger: call_command('download_course_images') mock_logger.error.assert_called_with( 'Failed to download image for course [%s] from [%s]! Response was [%d]:\n%s', course.key, image_url, status, body ) assert len(responses.calls) == 1 self.assert_course_has_no_image(course)
def test_course_ordering(self): """ Verify that courses in a program are ordered by ascending run start date, with ties broken by earliest run enrollment start date. """ request = make_request() course_list = CourseFactory.create_batch(3) # Create a course run with arbitrary start and empty enrollment_start. CourseRunFactory( course=course_list[2], enrollment_start=None, start=datetime(2014, 2, 1), ) # Create a second run with matching start, but later enrollment_start. CourseRunFactory( course=course_list[1], enrollment_start=datetime(2014, 1, 2), start=datetime(2014, 2, 1), ) # Create a third run with later start and enrollment_start. CourseRunFactory( course=course_list[0], enrollment_start=datetime(2014, 2, 1), start=datetime(2014, 3, 1), ) program = ProgramFactory(courses=course_list) serializer = self.serializer_class(program, context={'request': request}) expected = MinimalProgramCourseSerializer( # The expected ordering is the reverse of course_list. course_list[::-1], many=True, context={ 'request': request, 'program': program, 'course_runs': list(program.course_runs) }).data self.assertEqual(serializer.data['courses'], expected)
def create_program(self): organizations = [OrganizationFactory()] person = PersonFactory() course = CourseFactory() CourseRunFactory(course=course, staff=[person]) program = ProgramFactory( courses=[course], authoring_organizations=organizations, credit_backing_organizations=organizations, corporate_endorsements=CorporateEndorsementFactory.create_batch(1), individual_endorsements=EndorsementFactory.create_batch(1), expected_learning_items=ExpectedLearningItemFactory.create_batch( 1), job_outlook_items=JobOutlookItemFactory.create_batch(1), banner_image=make_image_file('test_banner.jpg'), video=VideoFactory()) return program
def create_program(self): organizations = OrganizationFactory.create_batch(2) person = PersonFactory() courses = CourseFactory.create_batch(3) for course in courses: CourseRunFactory.create_batch(2, course=course, staff=[person], start=datetime.now()) return ProgramFactory( courses=courses, authoring_organizations=organizations, credit_backing_organizations=organizations, corporate_endorsements=CorporateEndorsementFactory.create_batch(1), individual_endorsements=EndorsementFactory.create_batch(1), expected_learning_items=ExpectedLearningItemFactory.create_batch(1), job_outlook_items=JobOutlookItemFactory.create_batch(1), banner_image=make_image_file('test_banner.jpg'), video=VideoFactory(), order_courses_by_start_date=False, )
def test_course_ordering(self): """ Verify that courses in a program are ordered by ascending run start date, with ties broken by earliest run enrollment start date. """ request = make_request() course_list = CourseFactory.create_batch(3) # Create a course run with arbitrary start and empty enrollment_start. CourseRunFactory( course=course_list[2], enrollment_start=None, start=datetime(2014, 2, 1), ) # Create a second run with matching start, but later enrollment_start. CourseRunFactory( course=course_list[1], enrollment_start=datetime(2014, 1, 2), start=datetime(2014, 2, 1), ) # Create a third run with later start and enrollment_start. CourseRunFactory( course=course_list[0], enrollment_start=datetime(2014, 2, 1), start=datetime(2014, 3, 1), ) program = ProgramFactory(courses=course_list) serializer = self.serializer_class(program, context={'request': request}) expected = MinimalProgramCourseSerializer( # The expected ordering is the reverse of course_list. course_list[::-1], many=True, context={'request': request, 'program': program, 'course_runs': list(program.course_runs)} ).data self.assertEqual(serializer.data['courses'], expected)