Beispiel #1
0
class UpdateCourseKeySerializerTests(TestCase):
    serializer_class = UpdateCourseKeySerializer

    def setUp(self):
        super(UpdateCourseKeySerializerTests, self).setUp()
        self.course_run = CourseRunFactory()
        self.request = RequestFactory()
        self.user = UserFactory()
        self.request.user = self.user

    def get_expected_data(self):
        return {
            'lms_course_id': self.course_run.lms_course_id,
            'changed_by': self.user
        }

    def test_validation(self):
        self.course_run.lms_course_id = 'course-v1:edxTest+TC101+2016_Q1'
        self.course_run.save()  # pylint: disable=no-member
        serializer = self.serializer_class(self.course_run)
        serializer.context['request'] = self.request
        expected = serializer.validate(serializer.data)
        self.assertEqual(self.get_expected_data(), expected)

    def test_validation_error(self):
        self.course_run.lms_course_id = 'wrong-course-id'
        self.course_run.save()  # pylint: disable=no-member
        serializer = self.serializer_class(self.course_run)
        with self.assertRaises(ValidationError):
            serializer.validate(serializer.data)
Beispiel #2
0
    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,
            )
Beispiel #3
0
    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
Beispiel #4
0
    def test_create_course_run_in_studio_with_image_failure(self, __):
        organization = OrganizationFactory()
        OrganizationExtensionFactory(organization=organization)
        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)

        course = CourseFactory(organizations=[organization])

        with mock.patch('course_discovery.apps.api.utils.logger.exception'
                        ) as mock_logger:
            publisher_course_run = CourseRunFactory(
                course=course,
                start=start,
                lms_course_id=None,
            )

        assert mock_logger.call_count == 1
        assert mock_logger.call_args_list[0] == mock.call(
            'An error occurred while setting the course run image for [{key}] in studio. All other fields '
            'were successfully saved in Studio.'.format(key=course_run_key))

        publisher_course_run.refresh_from_db()
        assert len(responses.calls) == 2
        assert publisher_course_run.lms_course_id == course_run_key
class UpdateCourseKeySerializerTests(TestCase):
    serializer_class = UpdateCourseKeySerializer

    def setUp(self):
        super(UpdateCourseKeySerializerTests, self).setUp()
        self.course_run = CourseRunFactory()
        self.request = RequestFactory()
        self.user = UserFactory()
        self.request.user = self.user

    def get_expected_data(self):
        return {
            'lms_course_id': self.course_run.lms_course_id,
            'changed_by': self.user
        }

    def test_validation(self):
        self.course_run.lms_course_id = 'course-v1:edxTest+TC101+2016_Q1'
        self.course_run.save()  # pylint: disable=no-member
        serializer = self.serializer_class(self.course_run, context={'request': self.request})
        expected = serializer.validate(serializer.data)
        self.assertEqual(self.get_expected_data(), expected)

    def test_validation_error(self):
        self.course_run.lms_course_id = 'wrong-course-id'
        self.course_run.save()  # pylint: disable=no-member
        serializer = self.serializer_class(self.course_run)
        with self.assertRaises(ValidationError):
            serializer.validate(serializer.data)
Beispiel #6
0
 def setUp(self):
     super(CourseRunSerializerTests, self).setUp()
     self.course_run = CourseRunFactory()
     self.course_run.lms_course_id = 'course-v1:edX+DemoX+Demo_Course'
     self.request = RequestFactory()
     self.user = UserFactory()
     self.request.user = self.user
     self.course_state = CourseRunStateFactory(course_run=self.course_run, owner_role=PublisherUserRole.Publisher)
Beispiel #7
0
 def setUp(self):
     super(CourseRunSerializerTests, self).setUp()
     self.course_run = CourseRunFactory()
     self.course_run.lms_course_id = 'course-v1:edX+DemoX+Demo_Course'
     self.course_run.external_key = 'testOrg-course-1'
     self.person = PersonFactory()
     self.discovery_course_run = DiscoveryCourseRunFactory(
         key=self.course_run.lms_course_id,
         external_key=self.course_run.external_key,
         staff=[self.person])
     self.request = RequestFactory()
     self.user = UserFactory()
     self.request.user = self.user
     self.course_state = CourseRunStateFactory(
         course_run=self.course_run, owner_role=PublisherUserRole.Publisher)
Beispiel #8
0
    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
            ),
        )
Beispiel #9
0
    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)
Beispiel #10
0
    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'))
Beispiel #11
0
    def test_create_course_run_error_with_discovery_run(
            self, mock_access_token):  # pylint: disable=unused-argument
        """
        Tests that course run creations raises exception and logs expected exception message
        """
        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)

        body = {'error': 'Server error'}
        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=500)

        with mock.patch(
                'course_discovery.apps.publisher.signals.logger.exception'
        ) as mock_logger:
            with pytest.raises(HttpServerError):
                CourseRunFactory(lms_course_id=None,
                                 course__organizations=[organization],
                                 course__number=number)

            assert len(responses.calls) == 1
            mock_logger.assert_called_with(
                'Failed to create course run [%s] on Studio: %s', course_key,
                json.dumps(body).encode('utf8'))
Beispiel #12
0
 def test_create_seat_masters_track(self, form_data):
     course_run = CourseRunFactory()
     form = SeatForm(data=form_data)
     seat = form.save(course_run=course_run)
     expected_masters = 'masters_track' in form_data and form_data[
         'masters_track']
     self.assertEqual(expected_masters, seat.masters_track)
Beispiel #13
0
def test_update_course_run_image_in_studio_without_course_image():
    publisher_course_run = CourseRunFactory(course__image=None)
    api = StudioAPI(None)

    with mock.patch('course_discovery.apps.api.utils.logger') as mock_logger:
        api.update_course_run_image_in_studio(publisher_course_run)
        mock_logger.warning.assert_called_with(
            'Card image for course run [%d] cannot be updated. The related course [%d] has no image defined.',
            publisher_course_run.id, publisher_course_run.course.id)
Beispiel #14
0
    def test_create_course_run_in_studio_without_partner(self):
        with mock.patch('course_discovery.apps.publisher.signals.logger.error'
                        ) as mock_logger:
            publisher_course_run = CourseRunFactory(course__organizations=[])

            assert publisher_course_run.course.partner is None
            mock_logger.assert_called_with(
                'Failed to publish course run [%d] to Studio. Related course [%d] has no associated Partner.',
                publisher_course_run.id, publisher_course_run.course.id)
Beispiel #15
0
def test_generate_data_for_studio_api_without_team():
    course_run = CourseRunFactory(
        course__organizations=[OrganizationFactory()])

    with mock.patch(
            'course_discovery.apps.api.utils.logger.warning') as mock_logger:
        assert_data_generated_correctly(course_run, [])
        mock_logger.assert_called_with(
            'No course team admin specified for course [%s]. This may result in a Studio course run '
            'being created without a course team.', course_run.course.number)
Beispiel #16
0
 def _create_course_run_for_publication(self):
     organization = OrganizationFactory()
     transcript_languages = [LanguageTag.objects.first()]
     mock_image_file = make_image_file('test_image.jpg')
     return CourseRunFactory(course__organizations=[organization],
                             course__tertiary_subject=None,
                             course__image__from_file=mock_image_file,
                             lms_course_id='a/b/c',
                             transcript_languages=transcript_languages,
                             staff=PersonFactory.create_batch(2))
def test_generate_data_for_studio_api():
    course_run = CourseRunFactory(course__organizations=[OrganizationFactory()])
    course = course_run.course
    role = CourseUserRoleFactory(course=course, role=PublisherUserRole.CourseTeam)
    team = [
        {
            'user': role.user.username,
            'role': 'instructor',
        },
    ]
    assert_data_generated_correctly(course_run, team)
Beispiel #18
0
    def test_successful_post(self):
        """Posting data to the comment post endpoint creates a comment."""
        path = reverse('comments-post-comment')
        self.assertEqual(Comments.objects.count(), 0)
        course_run = CourseRunFactory()
        generated_data = self.generate_data(course_run)
        self.client.post(path, data=generated_data)

        self.assertEqual(Comments.objects.count(), 1)
        comment = Comments.objects.first()
        self.assertEqual(comment.user_name, generated_data['name'])
        self.assertEqual(comment.comment, generated_data['comment'])
        self.assertEqual(comment.user_email, generated_data['email'])
Beispiel #19
0
class CourseRunSerializerTests(TestCase):
    serializer_class = CourseRunSerializer

    def setUp(self):
        super(CourseRunSerializerTests, self).setUp()
        self.course_run = CourseRunFactory()
        self.course_run.lms_course_id = 'course-v1:edX+DemoX+Demo_Course'
        self.request = RequestFactory()
        self.user = UserFactory()
        self.request.user = self.user
        self.course_state = CourseRunStateFactory(course_run=self.course_run, owner_role=PublisherUserRole.Publisher)

    def get_expected_data(self):
        return {
            'lms_course_id': self.course_run.lms_course_id,
            'changed_by': self.user,
            'preview_url': self.course_run.preview_url
        }

    def test_validate_lms_course_id(self):
        """ Verify that serializer raises error if 'lms_course_id' has invalid format. """
        self.course_run.lms_course_id = 'invalid-course-id'
        self.course_run.save()  # pylint: disable=no-member
        serializer = self.serializer_class(self.course_run)
        with self.assertRaises(ValidationError):
            serializer.validate_lms_course_id(self.course_run.lms_course_id)

    def test_validate_preview_url(self):
        """ Verify that serializer raises error if 'preview_url' has invalid format. """
        self.course_run.preview_url = 'invalid-preview-url'
        self.course_run.save()  # pylint: disable=no-member
        serializer = self.serializer_class(self.course_run)
        with self.assertRaises(ValidationError):
            serializer.validate_preview_url(self.course_run.preview_url)

    def test_serializer_with_valid_data(self):
        """ Verify that serializer validate course_run object. """
        serializer = self.serializer_class(self.course_run, context={'request': self.request})
        self.assertEqual(self.get_expected_data(), serializer.validate(serializer.data))

    def test_update_preview_url(self):
        """ Verify that course 'owner_role' will be changed to course_team after updating
        course run with preview url.
        """
        serializer = self.serializer_class(self.course_run)
        serializer.update(self.course_run, serializer.data)
        self.assertEqual(self.course_state.owner_role, PublisherUserRole.CourseTeam)

    def test_update_lms_course_id(self):
        """ Verify that 'changed_by' also updated after updating course_run's lms_course_id."""
        self.course_run.preview_url = None
        self.course_run.save()

        serializer = self.serializer_class(self.course_run, context={'request': self.request})
        serializer.update(self.course_run, serializer.validate(serializer.data))

        self.assertEqual(self.course_run.lms_course_id, serializer.data['lms_course_id'])
        self.assertEqual(self.course_run.changed_by, self.user)
Beispiel #20
0
    def test_create_course_run_in_studio_with_organization_opt_out(self):
        with mock.patch(
                'course_discovery.apps.publisher.signals.logger.warning'
        ) as mock_logger:
            course_organization = OrganizationFactory()
            OrganizationExtensionFactory(organization=course_organization,
                                         auto_create_in_studio=False)
            publisher_course_run = CourseRunFactory(
                course__organizations=[course_organization])

            mock_logger.assert_called_with(
                ('Course run [%d] will not be automatically created in studio.'
                 'Organization [%s] has opted out of this feature.'),
                publisher_course_run.course.id,
                course_organization.key,
            )
def test_calculate_course_run_key_run_value_with_multiple_runs_per_trimester():
    number = 'TestX'
    organization = OrganizationFactory()
    partner = organization.partner
    course_key = '{org}+{number}'.format(org=organization.key, number=number)
    discovery_course = DiscoveryCourseFactory(partner=partner, key=course_key)
    DiscoveryCourseRunFactory(key='course-v1:TestX+Testing101x+1T2017', course=discovery_course)
    course_run = CourseRunFactory(
        start=datetime.datetime(2017, 2, 1),
        lms_course_id=None,
        course__organizations=[organization],
        course__number=number
    )
    assert StudioAPI.calculate_course_run_key_run_value(course_run) == '1T2017a'

    DiscoveryCourseRunFactory(key='course-v1:TestX+Testing101x+1T2017a', course=discovery_course)
    assert StudioAPI.calculate_course_run_key_run_value(course_run) == '1T2017b'
Beispiel #22
0
    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)
        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
Beispiel #23
0
    def test_create_course_run_in_studio_with_api_failure(
            self, mock_access_token):  # pylint: disable=unused-argument
        organization = OrganizationFactory()
        partner = organization.partner

        body = {'error': 'Server error'}
        studio_url_root = partner.studio_url.strip('/')
        url = '{}/api/v1/course_runs/'.format(studio_url_root)
        responses.add(responses.POST, url, json=body, status=500)

        with mock.patch(
                'course_discovery.apps.publisher.signals.logger.exception'
        ) as mock_logger:
            with pytest.raises(HttpServerError):
                publisher_course_run = CourseRunFactory(
                    lms_course_id=None, course__organizations=[organization])

                assert len(responses.calls) == 1
                assert publisher_course_run.lms_course_id is None

                mock_logger.assert_called_with(
                    'Failed to create course run [%d] on Studio: %s',
                    publisher_course_run.id,
                    json.dumps(body).encode('utf8'))
 def setUp(self):
     super(UpdateCourseKeySerializerTests, self).setUp()
     self.course_run = CourseRunFactory()
     self.request = RequestFactory()
     self.user = UserFactory()
     self.request.user = self.user
def test_calculate_course_run_key_run_value(month, expected):
    course_run = CourseRunFactory(start=datetime.datetime(2017, month, 1))
    assert StudioAPI.calculate_course_run_key_run_value(course_run) == expected
Beispiel #26
0
 def setUp(self):
     super(UpdateCourseKeySerializerTests, self).setUp()
     self.course_run = CourseRunFactory()
     self.request = RequestFactory()
     self.user = UserFactory()
     self.request.user = self.user
Beispiel #27
0
class TestMigrateCommentsToSalesforce(TestCase):
    LOGGER_PATH = 'course_discovery.apps.course_metadata.management.commands.migrate_comments_to_salesforce.logger'

    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 tearDown(self):
        super(TestMigrateCommentsToSalesforce, self).tearDown()
        # Zero out the instances that are created during testing
        SalesforceUtil.instances = {}

    @mock.patch(LOGGER_PATH)
    def test_handle_no_orgs(self, mock_logger):
        config = MigrateCommentsToSalesforceFactory()
        config.orgs.all().delete()

        with self.assertRaises(CommandError):
            Command().handle()
        mock_logger.error.assert_called_with(
            'No organizations were defined. Please add organizations to the MigrateCommentsToSalesforce model.'
        )

    @mock.patch(LOGGER_PATH)
    def test_handle_no_partner(self, mock_logger):
        config = MigrateCommentsToSalesforceFactory()
        config.orgs.add(self.org_1)
        with self.assertRaises(CommandError):
            Command().handle()
        mock_logger.error.assert_called_with(
            'No partner was defined. Please add a partner to the MigrateCommentsToSalesforce model.'
        )

    @mock.patch(LOGGER_PATH)
    def test_handle_no_salesforce_configuration(self, mock_logger):
        config = MigrateCommentsToSalesforceFactory(partner=self.partner)
        config.orgs.add(self.org_1)
        with self.assertRaises(CommandError):
            Command().handle()
        mock_logger.error.assert_called_with(
            'Salesforce configuration for {} does not exist'.format(self.partner.name)
        )

    @mock.patch('course_discovery.apps.course_metadata.salesforce.Salesforce')
    def test_handle_without_publisher_course_run(self, mock_salesforce):
        config = MigrateCommentsToSalesforceFactory(partner=self.partner)
        config.orgs.add(self.org_1)
        SalesforceConfigurationFactory(partner=self.partner)

        self.publisher_course_run_1.delete()

        # Set return values for all of the Salesforce methods that get called
        mock_salesforce().Publisher_Organization__c.create.return_value = {'id': 'SomePubOrgId'}
        mock_salesforce().Course__c.create.return_value = {'id': 'SomeCourseId'}
        mock_salesforce().Case.create.return_value = {'id': 'SomeCaseId'}
        mock_salesforce().Course_Run__c.create.return_value = {'id': 'SomeCourseRunId'}

        with mock.patch(self.LOGGER_PATH) as mock_logger:
            Command().handle()
            calls = [
                mock.call('No PublisherCourseRun found for {}.'.format(self.course_run_1.key)),
                mock.call('No PublisherCourses found for {}'.format(self.course_1.key))
            ]
            mock_logger.warning.assert_has_calls(calls, any_order=True)

    @mock.patch('course_discovery.apps.course_metadata.salesforce.Salesforce')
    def test_handle_with_comments(self, mock_salesforce):
        config = MigrateCommentsToSalesforceFactory(partner=self.partner)
        config.orgs.add(self.org_1)
        SalesforceConfigurationFactory(partner=self.partner)
        course_comment = CommentFactory(
            user=self.user_1,
            content_type_id=ContentType.objects.get_for_model(PublisherCourse),
            object_pk=self.publisher_course_1.id,
        )
        course_comment.content_type_id = ContentType.objects.get_for_model(PublisherCourse)
        course_comment.object_pk = self.publisher_course_1.id
        course_comment.save()

        course_run_comment = CommentFactory(
            user=self.user_1,
            content_type_id=ContentType.objects.get_for_model(PublisherCourseRun),
            object_pk=self.publisher_course_run_1.id,
        )
        course_run_comment.content_type_id = ContentType.objects.get_for_model(PublisherCourseRun)
        course_run_comment.object_pk = self.publisher_course_run_1.id
        course_run_comment.save()

        # Set return values for all of the Salesforce methods that get called
        mock_salesforce().Publisher_Organization__c.create.return_value = {'id': 'SomePubOrgId'}
        mock_salesforce().Course__c.create.return_value = {'id': 'SomeCourseId'}
        mock_salesforce().Case.create.return_value = {'id': 'SomeCaseId'}
        mock_salesforce().Course_Run__c.create.return_value = {'id': 'SomeCourseRunId'}

        with mock.patch(self.LOGGER_PATH) as mock_logger:
            Command().handle()
            self.org_1.refresh_from_db()
            self.course_1.refresh_from_db()
            self.course_run_1.refresh_from_db()

            self.assertEqual(self.org_1.salesforce_id, 'SomePubOrgId')
            self.assertEqual(self.course_1.salesforce_id, 'SomeCourseId')
            self.assertEqual(self.course_1.salesforce_case_id, 'SomeCaseId')
            self.assertEqual(self.course_run_1.salesforce_id, 'SomeCourseRunId')

            mock_logger.info.assert_called_with('Inserted 2 comments for {}'.format(self.course_1.title))
class CourseRunSerializerTests(TestCase):
    serializer_class = CourseRunSerializer

    def setUp(self):
        super(CourseRunSerializerTests, self).setUp()
        self.course_run = CourseRunFactory()
        self.course_run.lms_course_id = 'course-v1:edX+DemoX+Demo_Course'
        self.person = PersonFactory()
        self.discovery_course_run = DiscoveryCourseRunFactory(
            key=self.course_run.lms_course_id, staff=[self.person])
        self.request = RequestFactory()
        self.user = UserFactory()
        self.request.user = self.user
        self.course_state = CourseRunStateFactory(
            course_run=self.course_run, owner_role=PublisherUserRole.Publisher)

    def get_expected_data(self):
        """ Helper method which will return expected serialize data. """
        return {
            'lms_course_id': self.course_run.lms_course_id,
            'changed_by': self.user,
            'preview_url': self.course_run.preview_url
        }

    def test_validate_lms_course_id(self):
        """ Verify that serializer raises error if 'lms_course_id' has invalid format. """
        self.course_run.lms_course_id = 'invalid-course-id'
        self.course_run.save()
        serializer = self.serializer_class(self.course_run)
        with self.assertRaises(ValidationError):
            serializer.validate_lms_course_id(self.course_run.lms_course_id)

    def test_validate_preview_url(self):
        """ Verify that serializer raises error if 'preview_url' has invalid format. """
        serializer = self.serializer_class(self.course_run,
                                           context={'request': self.request})
        with self.assertRaises(ValidationError):
            serializer.validate({'preview_url': 'invalid-url'})

    def test_serializer_with_valid_data(self):
        """ Verify that serializer validate course_run object. """
        serializer = self.serializer_class(self.course_run,
                                           context={'request': self.request})
        self.assertEqual(self.get_expected_data(),
                         serializer.validate(serializer.data))

    def test_update_preview_url(self):
        """ Verify that course 'owner_role' will be changed to course_team after updating
        course run with preview url.
        """
        self.discovery_course_run.slug = ''
        self.discovery_course_run.save(suppress_publication=True)
        serializer = self.serializer_class(self.course_run,
                                           context={'request': self.request})
        serializer.update(self.course_run,
                          {'preview_url': 'https://example.com/abc/course'})

        self.assertEqual(self.course_state.owner_role,
                         PublisherUserRole.CourseTeam)
        self.assertEqual(
            self.course_run.preview_url.rsplit('/', 1)[-1], 'course')

    def test_update_preview_url_no_op(self):
        """ Verify we don't push to marketing if no change required """
        self.discovery_course_run.slug = ''
        self.discovery_course_run.save(suppress_publication=True)

        toggle_switch('publish_course_runs_to_marketing_site')
        serializer = self.serializer_class(self.course_run,
                                           context={'request': self.request})

        mock_path = 'course_discovery.apps.course_metadata.publishers.CourseRunMarketingSitePublisher.publish_obj'
        with mock.patch(mock_path) as mock_save:
            serializer.update(
                self.course_run,
                {'preview_url': 'https://example.com/abc/course'})
            self.assertEqual(mock_save.call_count, 1)

            # Now when we update a second time, there should be nothing to do, call count should remain at 1
            serializer.update(
                self.course_run,
                {'preview_url': 'https://example.com/abc/course'})
            self.assertEqual(mock_save.call_count, 1)

    def test_update_preview_url_slug_exists(self):
        """ Verify we don't push to marketing if no change required """
        DiscoveryCourseRunFactory(
            title='course')  # will create the slug 'course'
        serializer = self.serializer_class(self.course_run,
                                           context={'request': self.request})

        with self.assertRaises(Exception) as cm:
            serializer.update(
                self.course_run,
                {'preview_url': 'https://example.com/abc/course'})
        self.assertEqual(cm.exception.args[0],
                         'Preview URL already in use for another course')

    def test_update_lms_course_id(self):
        """ Verify that 'changed_by' also updated after updating course_run's lms_course_id."""
        serializer = self.serializer_class(self.course_run,
                                           context={'request': self.request})
        serializer.update(self.course_run,
                          serializer.validate(serializer.data))

        self.assertEqual(self.course_run.lms_course_id,
                         serializer.data['lms_course_id'])
        self.assertEqual(self.course_run.changed_by, self.user)

    def test_update_with_transaction_rollback(self):
        """
        Verify that transaction roll backed if an error occurred.
        """
        serializer = self.serializer_class(self.course_run)

        with self.assertRaises(Exception):
            serializer.update(self.course_run, {'preview_url': 'invalid_url'})
            self.assertFalse(self.course_run.preview_url)

    def test_transaction_roll_back_with_error_on_email(self):
        """
        Verify that transaction is roll backed if error occurred during email sending.
        """
        toggle_switch('enable_publisher_email_notifications', True)
        serializer = self.serializer_class(self.course_run)
        self.assertEqual(self.course_run.course_run_state.owner_role,
                         PublisherUserRole.Publisher)

        with self.assertRaises(Exception):
            serializer.update(
                self.course_run,
                {'preview_url': 'https://example.com/abc/course'})

        self.course_run = CourseRun.objects.get(id=self.course_run.id)
        self.assertFalse(self.course_run.preview_url)
        # Verify that owner role not changed.
        self.assertEqual(self.course_run.course_run_state.owner_role,
                         PublisherUserRole.Publisher)
Beispiel #29
0
class CourseRunSerializerTests(TestCase):
    serializer_class = CourseRunSerializer

    def setUp(self):
        super(CourseRunSerializerTests, self).setUp()
        self.course_run = CourseRunFactory()
        self.course_run.lms_course_id = 'course-v1:edX+DemoX+Demo_Course'
        self.request = RequestFactory()
        self.user = UserFactory()
        self.request.user = self.user
        self.course_state = CourseRunStateFactory(
            course_run=self.course_run, owner_role=PublisherUserRole.Publisher)

    def get_expected_data(self):
        """ Helper method which will return expected serialize data. """
        return {
            'lms_course_id': self.course_run.lms_course_id,
            'changed_by': self.user,
            'preview_url': self.course_run.preview_url
        }

    def test_validate_lms_course_id(self):
        """ Verify that serializer raises error if 'lms_course_id' has invalid format. """
        self.course_run.lms_course_id = 'invalid-course-id'
        self.course_run.save()  # pylint: disable=no-member
        serializer = self.serializer_class(self.course_run)
        with self.assertRaises(ValidationError):
            serializer.validate_lms_course_id(self.course_run.lms_course_id)

    def test_validate_preview_url(self):
        """ Verify that serializer raises error if 'preview_url' has invalid format. """
        self.course_run.preview_url = 'invalid-preview-url'
        self.course_run.save()  # pylint: disable=no-member
        serializer = self.serializer_class(self.course_run)
        with self.assertRaises(ValidationError):
            serializer.validate_preview_url(self.course_run.preview_url)

    def test_serializer_with_valid_data(self):
        """ Verify that serializer validate course_run object. """
        serializer = self.serializer_class(self.course_run,
                                           context={'request': self.request})
        self.assertEqual(self.get_expected_data(),
                         serializer.validate(serializer.data))

    def test_update_preview_url(self):
        """ Verify that course 'owner_role' will be changed to course_team after updating
        course run with preview url.
        """
        self.course_run.preview_url = ''
        self.course_run.save()
        serializer = self.serializer_class(self.course_run)
        serializer.update(self.course_run,
                          {'preview_url': 'https://example.com/abc/course'})

        self.assertEqual(self.course_state.owner_role,
                         PublisherUserRole.CourseTeam)
        self.assertEqual(self.course_run.preview_url,
                         serializer.data['preview_url'])

    def test_update_lms_course_id(self):
        """ Verify that 'changed_by' also updated after updating course_run's lms_course_id."""
        self.course_run.preview_url = None
        self.course_run.save()

        serializer = self.serializer_class(self.course_run,
                                           context={'request': self.request})
        serializer.update(self.course_run,
                          serializer.validate(serializer.data))

        self.assertEqual(self.course_run.lms_course_id,
                         serializer.data['lms_course_id'])
        self.assertEqual(self.course_run.changed_by, self.user)

    def test_update_with_transaction_rollback(self):
        """
        Verify that transaction roll backed if an error occurred.
        """
        self.course_run.preview_url = ''
        self.course_run.save()
        serializer = self.serializer_class(self.course_run)

        with self.assertRaises(Exception):
            serializer.update(self.course_run, {'preview_url': 'invalid_url'})
            self.assertFalse(self.course_run.preview_url)

    def test_transaction_roll_back_with_error_on_email(self):
        """
        Verify that transaction is roll backed if error occurred during email sending.
        """
        toggle_switch('enable_publisher_email_notifications', True)
        self.course_run.preview_url = ''
        self.course_run.save()
        serializer = self.serializer_class(self.course_run)
        self.assertEqual(self.course_run.course_run_state.owner_role,
                         PublisherUserRole.Publisher)

        with self.assertRaises(Exception):
            serializer.update(
                self.course_run,
                {'preview_url': 'https://example.com/abc/course'})

        self.course_run = CourseRun.objects.get(id=self.course_run.id)
        self.assertFalse(self.course_run.preview_url)
        # Verify that owner role not changed.
        self.assertEqual(self.course_run.course_run_state.owner_role,
                         PublisherUserRole.Publisher)