def setUp(self): super().setUp() self.org = OrganizationFactory(name='MyOrg', key='myorg') self.course_run = CourseRunFactory(draft=True, title_override='MyCourse') self.course = self.course_run.course self.course.authoring_organizations.add(self.org) self.partner = self.course.partner self.group = GroupFactory() self.pc = self.make_user(email='*****@*****.**') self.editor = self.make_user(groups=[self.group]) self.editor2 = self.make_user(groups=[self.group]) self.non_editor = self.make_user(groups=[self.group]) self.legal = self.make_user( groups=[Group.objects.get(name=LEGAL_TEAM_GROUP_NAME)]) CourseEditorFactory(user=self.editor, course=self.course) CourseEditorFactory(user=self.editor2, course=self.course) OrganizationExtensionFactory(group=self.group, organization=self.org) OrganizationUserRoleFactory(user=self.pc, organization=self.org, role=InternalUserRole.ProjectCoordinator) self.publisher_url = '{}courses/{}'.format(self.partner.publisher_url, self.course_run.course.uuid) self.studio_url = '{}course/{}'.format(self.partner.studio_url, self.course_run.key) self.admin_url = 'https://{}/admin/course_metadata/courserun/{}/change/'.format( self.partner.site.domain, self.course_run.id) self.run_num = CourseKey.from_string(self.course_run.key).run
def test_typeahead_org_course_runs_come_up_first(self): """ Test typeahead response to ensure org is taken into account. """ MITx = OrganizationFactory(key='MITx') HarvardX = OrganizationFactory(key='HarvardX') mit_run = CourseRunFactory( authoring_organizations=[MITx, HarvardX], title='MIT Testing1', course__partner=self.partner ) harvard_run = CourseRunFactory( authoring_organizations=[HarvardX], title='MIT Testing2', course__partner=self.partner ) mit_program = ProgramFactory( authoring_organizations=[MITx, HarvardX], title='MIT Testing1', partner=self.partner ) harvard_program = ProgramFactory( authoring_organizations=[HarvardX], title='MIT Testing2', partner=self.partner ) response = self.get_response({'q': 'mit'}) self.assertEqual(response.status_code, 200) expected = { 'course_runs': [self.serialize_course_run_search(mit_run), self.serialize_course_run_search(harvard_run)], 'programs': [self.serialize_program_search(mit_program), self.serialize_program_search(harvard_program)] } self.assertDictEqual(response.data, expected)
def test_process_node_not_whitelisted(self): # Set the end date in the future data = mock_data.UNIQUE_MARKETING_SITE_API_COURSE_BODIES[0] data['field_course_end_date'] = datetime.datetime.max.strftime('%s') OrganizationFactory.create( uuid=data.get('field_course_school_node', {})[0].get('uuid')) config = DrupalLoaderConfigFactory.create( course_run_ids='SomeFakeCourseRunId', partner_code=self.partner.short_code, load_unpublished_course_runs=False) data_loader = DrupalCourseMarketingSiteDataLoader( self.partner, self.partner.marketing_site_url_root, ACCESS_TOKEN, 'JWT', 1, # Make this a constant of 1 for no concurrency False, set(config.course_run_ids.split(',')), config.load_unpublished_course_runs) # Need to mock this method so that the GET isn't sent out to the test data server with mock.patch( 'course_discovery.apps.publisher.dataloader.create_courses.' 'transfer_course_image'): for body in mock_data.UNIQUE_MARKETING_SITE_API_COURSE_BODIES: data_loader.process_node(body) # Even after looping through all course bodies no new rows should be created course_metadata_course_run = CourseMetadataCourseRun.objects.filter( key=data.get('field_course_id')) self.assertEqual(course_metadata_course_run.count(), 0)
def test_process_node(self): # Set the end date in the future data = mock_data.UNIQUE_MARKETING_SITE_API_COURSE_BODIES[0] data['field_course_end_date'] = datetime.datetime.max.strftime('%s') OrganizationFactory.create( uuid=data.get('field_course_school_node', {})[0].get('uuid')) config = DrupalLoaderConfigFactory.create( course_run_ids=data.get('field_course_id'), partner_code=self.partner.short_code, load_unpublished_course_runs=False) data_loader = DrupalCourseMarketingSiteDataLoader( self.partner, self.partner.marketing_site_url_root, ACCESS_TOKEN, 'JWT', 1, # Make this a constant of 1 for no concurrency False, set(config.course_run_ids.split(',')), config.load_unpublished_course_runs) # Need to mock this method so that the GET isn't sent out to the test data server with mock.patch( 'course_discovery.apps.publisher.dataloader.create_courses.' 'transfer_course_image'): data_loader.process_node( mock_data.UNIQUE_MARKETING_SITE_API_COURSE_BODIES[0]) course_metadata_course_run = CourseMetadataCourseRun.objects.get( key=data.get('field_course_id')) self.assertIsNotNone(course_metadata_course_run) self.assertIsNotNone(course_metadata_course_run.course) publisher_course_run = PublisherCourseRun.objects.get( lms_course_id=course_metadata_course_run.key) self.assertIsNotNone(publisher_course_run) self.assertIsNotNone(publisher_course_run.course)
def setUp(self): super(TestMigrateCommentsToSalesforce, self).setUp() self.partner = PartnerFactory() self.user_1 = UserFactory() self.org_1 = OrganizationFactory(partner=self.partner) self.course_1 = CourseFactory( partner=self.partner, authoring_organizations=[self.org_1], key=self.org_1.key + '+101x', title='Old Title', ) self.course_run_1 = CourseRunFactory( key='course-v1:{key}+1T2019'.format( key=self.course_1.key, ), course=self.course_1, ) self.publisher_course_1 = PublisherCourseFactory(number='101x', title='New Title') self.publisher_course_1.organizations.add(self.org_1) # pylint: disable=no-member self.publisher_course_run_1 = PublisherCourseRunFactory( course=self.publisher_course_1, lms_course_id='course-v1:{org}+{number}+1T2019'.format( org=self.org_1.key, number=self.publisher_course_1.number ), )
def test_list_not_staff(self): """ Verify the endpoint returns a list of all organizations. """ org1 = OrganizationFactory.create(partner=self.partner) org2 = OrganizationFactory.create(partner=self.partner) OrganizationFactory.create(partner=self.partner) extension1 = publisher_factories.OrganizationExtensionFactory( organization=org1) publisher_factories.OrganizationExtensionFactory(organization=org2) assign_perm(OrganizationExtension.VIEW_COURSE, extension1.group, extension1) self.non_staff_user.groups.add(extension1.group) # Check Staff user get all groups response = self.client.get(self.list_path) assert response.status_code == 200 self.assert_response_data_valid(response, Organization.objects.all()) # Check non staff user gets 1 group self.client.logout() self.client.login(username=self.non_staff_user.username, password=USER_PASSWORD) response = self.client.get(self.list_path) assert response.status_code == 200 self.assert_response_data_valid(response, [org1])
def test_retrieve_not_staff(self): """ Verify the endpoint returns a list of all organizations. """ org1 = OrganizationFactory.create(partner=self.partner) org2 = OrganizationFactory.create(partner=self.partner) OrganizationFactory.create(partner=self.partner) url = reverse('api:v1:organization-detail', kwargs={'uuid': org2.uuid}) extension1 = publisher_factories.OrganizationExtensionFactory( organization=org1) publisher_factories.OrganizationExtensionFactory(organization=org2) assign_perm(OrganizationExtension.VIEW_COURSE, extension1.group, extension1) self.non_staff_user.groups.add(extension1.group) # Check Staff user get all groups response = self.client.get(url) assert response.status_code == 200 self.assert_response_data_valid(response, org2, many=False) # Check non staff user gets 1 group self.client.logout() self.client.login(username=self.non_staff_user.username, password=USER_PASSWORD) response = self.client.get(url) assert response.status_code == 404 url = reverse('api:v1:organization-detail', kwargs={'uuid': org1.uuid}) response = self.client.get(url) assert response.status_code == 200 self.assert_response_data_valid(response, org1, many=False)
def test_list(self): """ Verify the endpoint returns a list of all organizations. """ OrganizationFactory.create_batch(3, partner=self.partner) with self.assertNumQueries(7): response = self.client.get(self.list_path) assert response.status_code == 200 self.assert_response_data_valid(response, Organization.objects.all())
def test_list(self): """ Verify the endpoint returns a list of all organizations. """ OrganizationFactory.create_batch(3) with self.assertNumQueries(6): response = self.client.get(self.list_path) self.assertEqual(response.status_code, 200) self.assert_response_data_valid(response, Organization.objects.all())
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 setUp(self): super().setUp() self.partner = PartnerFactory(short_code="testx") self.organization = OrganizationFactory(partner=self.partner, name="testx") self.logo = mock.MagicMock(spec=File, name="logo") self.logo.name = "logo" self.certificate_logo = mock.MagicMock(spec=File, name="certificate_logo") self.certificate_logo.name = "certificate_logo" self.banner_image = mock.MagicMock(spec=File, name="banner_image") self.banner_image.name = "banner image"
def test_200(self): self.login_staff() org1 = OrganizationFactory() org2 = OrganizationFactory() program1 = self.create_program([org1]) program2 = self.create_program([org2]) program12 = self.create_program([org1, org2]) programs = [program1, program2, program12] uuids = [program.uuid for program in programs] response = self.get(uuids) self.assertEqual(response.status_code, 200) fixture = json.loads(response.content.decode('utf-8')) # To make this tests less brittle, allow (inclusive) ranges for each model count. # For some models (e.g. Course) we DO care about the exact count. # For others (e.g. Video) we just want to make sure that they are there, # but that we're not loading a crazy amount of them. expected_count_ranges_by_model = { Organization: (2, 2), Program: (3, 3), Curriculum: (3, 3), Course: (9, 9), CourseRun: (12, 12), CurriculumCourseMembership: (6, 6), CurriculumCourseRunExclusion: (3, 3), ProgramType: (1, 1), SeatType: (1, 1), AdditionalPromoArea: (5, 15), Image: (20, 60), LevelType: (5, 15), Video: (20, 60), LanguageTag: (10, 30), } actual_appearances_by_model_label = defaultdict(set) for record in fixture: pk = record['pk'] model_label = record['model'] # Assert no duplicate objects self.assertNotIn(pk, actual_appearances_by_model_label[model_label]) actual_appearances_by_model_label[model_label].add(pk) for model, (min_expected, max_expected) in expected_count_ranges_by_model.items(): model_label = model._meta.label_lower actual_count = len(actual_appearances_by_model_label[model_label]) err_string = "object count of {} for {} outside expected range [{}, {}]".format( actual_count, model_label, min_expected, max_expected) self.assertGreaterEqual(actual_count, min_expected, err_string) self.assertLessEqual(actual_count, max_expected, err_string)
class AddLogosToOrganizationTest(TestCase): def setUp(self): super().setUp() self.partner = PartnerFactory(short_code="testx") self.organization = OrganizationFactory(partner=self.partner, name="testx") self.logo = mock.MagicMock(spec=File, name="logo") self.logo.name = "logo" self.certificate_logo = mock.MagicMock(spec=File, name="certificate_logo") self.certificate_logo.name = "certificate_logo" self.banner_image = mock.MagicMock(spec=File, name="banner_image") self.banner_image.name = "banner image" def test_partner_not_found(self): with pytest.raises(Exception): call_command(Command()) def test_image_paths_not_found(self): with pytest.raises(Exception): call_command( Command(), partner="testx", ) @pytest.mark.django_db def test_two_organizations_with_same_partner_returns_correct_org(self): new_org = OrganizationFactory(partner=self.partner, name="notx") assert len(Organization.objects.all()) > 1 self.organization.logo_image = None new_org.logo_image = None with mock.patch( "course_discovery.apps.course_metadata.management.commands.add_logos_to_organization.Command._open_assets", return_value={ "logo": self.logo, "certificate_logo": self.certificate_logo, "banner_image": self.banner_image, }, ): call_command( Command(), partner="testx", logo="/", certificate_logo="/", banner_image="/", ) self.organization.refresh_from_db() assert "/media/organization/logos/" in self.organization.logo_image.path
def test_ingest_respects_partner(self): """ Existing organizations with the same key but linked to different partners shouldn't cause organization data loading to fail. """ api_data = self.mock_api() key = api_data[1]['short_name'] OrganizationFactory(key=key, partner=self.partner) OrganizationFactory(key=key) assert Organization.objects.count() == 2 self.loader.ingest() assert Organization.objects.count() == len(api_data) + 1
def test_404_nonexistent(self): self.login_staff() program = self.create_program([OrganizationFactory()]) bad_uuid = 'e9222eb7-7218-4a8b-9dff-b42bafbf6ed7' with self.assertNumQueries(self.queries(1)): response = self.get([program.uuid, bad_uuid]) self.assertEqual(response.status_code, 404)
def test_create_course_run_in_studio_as_rerun(self, mock_access_token): # pylint: disable=unused-argument number = 'TestX' organization = OrganizationFactory() partner = organization.partner course_key = '{org}+{number}'.format(org=organization.key, number=number) discovery_course_run = DiscoveryCourseRunFactory( course__partner=partner, course__key=course_key) start = datetime.datetime.utcnow() course_run_key = 'course-v1:TestX+Testing101x+1T2017' body = {'id': course_run_key} studio_url_root = partner.studio_url.strip('/') url = '{root}/api/v1/course_runs/{course_run_key}/rerun/'.format( root=studio_url_root, course_run_key=discovery_course_run.key) responses.add(responses.POST, url, json=body, status=200) body = {'card_image': 'https://example.com/image.jpg'} url = '{root}/api/v1/course_runs/{course_run_key}/images/'.format( root=studio_url_root, course_run_key=course_run_key) responses.add(responses.POST, url, json=body, status=200) publisher_course_run = CourseRunFactory( start=start, lms_course_id=None, course__organizations=[organization], course__number=number) # We refresh because the signal should update the instance with the course run key from Studio publisher_course_run.refresh_from_db() assert len(responses.calls) == 2 assert publisher_course_run.lms_course_id == course_run_key
def test_search_single(self): org = OrganizationFactory() course = CourseFactory(authoring_organizations=[org]) person1 = PersonFactory(partner=self.partner) person2 = PersonFactory(partner=self.partner) PersonFactory(partner=self.partner) CourseRunFactory(staff=[person1, person2], course=course) facet_name = 'organizations_exact:{org_key}'.format(org_key=org.key) self.reindex_people(person1) self.reindex_people(person2) query = {'selected_facets': facet_name} qs = urllib.parse.urlencode(query) url = '{path}?{qs}'.format(path=self.path, qs=qs) response = self.client.get(url) self.assertEqual(response.status_code, 200) response_data = response.json() self.assertEqual(response_data['objects']['count'], 2) query = {'selected_facets': facet_name, 'q': person1.uuid} qs = urllib.parse.urlencode(query) url = '{path}?{qs}'.format(path=self.path, qs=qs) response = self.client.get(url) self.assertEqual(response.status_code, 200) response_data = response.json() self.assertEqual(response_data['objects']['count'], 1) self.assertEqual(response_data['objects']['results'][0]['uuid'], str(person1.uuid)) self.assertEqual(response_data['objects']['results'][0]['full_name'], person1.full_name)
def test_publish_with_additional_organization(self, mock_access_token): """ Test that the publish button does not remove existing organization """ publisher_course_run = self._create_course_run_for_publication() partner = publisher_course_run.course.organizations.first().partner self._set_test_client_domain_and_login(partner) self._mock_studio_api_success(publisher_course_run) self._mock_ecommerce_api(publisher_course_run) publish_url = reverse('publisher:api:v1:course_run-publish', kwargs={'pk': publisher_course_run.pk}) response = self.client.post(publish_url, {}) assert response.status_code == 200 discovery_course_run = CourseRun.objects.get( key=publisher_course_run.lms_course_id) publisher_course = publisher_course_run.course discovery_course = discovery_course_run.course assert discovery_course.authoring_organizations.all().count() == 1 publisher_course.organizations.add(OrganizationFactory()) response = self.client.post(publish_url, {}) assert response.status_code == 200 assert discovery_course.authoring_organizations.all().count() == 2
def test_create_course_run_in_studio_with_image_api_failure( self, mock_access_token): organization = OrganizationFactory() partner = organization.partner start = datetime.datetime.utcnow() course_run_key = 'course-v1:TestX+Testing101x+1T2017' body = {'id': course_run_key} studio_url_root = partner.studio_url.strip('/') url = '{}/api/v1/course_runs/'.format(studio_url_root) responses.add(responses.POST, url, json=body, status=200) body = {'error': 'Server error'} url = '{root}/api/v1/course_runs/{course_run_key}/images/'.format( root=studio_url_root, course_run_key=course_run_key) responses.add(responses.POST, url, json=body, status=500) with mock.patch( 'course_discovery.apps.publisher.signals.logger.exception' ) as mock_logger: publisher_course_run = CourseRunFactory( start=start, lms_course_id=None, course__organizations=[organization]) assert len(responses.calls) == 2 assert publisher_course_run.lms_course_id == course_run_key mock_logger.assert_called_with( 'Failed to update Studio image for course run [%s]: %s', course_run_key, json.dumps(body).encode('utf8'))
def setUp(self): super(PublisherCustomCourseFormTests, self).setUp() self.course_form = CourseForm() self.organization = OrganizationFactory() self.course = CourseFactory(title='Test', number='a123', organizations=[self.organization])
def setUp(self): super(AutoCompletePersonTests, self).setUp() self.user = UserFactory(is_staff=True) self.client.login(username=self.user.username, password=USER_PASSWORD) first_instructor = PersonFactory(given_name="First", family_name="Instructor") second_instructor = PersonFactory(given_name="Second", family_name="Instructor") self.instructors = [first_instructor, second_instructor] self.organizations = OrganizationFactory.create_batch(3) self.organization_extensions = [] for instructor in self.instructors: PositionFactory(organization=self.organizations[0], title="professor", person=instructor) for organization in self.organizations: org_ex = publisher_factories.OrganizationExtensionFactory( organization=organization) self.organization_extensions.append(org_ex) disco_course = CourseFactory( authoring_organizations=[self.organizations[0]]) disco_course2 = CourseFactory( authoring_organizations=[self.organizations[1]]) CourseRunFactory(course=disco_course, staff=[first_instructor]) CourseRunFactory(course=disco_course2, staff=[second_instructor]) self.user.groups.add(self.organization_extensions[0].group)
def test_partner(self): """ Verify that the wrapper can return partner values. """ organization = OrganizationFactory() self.course.organizations.add(organization) partner = "/".join( [org.key for org in self.course_run.course.organizations.all()]) self.assertEqual(self.wrapped_course_run.partner, partner)
def test_organization_key(self): """ Verify that the wrapper return the organization key. """ organization = OrganizationFactory() course_run = factories.CourseRunFactory( course__organizations=[organization]) wrapped_course_run = CourseRunWrapper(course_run) self.assertEqual(wrapped_course_run.organization_key, organization.key)
def test_do_not_index_if_not_active(self): unpublished_program = AlgoliaProxyProgramFactory(partner=self.__class__.edxPartner, status=ProgramStatus.Unpublished) unpublished_program.authoring_organizations.add(OrganizationFactory()) retired_program = AlgoliaProxyProgramFactory(partner=self.__class__.edxPartner, status=ProgramStatus.Retired) retired_program.authoring_organizations.add(OrganizationFactory()) deleted_program = AlgoliaProxyProgramFactory(partner=self.__class__.edxPartner, status=ProgramStatus.Deleted) deleted_program.authoring_organizations.add(OrganizationFactory()) assert not unpublished_program.should_index assert not retired_program.should_index assert not deleted_program.should_index
def test_create_course_run_in_studio_with_image_failure(self, __, ___): # pylint: disable=unused-argument organization = OrganizationFactory() partner = organization.partner start = datetime.datetime.utcnow() course_run_key = 'course-v1:TestX+Testing101x+1T2017' body = {'id': course_run_key} studio_url_root = partner.studio_url.strip('/') url = '{}/api/v1/course_runs/'.format(studio_url_root) responses.add(responses.POST, url, json=body, status=200) with mock.patch( 'course_discovery.apps.publisher.signals.logger.exception' ) as mock_logger: publisher_course_run = CourseRunFactory( start=start, lms_course_id=None, course__organizations=[organization]) assert len(responses.calls) == 1 assert publisher_course_run.lms_course_id == course_run_key mock_logger.assert_called_with( 'Failed to update Studio image for course run [%s]', course_run_key)
def setUp(self): super(CourseRunMarkAsReviewedEmailTests, self).setUp() self.user = UserFactory() self.user_2 = UserFactory() self.user_3 = UserFactory() self.seat = factories.SeatFactory() self.course_run = self.seat.course_run self.course = self.course_run.course self.course.organizations.add(OrganizationFactory()) # add user in course-user-role table factories.CourseUserRoleFactory(course=self.course, role=PublisherUserRole.CourseTeam, user=self.user_2) factories.CourseUserRoleFactory(course=self.course, role=PublisherUserRole.Publisher, user=self.user_3) self.course_run_state = factories.CourseRunStateFactory( course_run=self.course_run) self.course_run.lms_course_id = 'course-v1:edX+DemoX+Demo_Course' self.course_run.save() toggle_switch('enable_publisher_email_notifications', True)
def setUp(self): super(AutoCompletePersonTests, self).setUp() self.user = UserFactory(is_staff=True) self.client.login(username=self.user.username, password=USER_PASSWORD) self.courses = factories.CourseFactory.create_batch( 3, title='Some random course title') for course in self.courses: factories.CourseRunFactory(course=course) self.organizations = OrganizationFactory.create_batch(3) self.organization_extensions = [] for organization in self.organizations: self.organization_extensions.append( factories.OrganizationExtensionFactory( organization=organization)) self.user.groups.add(self.organization_extensions[0].group) first_instructor = PersonFactory(given_name="First", family_name="Instructor") second_instructor = PersonFactory(given_name="Second", family_name="Instructor") self.instructors = [first_instructor, second_instructor] for instructor in self.instructors: PositionFactory(organization=self.organizations[0], title="professor", person=instructor)
def test_do_not_index_if_active_course_run_is_hidden(self): course = self.create_course_with_basic_active_course_run() course.authoring_organizations.add(OrganizationFactory()) for course_run in course.course_runs.all(): course_run.hidden = True course_run.save() assert not course.should_index
def test_do_not_index_if_no_url_slug(self): course = self.create_course_with_basic_active_course_run() course.authoring_organizations.add(OrganizationFactory()) for url_slug in course.url_slug_history.all(): url_slug.is_active = False url_slug.save() assert not course.should_index
def setUpClass(cls): super().setUpClass() cls.user = UserFactory(is_staff=True) 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) for organization in cls.organizations: cls.organization_extensions.append( 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 test_create_course_run_in_studio(self, mock_access_token): # pylint: disable=unused-argument organization = OrganizationFactory() partner = organization.partner start = datetime.datetime.utcnow() course_run_key = 'course-v1:TestX+Testing101x+1T2017' body = {'id': course_run_key} studio_url_root = partner.studio_url.strip('/') url = '{}/api/v1/course_runs/'.format(studio_url_root) responses.add(responses.POST, url, json=body, status=200) body = {'card_image': 'https://example.com/image.jpg'} url = '{root}/api/v1/course_runs/{course_run_key}/images/'.format( root=studio_url_root, course_run_key=course_run_key) responses.add(responses.POST, url, json=body, status=200) with mock.patch( 'course_discovery.apps.publisher.signals.logger.exception' ) as mock_logger: publisher_course_run = CourseRunFactory( start=start, lms_course_id=None, course__organizations=[organization]) # We refresh because the signal should update the instance with the course run key from Studio publisher_course_run.refresh_from_db() assert len(responses.calls) == 2 assert publisher_course_run.lms_course_id == course_run_key mock_logger.assert_called_with( 'Organization [%s] does not have an associated OrganizationExtension', organization.key, )
def test_list_uuid_filter(self): """ Verify the endpoint returns a list of organizations filtered by UUID. """ organizations = OrganizationFactory.create_batch(3) # Test with a single UUID self.assert_list_uuid_filter([organizations[0]]) # Test with multiple UUIDs self.assert_list_uuid_filter(organizations)
def test_data(self): authoring_organization, crediting_organization = OrganizationFactory.create_batch(2) program = ProgramFactory(authoring_organizations=[authoring_organization], credit_backing_organizations=[crediting_organization]) # NOTE: This serializer expects SearchQuerySet results, so we run a search on the newly-created object # to generate such a result. result = SearchQuerySet().models(Program).filter(uuid=program.uuid)[0] serializer = ProgramSearchSerializer(result) expected = self._create_expected_data(program) self.assertDictEqual(serializer.data, expected)
def test_typeahead_authoring_organizations_partial_search(self): """ Test typeahead response with partial organization matching. """ authoring_organizations = OrganizationFactory.create_batch(3) course_run = CourseRunFactory(authoring_organizations=authoring_organizations, course__partner=self.partner) program = ProgramFactory(authoring_organizations=authoring_organizations, partner=self.partner) partial_key = authoring_organizations[0].key[0:5] response = self.get_typeahead_response(partial_key) self.assertEqual(response.status_code, 200) expected = { 'course_runs': [self.serialize_course_run(course_run)], 'programs': [self.serialize_program(program)] } self.assertDictEqual(response.data, expected)
def test_typeahead_multiple_authoring_organizations(self): """ Test typeahead response with multiple authoring organizations. """ title = "Design" authoring_organizations = OrganizationFactory.create_batch(3) course_run = CourseRunFactory( title=title, authoring_organizations=authoring_organizations, course__partner=self.partner ) program = ProgramFactory( title=title, authoring_organizations=authoring_organizations, status=ProgramStatus.Active, partner=self.partner ) response = self.get_typeahead_response(title) self.assertEqual(response.status_code, 200) response_data = response.json() self.assertDictEqual(response_data, {'course_runs': [self.serialize_course_run(course_run)], 'programs': [self.serialize_program(program)]})
def test_list_tag_filter(self): """ Verify the endpoint returns a list of organizations filtered by tag. """ tag = 'test-org' organizations = OrganizationFactory.create_batch(2) # If no organizations have been tagged, the endpoint should not return any data self.assert_list_tag_filter([], [tag], expected_query_count=4) # Tagged organizations should be returned organizations[0].tags.add(tag) self.assert_list_tag_filter([organizations[0]], [tag]) # The endpoint should support filtering by multiple tags. The filter should be an OR filter, meaning the results # include any organization containing at least one of the given tags. tag2 = 'another-tag' organizations[1].tags.add(tag) self.assert_list_tag_filter(Organization.objects.all(), [tag, tag2])
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_data_multiple_authoring_organizations(self): authoring_organizations = OrganizationFactory.create_batch(3) program = ProgramFactory(authoring_organizations=authoring_organizations) serialized_program = self.serialize_program(program) expected = [org.key for org in authoring_organizations] self.assertEqual(serialized_program.data['orgs'], expected)