class TestSyncCourseRunsCommand(ModuleStoreTestCase): """ Test for the sync course runs management command. """ def setUp(self): super(TestSyncCourseRunsCommand, self).setUp() # create mongo course self.course = CourseFactory.create() # load this course into course overview self.course_overview = CourseOverview.get_from_id(self.course.id) # create a catalog course run with the same course id. self.catalog_course_run = CourseRunFactory( key=unicode(self.course.id), marketing_url='test_marketing_url', eligible_for_financial_aid=False ) def test_course_run_sync(self, mock_catalog_course_runs): """ Verify on executing management command course overview data is updated with course run data from course discovery. """ mock_catalog_course_runs.return_value = [self.catalog_course_run] call_command('sync_course_runs') updated_course_overview = CourseOverview.objects.get(id=self.course.id) # assert fields have updated for field in sync_command.course_run_fields: course_overview_field_name = field.course_overview_name catalog_field_name = field.catalog_name previous_course_overview_value = getattr(self.course_overview, course_overview_field_name), updated_course_overview_value = getattr(updated_course_overview, course_overview_field_name) # course overview value matches catalog value self.assertEqual( updated_course_overview_value, self.catalog_course_run.get(catalog_field_name), ) # new value doesn't match old value self.assertNotEqual( updated_course_overview_value, previous_course_overview_value, ) @mock.patch(COMMAND_MODULE + '.log.info') def test_course_overview_does_not_exist(self, mock_log_info, mock_catalog_course_runs): """ Verify no error in case if a course run is not found in course overview. """ nonexistent_course_run = CourseRunFactory() mock_catalog_course_runs.return_value = [self.catalog_course_run, nonexistent_course_run] call_command('sync_course_runs') mock_log_info.assert_any_call( '[sync_course_runs] course overview record not found for course run: %s', nonexistent_course_run['key'], ) updated_marketing_url = CourseOverview.objects.get(id=self.course.id).marketing_url self.assertEqual(updated_marketing_url, 'test_marketing_url') @mock.patch(COMMAND_MODULE + '.log.info') def test_starting_and_ending_logs(self, mock_log_info, mock_catalog_course_runs): """ Verify logging at start and end of the command. """ def _assert_logs(num_updates): mock_log_info.assert_any_call('[sync_course_runs] Fetching course runs from catalog service.') mock_log_info.assert_any_call( '[sync_course_runs] course runs found in catalog: %d, course runs found in course overview: %d,' ' course runs not found in course overview: %d, course overviews updated: %d', 3, 1, 2, num_updates, ) mock_log_info.reset_mock() mock_catalog_course_runs.return_value = [self.catalog_course_run, CourseRunFactory(), CourseRunFactory()] call_command('sync_course_runs') _assert_logs(num_updates=1) call_command('sync_course_runs') _assert_logs(num_updates=0)
class TestSyncCourseRunsCommand(ModuleStoreTestCase): """ Test for the sync course runs management command. """ def setUp(self): super().setUp() # create mongo course self.course = CourseFactory.create() # load this course into course overview self.course_overview = CourseOverview.get_from_id(self.course.id) # create a catalog course run with the same course id. self.catalog_course_run = CourseRunFactory( key=str(self.course.id), marketing_url='test_marketing_url', eligible_for_financial_aid=False) def test_course_run_sync(self, mock_catalog_course_runs): """ Verify on executing management command course overview data is updated with course run data from course discovery. """ mock_catalog_course_runs.return_value = [self.catalog_course_run] call_command('sync_course_runs') updated_course_overview = CourseOverview.objects.get(id=self.course.id) # assert fields have updated for field in sync_command.course_run_fields: course_overview_field_name = field.course_overview_name catalog_field_name = field.catalog_name previous_course_overview_value = getattr( self.course_overview, course_overview_field_name) updated_course_overview_value = getattr( updated_course_overview, course_overview_field_name) # course overview value matches catalog value assert updated_course_overview_value == self.catalog_course_run.get( catalog_field_name) # pylint: disable=no-member, line-too-long # new value doesn't match old value assert updated_course_overview_value != previous_course_overview_value @mock.patch(COMMAND_MODULE + '.log.info') def test_course_overview_does_not_exist(self, mock_log_info, mock_catalog_course_runs): """ Verify no error in case if a course run is not found in course overview. """ nonexistent_course_run = CourseRunFactory() mock_catalog_course_runs.return_value = [ self.catalog_course_run, nonexistent_course_run ] call_command('sync_course_runs') mock_log_info.assert_any_call( '[sync_course_runs] course overview record not found for course run: %s', nonexistent_course_run['key'], ) updated_marketing_url = CourseOverview.objects.get( id=self.course.id).marketing_url assert updated_marketing_url == 'test_marketing_url' @mock.patch(COMMAND_MODULE + '.log.info') def test_starting_and_ending_logs(self, mock_log_info, mock_catalog_course_runs): """ Verify logging at start and end of the command. """ def _assert_logs(num_updates): mock_log_info.assert_any_call( '[sync_course_runs] Fetching course runs from catalog service.' ) mock_log_info.assert_any_call( '[sync_course_runs] course runs found in catalog: %d, course runs found in course overview: %d,' ' course runs not found in course overview: %d, course overviews updated: %d', 3, 1, 2, num_updates, ) mock_log_info.reset_mock() mock_catalog_course_runs.return_value = [ self.catalog_course_run, CourseRunFactory(), CourseRunFactory() ] call_command('sync_course_runs') _assert_logs(num_updates=1) call_command('sync_course_runs') _assert_logs(num_updates=0)
class EnrollmentAttributeOverrideViewTest(ModuleStoreTestCase): """ Tests for course creator admin. """ def setUp(self): """ Test case setup """ super().setUp() self.client = Client() user = AdminFactory() self.view_url = reverse('admin:enterprise_override_attributes') self.client.login(username=user.username, password=TEST_PASSWORD) self.users = [] for _ in range(3): self.users.append(UserFactory()) self.course = CourseRunFactory() self.course_id = self.course.get('key') # lint-amnesty, pylint: disable=no-member self.csv_data = [ [self.users[0].id, self.course_id, 'OP_4321'], [self.users[1].id, self.course_id, 'OP_8765'], [self.users[2].id, self.course_id, 'OP_2109'], ] self.csv_data_for_existing_attributes = [ [self.users[0].id, self.course_id, 'OP_1234'], [self.users[1].id, self.course_id, 'OP_5678'], [self.users[2].id, self.course_id, 'OP_9012'], ] for user in self.users: CourseEnrollmentFactory( course_id=self.course_id, user=user ) def create_csv(self, header=None, data=None): """Create csv""" header = header or ['lms_user_id', 'course_id', 'opportunity_id'] data = data or self.csv_data tmp_csv_path = os.path.join(tempfile.gettempdir(), 'data.csv') with open(tmp_csv_path, 'w') as csv_file: csv_writer = csv.writer(csv_file) csv_writer.writerow(header) csv_writer.writerows(data) return tmp_csv_path def verify_enrollment_attributes(self, data=None): """ Verify that data from csv is imported correctly and tables have correct data. """ data = data or self.csv_data for user_id, course_id, opportunity_id in data: enrollment = CourseEnrollment.objects.get(user_id=user_id, course_id=course_id) enrollment_attribute = CourseEnrollmentAttribute.objects.get( enrollment=enrollment, namespace='salesforce', name='opportunity_id' ) assert enrollment_attribute.value == opportunity_id def test_get(self): """ Tests that HTTP GET is working as expected. """ response = self.client.get(self.view_url) assert response.status_code == 200 assert isinstance(response.context['form'], CSVImportForm) def test_post(self): """ Tests that HTTP POST is working as expected when creating new attributes and updating. """ csv_path = self.create_csv() post_data = {'csv_file': open(csv_path)} response = self.client.post(self.view_url, data=post_data) assert response.status_code == 302 self.verify_enrollment_attributes() # override existing csv_path = self.create_csv(data=self.csv_data_for_existing_attributes) post_data = {'csv_file': open(csv_path)} response = self.client.post(self.view_url, data=post_data) assert response.status_code == 302 self.verify_enrollment_attributes(data=self.csv_data_for_existing_attributes) def test_post_with_no_csv(self): """ Tests that HTTP POST without out csv file is working as expected. """ response = self.client.post(self.view_url) assert response.context['form'].errors == {'csv_file': ['This field is required.']} def test_post_with_incorrect_csv_header(self): """ Tests that HTTP POST with incorrect csv header is working as expected. """ csv_path = self.create_csv(header=['a', 'b']) post_data = {'csv_file': open(csv_path)} response = self.client.post(self.view_url, data=post_data) assert response.context['form'].errors == { 'csv_file': [ 'Expected a CSV file with [lms_user_id, course_id, opportunity_id] ' 'columns, but found [a, b] columns instead.' ] } def test_post_with_no_enrollment_error(self): """ Tests that HTTP POST is working as expected when for some records there is no enrollment. """ csv_data = self.csv_data + [[999, self.course_id, 'NOPE'], [1000, self.course_id, 'NONE']] csv_path = self.create_csv(data=csv_data) post_data = {'csv_file': open(csv_path)} response = self.client.post(self.view_url, data=post_data) assert response.status_code == 302 messages = [] for msg in get_messages(response.wsgi_request): messages.append(str(msg)) assert messages == [ 'Successfully updated learner enrollment opportunity ids.', 'Enrollment attributes were not updated for records at following line numbers ' 'in csv because no enrollment found for these records: 4, 5' ]