def setUp(self): """ Test set up. """ super(TestEnterpriseCustomerReportingConfigAdminForm, self).setUp() self.ent_customer1 = EnterpriseCustomerFactory() self.ent_customer2 = EnterpriseCustomerFactory() self.ent_catalogs1 = [ EnterpriseCustomerCatalogFactory( enterprise_customer=self.ent_customer1) for _ in range(3) ] self.ent_catalogs2 = [ EnterpriseCustomerCatalogFactory( enterprise_customer=self.ent_customer2) for _ in range(2) ] self.form_data = { 'enterprise_customer': self.ent_customer1.uuid, 'data_type': 'progress', 'report_type': 'csv', 'delivery_method': 'email', 'frequency': 'daily', 'hour_of_day': 1, 'email': '*****@*****.**', 'decrypted_password': '******', }
def test_delete_catalog(self, api_client_mock): enterprise_catalog = EnterpriseCustomerCatalogFactory() enterprise_catalog_uuid = enterprise_catalog.uuid api_client_mock.return_value.get_enterprise_catalog.return_value = True enterprise_catalog.delete() # Verify the API was called correctly and the catalog was deleted api_client_mock.return_value.delete_enterprise_catalog.assert_called_with(enterprise_catalog_uuid) self.assertFalse(EnterpriseCustomerCatalog.objects.exists())
def test_get_course_specific_consent_improperly_configured_course_catalog( self, course_catalog_api_client_mock, *args): # pylint: disable=unused-argument,invalid-name course_id = 'course-v1:edX+DemoX+Demo_Course' course_catalog_api_client_mock.side_effect = ImproperlyConfigured( "There is no active CatalogIntegration.") self._login() enterprise_customer = EnterpriseCustomerFactory( name='Starfleet Academy', enable_data_sharing_consent=True, enforce_data_sharing_consent='at_enrollment', ) content_filter = { 'key': [ course_id, ] } EnterpriseCustomerCatalogFactory( enterprise_customer=enterprise_customer, content_filter=content_filter) ecu = EnterpriseCustomerUserFactory( user_id=self.user.id, enterprise_customer=enterprise_customer) EnterpriseCourseEnrollment.objects.create(enterprise_customer_user=ecu, course_id=course_id) params = { 'course_id': course_id, 'enterprise_customer_uuid': str(enterprise_customer.uuid), 'next': 'https://google.com', 'failure_url': 'https://facebook.com', 'defer_creation': True, } with mock.patch('enterprise.views.render') as mock_render: mock_render.return_value = HttpResponse() self.client.get(self.url, data=params) assert mock_render.call_args_list[0][1]['status'] == 404
def test_no_response_doesnt_get_cached(self): """ Response doesn't get cached when empty. """ EnterpriseCustomerCatalogFactory( enterprise_customer=self.enterprise_customer, ) enterprise_catalog_uuid = str( self.enterprise_customer.enterprise_customer_catalogs.first().uuid) api_resource_name = 'enterprise_catalogs' cache_key = get_cache_key( resource=api_resource_name, querystring={}, traverse_pagination=False, resource_id=enterprise_catalog_uuid, ) cached_enterprise_api_response = cache.get(cache_key) assert cached_enterprise_api_response is None self.mock_empty_response('enterprise-catalogs-detail', enterprise_catalog_uuid) client = enterprise_api.EnterpriseApiClient(self.user) response = client._load_data( # pylint: disable=protected-access resource=api_resource_name, resource_id=enterprise_catalog_uuid, ) assert not response # The empty response is not cached. cached_api_response = cache.get(cache_key) assert not cached_api_response
def test_handle_consent_enrollment_with_professional_course_mode( self, registry_mock, enrollment_api_client_mock, track_enrollment_mock, *args ): # pylint: disable=unused-argument """ Verify that user is redirected to course in case the provided course mode is audit track. """ course_id = self.demo_course_id enterprise_customer = EnterpriseCustomerFactory( name='Starfleet Academy', enable_data_sharing_consent=True, enforce_data_sharing_consent='at_enrollment', enable_audit_enrollment=True, ) enterprise_catalog = EnterpriseCustomerCatalogFactory(enterprise_customer=enterprise_customer) faker = FakerFactory.create() provider_id = faker.slug() # pylint: disable=no-member self._setup_registry_mock(registry_mock, provider_id) EnterpriseCustomerIdentityProviderFactory(provider_id=provider_id, enterprise_customer=enterprise_customer) enterprise_customer_user = EnterpriseCustomerUserFactory( user_id=self.user.id, enterprise_customer=enterprise_customer ) enrollment_client = enrollment_api_client_mock.return_value enrollment_client.get_course_modes.return_value = self.dummy_demo_course_modes self._login() handle_consent_enrollment_url = self._append_fresh_login_param( '{consent_enrollment_url}?{params}'.format( consent_enrollment_url=reverse( 'enterprise_handle_consent_enrollment', args=[enterprise_customer.uuid, course_id] ), params=urlencode({ 'course_mode': 'professional', 'catalog': enterprise_catalog.uuid }) ) ) response = self.client.get(handle_consent_enrollment_url) redirect_url = LMS_START_PREMIUM_COURSE_FLOW_URL.format(course_id=course_id) redirect_url += '?catalog={catalog_uuid}'.format( catalog_uuid=enterprise_catalog.uuid ) self.assertRedirects(response, redirect_url, fetch_redirect_response=False) self.assertTrue(EnterpriseCourseEnrollment.objects.filter( enterprise_customer_user__enterprise_customer=enterprise_customer, enterprise_customer_user__user_id=enterprise_customer_user.user_id, course_id=course_id ).exists()) track_enrollment_mock.assert_called_once_with( 'course-landing-page-enrollment', enterprise_customer_user.user_id, course_id, handle_consent_enrollment_url, )
def test_default_content_filter(self, default_content_filter, expected_content_filter): """ Test that `EnterpriseCustomerCatalog`.content_filter is saved with correct default content filter. """ with override_settings(ENTERPRISE_CUSTOMER_CATALOG_DEFAULT_CONTENT_FILTER=default_content_filter): enterprise_catalog = EnterpriseCustomerCatalogFactory() assert enterprise_catalog.content_filter == expected_content_filter
def setUp(self): self.user = UserFactory.create(is_staff=True, is_active=True) self.enterprise_customer = EnterpriseCustomerFactory( name='Starfleet Academy', ) self.enterprise_catalog = EnterpriseCustomerCatalogFactory( enterprise_customer=self.enterprise_customer) super().setUp()
def test_get_content_metadata_with_enterprise_catalogs(self): """ Verify that the client method `get_content_metadata` works as expected. """ EnterpriseCustomerCatalogFactory( enterprise_customer=self.enterprise_customer, ) uuid = str(self.enterprise_customer.uuid) course_run_ids = ['course-v1:edX+DemoX+Demo_Course_1', 'course-v1:edX+DemoX+Demo_Course_2'] self.mock_ent_courses_api_with_pagination( enterprise_uuid=uuid, course_run_ids=course_run_ids ) enterprise_catalog_uuid = str(self.enterprise_customer.enterprise_customer_catalogs.first().uuid) self.mock_enterprise_customer_catalogs(enterprise_catalog_uuid) api_resource_name = 'enterprise-customer' cache_key = get_cache_key( resource=api_resource_name, querystring={}, resource_id=uuid, traverse_pagination=False, ) cached_enterprise_api_response = cache.get(cache_key) self.assertIsNone(cached_enterprise_api_response) # Verify that by default enterprise client fetches all the course runs associated with the catalog. client = enterprise_api.EnterpriseApiClient(self.user) course_runs = client.get_content_metadata(self.enterprise_customer) assert len(course_runs) == 5
def test_get_content_metadata_with_enterprise_catalog_set_to_none(self): """ Verify that the client method `get_content_metadata` returns courses from associated EnterpriseCustomerCatalog objects only if EnterpriseCustomer.catalog is set to None. """ EnterpriseCustomerCatalogFactory( enterprise_customer=self.enterprise_customer, ) enterprise_catalog_uuid = str( self.enterprise_customer.enterprise_customer_catalogs.first().uuid) self.mock_enterprise_customer_catalogs(enterprise_catalog_uuid) api_resource_name = 'enterprise-customer' cache_key = get_cache_key( resource=api_resource_name, querystring={}, resource_id=str(self.enterprise_customer.uuid), traverse_pagination=False, ) cached_enterprise_api_response = cache.get(cache_key) self.assertIsNone(cached_enterprise_api_response) # Verify that by default enterprise client fetches all the course runs associated with the enterprise catalog. client = enterprise_api.EnterpriseApiClient(self.user) course_runs = client.get_content_metadata(self.enterprise_customer) assert len(course_runs) == 3
def test_update_catalog_without_existing_service_catalog( self, api_client_mock): enterprise_catalog = EnterpriseCustomerCatalogFactory() api_client_mock.return_value.get_enterprise_catalog.return_value = {} enterprise_catalog.title = 'New title' enterprise_catalog.save() # Verify the API was called and the catalog is the same as there were no real updates api_client_mock.return_value.create_enterprise_catalog.assert_called_with( str(enterprise_catalog.uuid), str(enterprise_catalog.enterprise_customer.uuid), enterprise_catalog.enterprise_customer.name, enterprise_catalog.title, enterprise_catalog.content_filter, enterprise_catalog.enabled_course_modes, enterprise_catalog.publish_audit_enrollment_urls)
def setUp(self): super(EnterpriseCustomerCatalogAdminTests, self).setUp() self.catalog_admin = EnterpriseCustomerCatalogAdmin( EnterpriseCustomerCatalog, AdminSite) self.request = RequestFactory() self.request.user = UserFactory(is_staff=True) self.enterprise_catalog = EnterpriseCustomerCatalogFactory() self.enterprise_catalog_uuid = self.enterprise_catalog.uuid self.form = None # The form isn't important for the current tests as we don't change any logic there
def test_update_enterprise_catalog_query(self, api_client_mock): """ Tests the update_enterprise_query post_save signal. Creates an EnterpriseCatalogQuery instance and two separate EnterpriseCatalog instances that are associated with the query. The query's content filter is then updated to see if the changes are applied across both related catalogs. Additionally, there is a test to see if the sync is sent to the EnterpriseCatalogApi service which is done through the mock api client. """ content_filter_1 = OrderedDict({ 'content_type': 'course1', }) content_filter_2 = OrderedDict({ 'content_type': 'course2', }) test_query = EnterpriseCatalogQueryFactory( content_filter=content_filter_1 ) enterprise_catalog_1 = EnterpriseCustomerCatalogFactory( sync_enterprise_catalog_query=True, enterprise_catalog_query=test_query ) enterprise_catalog_2 = EnterpriseCustomerCatalogFactory( sync_enterprise_catalog_query=True, enterprise_catalog_query=test_query ) test_query.content_filter = content_filter_2 test_query.save() enterprise_catalog_1.refresh_from_db() enterprise_catalog_2.refresh_from_db() self.assertEqual(enterprise_catalog_1.content_filter, content_filter_2) self.assertEqual(enterprise_catalog_2.content_filter, content_filter_2) api_client_mock.return_value.get_enterprise_catalog.return_value = True # verify that the mock api was called when saving the catalog after updating the query # enterprise_catalog_2 was most recently modified so the last call should be for that api_client_mock.return_value.update_enterprise_catalog.assert_called_with( enterprise_catalog_2.uuid, enterprise_customer=str(enterprise_catalog_2.enterprise_customer.uuid), enterprise_customer_name=enterprise_catalog_2.enterprise_customer.name, title=enterprise_catalog_2.title, content_filter=enterprise_catalog_2.content_filter, enabled_course_modes=enterprise_catalog_2.enabled_course_modes, publish_audit_enrollment_urls=enterprise_catalog_2.publish_audit_enrollment_urls ) api_client_mock.return_value.refresh_catalogs.assert_called_with([enterprise_catalog_2])
def test_create_catalog(self, api_client_mock): api_client_mock.return_value.get_enterprise_catalog.return_value = {} enterprise_catalog = EnterpriseCustomerCatalogFactory() # Verify the API was called and the catalog "was created" (even though it already was) # This method is a little weird in that the object is sort of created / not-created at the same time api_client_mock.return_value.create_enterprise_catalog.assert_called_with( str(enterprise_catalog.uuid), str(enterprise_catalog.enterprise_customer.uuid), enterprise_catalog.enterprise_customer.name, enterprise_catalog.title, enterprise_catalog.content_filter, enterprise_catalog.enabled_course_modes, enterprise_catalog.publish_audit_enrollment_urls)
def test_partial_successful_refresh_catalog(): catalog1 = EnterpriseCustomerCatalogFactory() catalog2 = EnterpriseCustomerCatalogFactory() task_id = '17812314511' responses.add( responses.POST, _url("enterprise-catalogs/{catalog_uuid}/refresh_metadata/".format( catalog_uuid=catalog1.uuid)), json={'async_task_id': task_id}, ) responses.add( responses.POST, _url("enterprise-catalogs/{catalog_uuid}/refresh_metadata/".format( catalog_uuid=catalog2.uuid)), body=ConnectionError(), ) client = enterprise_catalog.EnterpriseCatalogApiClient( 'staff-user-goes-here') refreshed_catalogs, failed_to_refresh_catalogs = client.refresh_catalogs( EnterpriseCustomerCatalog.objects.all()) assert failed_to_refresh_catalogs[0] == catalog2.uuid assert len(refreshed_catalogs.items()) == 1 assert refreshed_catalogs.get(catalog1.uuid) == task_id
def test_failing_refresh_catalog(): catalog = EnterpriseCustomerCatalogFactory() responses.add( responses.POST, _url("enterprise-catalogs/{catalog_uuid}/refresh_metadata/".format( catalog_uuid=catalog.uuid)), body=ConnectionError(), ) client = enterprise_catalog.EnterpriseCatalogApiClient( 'staff-user-goes-here') refreshed_catalogs, failed_to_refresh_catalogs = client.refresh_catalogs( EnterpriseCustomerCatalog.objects.all()) assert failed_to_refresh_catalogs[0] == catalog.uuid assert len(refreshed_catalogs.items()) == 0
def setUp(self): self.enterprise_customer = EnterpriseCustomerFactory() self.enterprise_customer_catalog = EnterpriseCustomerCatalogFactory( enterprise_customer=self.enterprise_customer ) self.config = CornerstoneEnterpriseCustomerConfiguration( enterprise_customer=self.enterprise_customer, catalogs_to_transmit=str(self.enterprise_customer_catalog.uuid), active=True ) self.config.save() self.user = UserFactory() self.demo_course_run_id = 'course-v1:edX+DemoX+Demo_Course_1' super(TestCornerstoneEnterpriseCustomerConfiguration, self).setUp()
def test_get_content_metadata_with_catalogs_to_transmit( self, mock_load_data): """ Verify that the client method `get_content_metadata` returns courses from catalogs passed in 'catalogs_to_transmit' parameter. """ enterprise_catalog = EnterpriseCustomerCatalogFactory( enterprise_customer=self.enterprise_customer) client = enterprise_api.EnterpriseApiClient(self.user) # get_content_metadata will transmit the 'enterprise_customer' catalogs client.get_content_metadata(self.enterprise_customer) assert mock_load_data.called assert mock_load_data.call_args[1]['resource_id'] == str( enterprise_catalog.uuid) other_catalog = EnterpriseCustomerCatalogFactory() # get_content_metadata will transmit the catalogs which are being passed in 'catalogs_to_transmit' client.get_content_metadata( self.enterprise_customer, enterprise_catalogs=EnterpriseCustomerCatalog.objects.filter( uuid=other_catalog.uuid)) assert mock_load_data.called assert mock_load_data.call_args[1]['resource_id'] == str( other_catalog.uuid)
def test_successful_refresh_catalog(): catalog = EnterpriseCustomerCatalogFactory() task_id = '17812314511' responses.add( responses.POST, _url("enterprise-catalogs/{catalog_uuid}/refresh_metadata/".format( catalog_uuid=catalog.uuid)), json={'async_task_id': task_id}, ) client = enterprise_catalog.EnterpriseCatalogApiClient( 'staff-user-goes-here') refreshed_catalogs, failed_to_refresh_catalogs = client.refresh_catalogs( EnterpriseCustomerCatalog.objects.all()) assert refreshed_catalogs.get(catalog.uuid) == task_id assert len(failed_to_refresh_catalogs) == 0
def test_clean(self): """ Test the custom clean method of model. """ # with valid catalog uuids in 'catalogs_to_transmit', clean will not raise any exception. self.config.clean() # with invalid catalog uuids in 'catalogs_to_transmit', clean will raise 'ValidationError'. self.config.catalogs_to_transmit = "fake-uuid," self.config.save() with raises(ValidationError): self.config.clean() self.config.catalogs_to_transmit = str(EnterpriseCustomerCatalogFactory().uuid) self.config.save() with raises(ValidationError): self.config.clean()
def test_get_course_specific_consent(self, defer_creation, existing_course_enrollment, course_start_date, course_api_client_mock, course_catalog_api_client_mock, *args): # pylint: disable=unused-argument,invalid-name course_id = 'course-v1:edX+DemoX+Demo_Course' course_key = 'edX+DemoX' course_catalog_api_client_mock.return_value.course_in_catalog.return_value = True content_filter = { 'key': [ course_id, ] } course_catalog_api_client_mock.return_value.get_course_id.return_value = course_key course_run_details = { 'start': course_start_date, 'title': 'Demo Course' } course_catalog_api_client_mock.return_value.get_course_run.return_value = course_run_details client = course_api_client_mock.return_value client.get_course_details.return_value = { 'name': 'edX Demo Course', } self._login() enterprise_customer = EnterpriseCustomerFactory( name='Starfleet Academy', enable_data_sharing_consent=True, enforce_data_sharing_consent='at_enrollment', ) EnterpriseCustomerCatalogFactory( enterprise_customer=enterprise_customer, content_filter=content_filter) ecu = EnterpriseCustomerUserFactory( user_id=self.user.id, enterprise_customer=enterprise_customer) if existing_course_enrollment: EnterpriseCourseEnrollment.objects.create( enterprise_customer_user=ecu, course_id=course_id) params = { 'enterprise_customer_uuid': str(enterprise_customer.uuid), 'course_id': course_id, 'next': 'https://google.com', 'failure_url': 'https://facebook.com', } if defer_creation: params['defer_creation'] = True response = self.client.get(self.url, data=params) assert response.status_code == 200 expected_prompt = ( 'To access this course, you must first consent to share your learning achievements ' 'with <b>Starfleet Academy</b>.') expected_alert = ( 'In order to start this course and use your discount, <b>you must</b> consent to share your ' 'course data with Starfleet Academy.') expected_course_start_date = '' if course_start_date: expected_course_start_date = parse( course_run_details['start']).strftime('%B %d, %Y') for key, value in { 'platform_name': 'Test platform', 'platform_description': 'Test description', 'tagline': "High-quality online learning opportunities from the world's best universities", 'header_logo_alt_text': 'Test platform home page', 'consent_request_prompt': expected_prompt, 'requested_permissions_header': ('Per the <a href="#consent-policy-dropdown-bar" ' 'class="policy-dropdown-link background-input" id="policy-dropdown-link">' 'Data Sharing Policy</a>, <b>Starfleet Academy</b> would like to know about:' ), 'confirmation_alert_prompt': expected_alert, 'sharable_items_footer': ('My permission applies only to data from courses or programs that are sponsored by ' 'Starfleet Academy, and not to data from any Test platform courses or programs that ' 'I take on my own. I understand that I may withdraw my permission only by fully unenrolling ' 'from any courses or programs that are sponsored by Starfleet Academy.' ), 'course_id': 'course-v1:edX+DemoX+Demo_Course', 'redirect_url': 'https://google.com', 'course_specific': True, 'defer_creation': defer_creation, 'welcome_text': 'Welcome to Test platform.', 'sharable_items_note_header': 'Please note', 'LMS_SEGMENT_KEY': settings.LMS_SEGMENT_KEY, 'LMS_ROOT_URL': 'http://lms.example.com', 'course_start_date': expected_course_start_date, 'enterprise_customer': enterprise_customer, 'enterprise_welcome_text': ("You have left the <strong>Starfleet Academy</strong> website and are now on the " "Test platform site. Starfleet Academy has partnered with Test platform to offer you " "high-quality, always available learning programs to help you advance your knowledge " "and career. <br/>Please note that Test platform has a different " "<a href='https://www.edx.org/edx-privacy-policy' target='_blank'>Privacy Policy </a> " "from Starfleet Academy."), }.items(): assert response.context[key] == value # pylint:disable=no-member
def test_post_course_specific_consent( self, defer_creation, consent_provided, expected_redirect_url, course_id, license_uuid, reverse_mock, course_catalog_api_client_mock, enterprise_catalog_api_client_mock, mock_enrollment_api_client, *args): # pylint: disable=unused-argument,invalid-name self._login() enterprise_customer = EnterpriseCustomerFactory( name='Starfleet Academy', enable_data_sharing_consent=True, enforce_data_sharing_consent='at_enrollment', ) content_filter = { 'key': [ course_id, ] } EnterpriseCustomerCatalogFactory( enterprise_customer=enterprise_customer, content_filter=content_filter) ecu = EnterpriseCustomerUserFactory( user_id=self.user.id, enterprise_customer=enterprise_customer) enterprise_enrollment = EnterpriseCourseEnrollment.objects.create( enterprise_customer_user=ecu, course_id=course_id, ) dsc = DataSharingConsentFactory( username=self.user.username, course_id=course_id, enterprise_customer=enterprise_customer, granted=consent_provided) course_catalog_api_client_mock.return_value.program_exists.return_value = True course_catalog_api_client_mock.return_value.get_course_id.return_value = 'edX+DemoX' mock_enterprise_catalog_api_client = enterprise_catalog_api_client_mock.return_value mock_enterprise_catalog_api_client.enterprise_contains_content_items.return_value = True reverse_mock.return_value = '/dashboard' course_mode = 'verified' mock_enrollment_api_client.return_value.get_course_modes.return_value = [ course_mode ] post_data = { 'enterprise_customer_uuid': enterprise_customer.uuid, 'course_id': course_id, 'redirect_url': '/successful_enrollment', 'failure_url': '/failure_url', } if defer_creation: post_data['defer_creation'] = True if consent_provided: post_data['data_sharing_consent'] = consent_provided if license_uuid: post_data['license_uuid'] = license_uuid resp = self.client.post(self.url, post_data) assert resp.url.endswith(expected_redirect_url) # pylint: disable=no-member assert resp.status_code == 302 if not defer_creation: dsc.refresh_from_db() assert dsc.granted is consent_provided # we'll only create an enrollment record if (1) creation is not deferred, (2) consent has not been provided, # (3) we provide a license_uuid, and (4) we provide a course _run_ id if not defer_creation and not consent_provided and license_uuid and course_id.endswith( 'Demo_Course'): assert LicensedEnterpriseCourseEnrollment.objects.filter( enterprise_course_enrollment=enterprise_enrollment, license_uuid=license_uuid, ).exists() is True mock_enrollment_api_client.return_value.enroll_user_in_course.assert_called_once_with( self.user.username, course_id, course_mode) if not license_uuid: assert not mock_enrollment_api_client.return_value.enroll_user_in_course.called