def test_exclude_utm(self): request = make_request() course = CourseFactory() CourseRunFactory.create_batch(3, course=course) serializer = self.serializer_class(course, context={'request': request, 'exclude_utm': 1}) self.assertEqual(serializer.data['marketing_url'], course.marketing_url)
def test_filter_by_license(self): CourseRun.objects.all().delete() course_runs_cc = CourseRunFactory.create_batch(3, course__partner=self.partner, license='cc-by-sa') CourseRunFactory.create_batch(3, course__partner=self.partner, license='') url = reverse('api:v1:course_run-list') + '?license=cc-by-sa' self.assert_list_results(url, course_runs_cc)
def test_data(self): course = CourseFactory() image = course.image video = course.video request = make_request() CourseRunFactory.create_batch(3, course=course) serializer = CourseSerializer(course, context={'request': request}) expected = { 'key': course.key, 'title': course.title, 'short_description': course.short_description, 'full_description': course.full_description, 'level_type': course.level_type.name, 'subjects': [], 'prerequisites': [], 'expected_learning_items': [], 'image': ImageSerializer(image).data, 'video': VideoSerializer(video).data, 'owners': [], 'sponsors': [], 'modified': json_date_format(course.modified), # pylint: disable=no-member 'course_runs': CourseRunSerializer(course.course_runs, many=True, context={'request': request}).data, 'marketing_url': '{url}?{params}'.format( url=course.marketing_url, params=urlencode({ 'utm_source': request.user.username, 'utm_medium': request.user.referral_tracking_id, }) ) } self.assertDictEqual(serializer.data, expected)
def test_data(self): request = make_request() organizations = OrganizationFactory() course = CourseFactory(authoring_organizations=[organizations]) CourseRunFactory.create_batch(2, course=course) serializer = self.serializer_class(course, context={'request': request}) expected = self.get_expected_data(course, request) self.assertDictEqual(serializer.data, expected)
def test_filter_by_marketable(self): """ Verify the endpoint filters course runs to those that are marketable. """ CourseRun.objects.all().delete() expected = CourseRunFactory.create_batch(3, course__partner=self.partner) CourseRunFactory.create_batch(3, slug=None, course__partner=self.partner) CourseRunFactory.create_batch(3, slug='', course__partner=self.partner) url = reverse('api:v1:course_run-list') + '?marketable=1' self.assert_list_results(url, expected)
def setUp(self): super(SearchQuerySetWrapperTests, self).setUp() title = 'Some random course' query = 'title:' + title CourseRunFactory.create_batch(3, title=title) self.search_queryset = SearchQuerySet().models(CourseRun).raw_search(query).load_all() self.course_runs = [e.object for e in self.search_queryset] self.wrapper = SearchQuerySetWrapper(self.search_queryset)
def test_filter_by_hidden(self): """ Verify the endpoint filters course runs that are hidden. """ CourseRun.objects.all().delete() course_runs = CourseRunFactory.create_batch(3, course__partner=self.partner) hidden_course_runs = CourseRunFactory.create_batch(3, hidden=True, course__partner=self.partner) url = reverse('api:v1:course_run-list') self.assert_list_results(url, course_runs + hidden_course_runs) url = reverse('api:v1:course_run-list') + '?hidden=False' self.assert_list_results(url, course_runs)
def setUp(self): super(SearchQuerySetWrapperTests, self).setUp() title = 'Some random course' query = 'title:' + title CourseRunFactory.create_batch(3, title=title) self.search_queryset = SearchQuerySet().models(CourseRun).raw_search( query).load_all() self.course_runs = [e.object for e in self.search_queryset] self.wrapper = SearchQuerySetWrapper(self.search_queryset)
def setUp(self): super().setUp() title = 'Some random course' query = 'title:' + title CourseRunFactory.create_batch(3, title=title) self.search_queryset = CourseRunDocument().search().query( 'query_string', query=query) self.course_runs = [e.object for e in self.search_queryset] self.wrapper = SearchQuerySetWrapper(self.search_queryset)
def test_update_using_api(self): """ Verify endpoint successfully updates a program. """ program_data = self._program_data() response = self.client.post(self.list_path, program_data, format='json') assert response.status_code == 201 program = Program.objects.last() assert program.courses.count() == 3 assert program.authoring_organizations.count() == 3 assert program.credit_backing_organizations.count() == 3 program_detail_url = reverse('api:v1:program-detail', kwargs={'uuid': str(program.uuid)}) program.title = '{orignal_title} Test Update'.format(orignal_title=program_data['title']) program_data['status'] = 'unpublished' course_runs = CourseRunFactory.create_batch(2) course_runs = [course_run.key for course_run in course_runs] program_data['course_runs'] = program_data['course_runs'] + course_runs organizations = OrganizationFactory.create_batch(3) organizations = [organization.key for organization in organizations] program_data['authoring_organizations'] = program_data['authoring_organizations'] + organizations program_data['credit_backing_organizations'] = program_data['credit_backing_organizations'] + organizations data = json.dumps(program_data) response = self.client.patch(program_detail_url, data, content_type='application/json') assert response.status_code == 200 program = Program.objects.last() assert program.title == response.data['title'] assert program.status == response.data['status'] assert program.courses.count() == 5 assert program.authoring_organizations.count() == 6 assert program.credit_backing_organizations.count() == 6 course_runs = CourseRunFactory.create_batch(2) course_runs = [course_run.key for course_run in course_runs] course_runs.append(program_data['course_runs'][0]) program_data['course_runs'] = course_runs organizations = OrganizationFactory.create_batch(3) organizations = [organization.key for organization in organizations] organizations.append(program_data['authoring_organizations'][0]) program_data['authoring_organizations'] = organizations program_data['credit_backing_organizations'] = organizations data = json.dumps(program_data) response = self.client.patch(program_detail_url, data, content_type='application/json') assert response.status_code == 200 program = Program.objects.last() assert program.courses.count() == 3 assert program.authoring_organizations.count() == 4 assert program.credit_backing_organizations.count() == 4
def test_exclude_utm(self): request = make_request() course = CourseFactory() CourseRunFactory.create_batch(3, course=course) serializer = self.serializer_class(course, context={ 'request': request, 'exclude_utm': 1 }) self.assertEqual(serializer.data['marketing_url'], course.marketing_url)
def test_filter_by_keys(self): """ Verify the endpoint returns a list of course runs filtered by the specified keys. """ CourseRun.objects.all().delete() expected = CourseRunFactory.create_batch(3, course__partner=self.partner) keys = ','.join([course.key for course in expected]) url = '{root}?keys={keys}'.format(root=reverse('api:v1:course_run-list'), keys=keys) self.assert_list_results(url, expected)
def setUp(self): super(CreateCoursesTests, self).setUp() transcript_languages = LanguageTag.objects.all()[:2] self.subjects = SubjectFactory.create_batch(3) self.course = CourseFactory(subjects=self.subjects) 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. SeatFactory(course_run=canonical_course_run, type=seat_type) 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_sanity_check_success(self): """ Verify the command does not raise a CommandError error if the new index passes the sanity check. """ CourseRunFactory.create_batch(59) ProgramFactory.create_batch(59) PersonFactory.create_batch(59) record_count = 60 # Ensure that no error is raised and the sanity check passes the second time with mock.patch( 'course_discovery.apps.core.utils.ElasticsearchUtils.set_alias', return_value=True): with mock.patch( 'course_discovery.apps.edx_elasticsearch_dsl_extensions.management.commands.' 'update_index.Command.get_record_count', return_value=record_count): call_command('update_index')
def test_with_exclusions(self): """ Test serializer with course_run exclusions within program """ request = make_request() course = CourseFactory() excluded_runs = [] course_runs = CourseRunFactory.create_batch(2, course=course) excluded_runs.append(course_runs[0]) program = ProgramFactory(courses=[course], excluded_course_runs=excluded_runs) serializer_context = { 'request': request, 'program': program, 'course_runs': list(program.course_runs) } serializer = MinimalProgramCourseSerializer(course, context=serializer_context) expected = MinimalCourseSerializer(course, context=serializer_context).data expected['course_runs'] = MinimalCourseRunSerializer([course_runs[1]], many=True, context={ 'request': request }).data self.assertDictEqual(serializer.data, expected)
def test_sanity_check_error(self): """ Verify the command raises a CommandError if new index fails the sanity check. """ CourseRunFactory() additional_runs = int(100 * settings.INDEX_SIZE_CHANGE_THRESHOLD + 1) CourseRunFactory.create_batch(additional_runs) # Ensure that an error is raised if the sanity check does not pass with pytest.raises(CommandError): with mock.patch( 'course_discovery.apps.core.utils.ElasticsearchUtils.set_alias', return_value=True): with mock.patch( 'course_discovery.apps.edx_elasticsearch_dsl_extensions.management.commands.' 'update_index.Command.percentage_change', return_value=0.5): call_command('update_index')
def test_sanity_check_success(self): """ Verify the command does not raise a CommandError error if the new index passes the sanity check. """ CourseRunFactory.create_batch(30) record_count = 60 additional_runs = int(10 * settings.INDEX_SIZE_CHANGE_THRESHOLD - 1) CourseRunFactory.create_batch(additional_runs) # Ensure that no error is raised and the sanity check passes the second time with mock.patch( 'course_discovery.apps.edx_haystack_extensions.management.commands.' 'update_index.Command.set_alias', return_value=True): with mock.patch( 'course_discovery.apps.edx_haystack_extensions.management.commands.' 'update_index.Command.get_record_count', return_value=record_count): call_command('update_index')
def test_sanity_check_error(self): """ Verify the command raises a CommandError if new index fails the sanity check. """ CourseRunFactory() record_count = 2 additional_runs = int(100 * settings.INDEX_SIZE_CHANGE_THRESHOLD + 1) CourseRunFactory.create_batch(additional_runs) # Ensure that an error is raised if the sanity check does not pass with pytest.raises(CommandError): with mock.patch( 'course_discovery.apps.edx_haystack_extensions.management.commands.' 'update_index.Command.set_alias', return_value=True): with mock.patch( 'course_discovery.apps.edx_haystack_extensions.management.commands.' 'update_index.Command.get_record_count', return_value=record_count): call_command('update_index')
def test_list_key_filter(self): """ Verify the endpoint returns a list of course runs filtered by the specified keys. """ course_runs = CourseRunFactory.create_batch(3) course_runs = sorted(course_runs, key=lambda course: course.key.lower()) keys = ','.join([course.key for course in course_runs]) url = '{root}?keys={keys}'.format(root=reverse('api:v1:course_run-list'), keys=keys) response = self.client.get(url) self.assertListEqual(response.data['results'], self.serialize_course_run(course_runs, many=True))
def test_course_run_autocomplete(self, admin_client): course_runs = CourseRunFactory.create_batch(3) path = reverse('admin_metadata:course-run-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 run keys and titles course_run = course_runs[0] self.assert_valid_query_result(admin_client, path, course_run.key[14:], course_run) self.assert_valid_query_result(admin_client, path, course_run.title[12:], course_run) course = course_run.course CourseRunFactory.create_batch(3, course=course) response = admin_client.get(path + '?forward={f}'.format(f=json.dumps({'course': course.pk}))) data = json.loads(response.content.decode('utf-8')) assert response.status_code == 200 assert len(data['results']) == 4
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 setUp(self): super(ImportCoursesTests, self).setUp() self.course = CourseFactory() self.course_runs = CourseRunFactory.create_batch(3, course=self.course) self.course.canonical_course_run = self.course_runs[2] self.course.save() # add multiple courses. self.course_2 = CourseFactory() self.command_name = 'import_metadata_courses' self.command_args = ['--start_id={}'.format(self.course.id), '--end_id={}'.format(self.course.id)]
def test_list_query(self): """ Verify the endpoint returns a filtered list of courses """ title = 'Some random title' course_runs = CourseRunFactory.create_batch(3, title=title) CourseRunFactory(title='non-matching name') query = 'title:' + title url = '{root}?q={query}'.format(root=reverse('api:v1:course_run-list'), query=query) response = self.client.get(url) actual_sorted = sorted(response.data['results'], key=lambda course_run: course_run['key']) expected_sorted = sorted(self.serialize_course_run(course_runs, many=True), key=lambda course_run: course_run['key']) self.assertListEqual(actual_sorted, expected_sorted)
def test_list_query(self): """ Verify the endpoint returns a filtered list of courses """ course_runs = CourseRunFactory.create_batch(3, title='Some random title', course__partner=self.partner) CourseRunFactory(title='non-matching name') query = 'title:Some random title' url = '{root}?q={query}'.format(root=reverse('api:v1:course_run-list'), query=query) with self.assertNumQueries(39): response = self.client.get(url) actual_sorted = sorted(response.data['results'], key=lambda course_run: course_run['key']) expected_sorted = sorted(self.serialize_course_run(course_runs, many=True), key=lambda course_run: course_run['key']) self.assertListEqual(actual_sorted, expected_sorted)
def _program_data(self): course_runs = CourseRunFactory.create_batch(3) organizations = OrganizationFactory.create_batch(3) return { "title": "Test Program", "type": "XSeries", "status": "active", "marketing_slug": "edX-test-program", "course_runs": [course_run.key for course_run in course_runs], "min_hours_effort_per_week": 10, "max_hours_effort_per_week": 20, "authoring_organizations": [organization.key for organization in organizations], "credit_backing_organizations": [organization.key for organization in organizations], }
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_with_exclusions(self): """ Test serializer with course_run exclusions within program """ request = make_request() course = CourseFactory() excluded_runs = [] course_runs = CourseRunFactory.create_batch(2, course=course) excluded_runs.append(course_runs[0]) program = ProgramFactory(courses=[course], excluded_course_runs=excluded_runs) serializer_context = {'request': request, 'program': program, 'course_runs': list(program.course_runs)} serializer = MinimalProgramCourseSerializer(course, context=serializer_context) expected = MinimalCourseSerializer(course, context=serializer_context).data expected['course_runs'] = MinimalCourseRunSerializer( [course_runs[1]], many=True, context={'request': request}).data self.assertDictEqual(serializer.data, expected)
def test_ensure_draft_world_not_draft_course_given(self): course = CourseFactory() entitlement = CourseEntitlementFactory(course=course) course.entitlements.add(entitlement) course_runs = CourseRunFactory.create_batch(3, course=course) for run in course_runs: course.course_runs.add(run) course.canonical_course_run = course_runs[0] course.save() org = OrganizationFactory() course.authoring_organizations.add(org) # pylint: disable=no-member ensured_draft_course = utils.ensure_draft_world(course) not_draft_course = Course.objects.get(uuid=course.uuid) self.assertNotEqual(ensured_draft_course, not_draft_course) self.assertEqual(ensured_draft_course.uuid, not_draft_course.uuid) self.assertTrue(ensured_draft_course.draft) # Check slugs are equal self.assertEqual(ensured_draft_course.slug, not_draft_course.slug) # Check authoring orgs are equal self.assertEqual( list(ensured_draft_course.authoring_organizations.all()), list(not_draft_course.authoring_organizations.all())) # Check canonical course run was updated self.assertNotEqual(ensured_draft_course.canonical_course_run, not_draft_course.canonical_course_run) self.assertTrue(ensured_draft_course.canonical_course_run.draft) self.assertEqual(ensured_draft_course.canonical_course_run.uuid, not_draft_course.canonical_course_run.uuid) # Check course runs all share the same UUIDs, but are now all drafts not_draft_course_runs_uuids = [run.uuid for run in course_runs] draft_course_runs_uuids = [ run.uuid for run in ensured_draft_course.course_runs.all() ] self.assertListEqual(draft_course_runs_uuids, not_draft_course_runs_uuids) # Entitlement checks draft_entitlement = ensured_draft_course.entitlements.first() not_draft_entitlement = not_draft_course.entitlements.first() self.assertNotEqual(draft_entitlement, not_draft_entitlement) self.assertEqual(draft_entitlement.price, not_draft_entitlement.price) self.assertEqual(draft_entitlement.sku, not_draft_entitlement.sku) self.assertNotEqual(draft_entitlement.course, not_draft_entitlement.course) self.assertEqual(draft_entitlement.course.uuid, not_draft_entitlement.course.uuid) # Check official and draft versions match up self.assertEqual(ensured_draft_course.official_version, not_draft_course) self.assertEqual(not_draft_course.draft_version, ensured_draft_course) self.assertEqual(draft_entitlement.official_version, not_draft_entitlement) self.assertEqual(not_draft_entitlement.draft_version, draft_entitlement)