def test_list(self):
        """ Verify the endpoint returns a list of all programs. """
        url = reverse('api:v1:program-list')
        ProgramFactory.create_batch(3)

        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.data['results'], ProgramSerializer(Program.objects.all(), many=True).data)
    def test_filter_by_marketable(self, status, is_marketable, expected_query_count):
        """ Verify the endpoint filters programs to those that are marketable. """
        url = self.list_path + '?marketable=1'
        ProgramFactory(marketing_slug='')
        programs = ProgramFactory.create_batch(3, status=status)
        programs.reverse()

        expected = programs if is_marketable else []
        self.assertEqual(list(Program.objects.marketable()), expected)
        self.assert_list_results(url, expected, expected_query_count)
    def test_filter_by_uuids(self):
        """ Verify that the endpoint filters programs to those matching the provided UUIDs. """
        expected = ProgramFactory.create_batch(2)
        expected.reverse()
        uuids = [str(p.uuid) for p in expected]
        url = self.list_path + '?uuids=' + ','.join(uuids)

        # Create a third program, which should be filtered out.
        ProgramFactory()

        self.assert_list_results(url, expected, 8)
    def test_data(self):
        program = ProgramFactory()
        organization = OrganizationFactory()
        program.organizations.add(organization)
        program.save()

        # 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 = {
            'uuid': str(program.uuid),
            'name': program.name,
            'subtitle': program.subtitle,
            'category': program.category,
            'marketing_url': program.marketing_url,
            'organizations': [OrganizationsMixin.format_organization(organization)],
        }
        self.assertDictEqual(serializer.data, expected)
 def setUp(self):
     super(MarketingSitePublisherTests, self).setUp()
     self.program = ProgramFactory()
     self.program.partner.marketing_site_url_root = self.api_root
     self.program.partner.marketing_site_api_username = self.username
     self.program.partner.marketing_site_api_password = self.password
     self.program.type = ProgramType.objects.get(name='MicroMasters')
     self.program.save()  # pylint: disable=no-member
     self.api_client = MarketingSiteAPIClient(
         self.username,
         self.password,
         self.api_root
     )
    def test_get_include_unpublished_programs(self):
        """
        Verify the endpoint returns associated unpublished programs
        with the 'include_unpublished_programs' flag set to True
        """
        ProgramFactory(courses=[self.course_run.course],
                       status=ProgramStatus.Unpublished)

        url = reverse('api:v1:course_run-detail',
                      kwargs={'key': self.course_run.key})
        url += '?include_unpublished_programs=1'

        with self.assertNumQueries(17):
            response = self.client.get(url)
        assert response.status_code == 200
        assert response.data == \
            self.serialize_course_run(self.course_run, extra_context={'include_unpublished_programs': True})
Exemple #7
0
 def test_partial_term_search(self):
     """ Test typeahead response with partial term search. """
     title = "Learn Data Science"
     course_run = CourseRunFactory(title=title,
                                   course__partner=self.partner)
     program = ProgramFactory(title=title,
                              status=ProgramStatus.Active,
                              partner=self.partner)
     query = "Data Sci"
     response = self.get_response({'q': query})
     self.assertEqual(response.status_code, 200)
     response_data = response.json()
     expected_response_data = {
         'course_runs': [self.serialize_course_run_search(course_run)],
         'programs': [self.serialize_program_search(program)]
     }
     self.assertDictEqual(response_data, expected_response_data)
 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_response({'q': title})
     self.assertEqual(response.status_code, 200)
     response_data = response.json()
     self.assertDictEqual(response_data, {'course_runs': [self.serialize_course_run_search(course_run)],
                                          'programs': [self.serialize_program_search(program)]})
    def test_empty_query(self):
        """ Verify, when the query (q) parameter is empty, the endpoint behaves as if the parameter
        was not provided. """
        course_run = CourseRunFactory(course__partner=self.partner,
                                      status=CourseRunStatus.Published)
        program = ProgramFactory(partner=self.partner,
                                 status=ProgramStatus.Active)

        response = self.get_response({
            'q': '',
            'content_type': ['courserun', 'program']
        })
        self.assertEqual(response.status_code, 200)
        response_data = json.loads(response.content.decode('utf-8'))
        self.assertListEqual(response_data['objects']['results'], [
            self.serialize_program(program),
            self.serialize_course_run(course_run)
        ])
Exemple #10
0
 def create_program(self, orgs):
     program = ProgramFactory(authoring_organizations=orgs,
                              type=self.program_type)
     curr = CurriculumFactory(program=program)
     course1_draft = CourseFactory(draft=True)
     course1 = CourseFactory(draft_version=course1_draft)
     _run1a = CourseRunFactory(course=course1)
     _run1b = CourseRunFactory(course=course1)
     course2 = CourseFactory()
     _run2a = CourseRunFactory(course=course2)
     run2b = CourseRunFactory(course=course2)
     _mem1 = CurriculumCourseMembershipFactory(curriculum=curr,
                                               course=course1)
     mem2 = CurriculumCourseMembershipFactory(curriculum=curr,
                                              course=course2)
     _ex = CurriculumCourseRunExclusionFactory(course_membership=mem2,
                                               course_run=run2b)
     return program
Exemple #11
0
 def test_to_representation(self):
     request = make_request()
     program = ProgramFactory(banner_image=make_image_file('test.jpg'))
     field = StdImageSerializerField()
     field._context = {'request': request}  # pylint: disable=protected-access
     expected = {
         size_key: {
             'url':
             '{}{}'.format('http://testserver',
                           getattr(program.banner_image, size_key).url),
             'width':
             program.banner_image.field.variations[size_key]['width'],
             'height':
             program.banner_image.field.variations[size_key]['height']
         }
         for size_key in program.banner_image.field.variations
     }
     assert field.to_representation(program.banner_image) == 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_response({'q': 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)
Exemple #13
0
    def test_results_include_aggregation_key(self):
        """ Verify the search results only include the aggregation_key for each document. """
        course_run = CourseRunFactory(course__partner=self.partner,
                                      status=CourseRunStatus.Published)
        program = ProgramFactory(partner=self.partner,
                                 status=ProgramStatus.Active)

        response = self.get_response()
        assert response.status_code == 200
        response_data = response.json()

        expected = sorted(
            [f'courserun:{course_run.course.key}', f'program:{program.uuid}'])
        actual = sorted([
            obj.get('aggregation_key')
            for obj in response_data['objects']['results']
        ])
        assert expected == actual
    def test_course_ordering(self):
        """
        Verify that courses in a program are ordered by ascending run start date,
        with ties broken by earliest run enrollment start date.
        """
        request = make_request()
        course_list = CourseFactory.create_batch(3)

        # Create a course run with arbitrary start and empty enrollment_start.
        CourseRunFactory(
            course=course_list[2],
            enrollment_start=None,
            start=datetime(2014, 2, 1),
        )

        # Create a second run with matching start, but later enrollment_start.
        CourseRunFactory(
            course=course_list[1],
            enrollment_start=datetime(2014, 1, 2),
            start=datetime(2014, 2, 1),
        )

        # Create a third run with later start and enrollment_start.
        CourseRunFactory(
            course=course_list[0],
            enrollment_start=datetime(2014, 2, 1),
            start=datetime(2014, 3, 1),
        )

        program = ProgramFactory(courses=course_list)
        serializer = self.serializer_class(program,
                                           context={'request': request})

        expected = MinimalProgramCourseSerializer(
            # The expected ordering is the reverse of course_list.
            course_list[::-1],
            many=True,
            context={
                'request': request,
                'program': program,
                'course_runs': list(program.course_runs)
            }).data

        self.assertEqual(serializer.data['courses'], expected)
Exemple #15
0
    def create_program(self):
        organizations = [OrganizationFactory()]
        person = PersonFactory()

        course = CourseFactory()
        CourseRunFactory(course=course, staff=[person])

        program = ProgramFactory(
            courses=[course],
            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())
        return program
    def test_results_include_aggregation_key(self):
        """ Verify the search results only include the aggregation_key for each document. """
        course_run = CourseRunFactory(course__partner=self.partner,
                                      status=CourseRunStatus.Published)
        program = ProgramFactory(partner=self.partner,
                                 status=ProgramStatus.Active)

        response = self.get_response()
        assert response.status_code == 200
        response_data = json.loads(response.content.decode('utf-8'))

        expected = sorted([
            'courserun:{}'.format(course_run.course.key),
            'program:{}'.format(program.uuid)
        ])
        actual = sorted([
            obj.get('aggregation_key')
            for obj in response_data['objects']['results']
        ])
        assert expected == actual
Exemple #17
0
    def test_program_autocomplete(self, admin_client):
        """ Verify Program autocomplete returns the data. """
        programs = ProgramFactory.create_batch(3)
        path = reverse('admin_metadata:program-autocomplete')
        response = admin_client.get(path)
        data = json.loads(response.content.decode('utf-8'))
        assert response.status_code == 200
        assert len(data['results']) == 3

        # Search for substrings of program titles
        program = programs[0]
        self.assert_valid_query_result(admin_client, path, program.title[5:], program)
        program = programs[1]
        self.assert_valid_query_result(admin_client, path, program.title[5:], program)

        admin_client.logout()
        response = admin_client.get(path)
        data = json.loads(response.content.decode('utf-8'))
        assert response.status_code == 200
        assert len(data['results']) == 0
 def create_test_program(self, partner):
     program = Program.objects.filter(title='test-program')
     if program:
         program.first().delete()
     logger.info('Creating test-program')
     course = CourseFactory(partner=partner)
     excluded_course_run = CourseRunFactory(course=course)
     ProgramFactory(
         title='test-program',
         partner=partner,
         courses=[course],
         excluded_course_runs=[excluded_course_run],
         authoring_organizations=[OrganizationFactory(partner=partner)],
         credit_backing_organizations=[OrganizationFactory(partner=partner)],
         corporate_endorsements=[CorporateEndorsementFactory()],
         individual_endorsements=[EndorsementFactory(endorser__partner=partner)],
         expected_learning_items=[ExpectedLearningItemFactory()],
         faq=[FAQFactory()],
         job_outlook_items=[JobOutlookItemFactory()],
         instructor_ordering=[PersonFactory()],
     )
Exemple #19
0
    def test_affiliate_with_approved_programs(self):
        """Verify that only the expected Program types are returned, No Masters programs"""
        response = self.client.get(self.affiliate_url)
        assert response.status_code == status.HTTP_200_OK
        root = ET.fromstring(response.content)

        # Assert that there is only on Program in the returned data even though 2
        # are created in setup
        assert len(root.findall('product')) == 1
        print(root.findall('product/[pid="{}"]'.format(self.program.uuid)))
        self._assert_product_xml(
            root.findall('product/[pid="{}"]'.format(self.program.uuid))[0],
            self.program)

        # Add a new program of approved type and verify it is available
        mm_program_type = ProgramType.objects.get(
            slug=ProgramType.MICROMASTERS)
        mm_program = ProgramFactory(type=mm_program_type,
                                    courses=[self.course],
                                    banner_image=self.test_image)

        response = self.client.get(self.affiliate_url)
        assert response.status_code == status.HTTP_200_OK
        root = ET.fromstring(response.content)

        # Assert that there is only on Program in the returned data even though 2
        # are created in setup
        assert len(root.findall('product')) == 2
        print(root.findall('product/[pid="{}"]'.format(self.program.uuid)))
        self._assert_product_xml(
            root.findall('product/[pid="{}"]'.format(self.program.uuid))[0],
            self.program)

        self._assert_product_xml(
            root.findall('product/[pid="{}"]'.format(mm_program.uuid))[0],
            mm_program)

        # Verify that the Masters program is not in the data
        assert not root.findall('product/[pid="{}"]'.format(
            self.ms_program.uuid))
    def test_to_representation(self):
        request = make_request()
        # TODO Create test-only model to avoid unnecessary dependency on Program model.
        program = ProgramFactory(banner_image=make_image_file('test.jpg'))
        field = StdImageSerializerField()
        field._context = {'request': request}  # pylint: disable=protected-access

        expected = {
            size_key: {
                'url':
                '{}{}'.format('http://testserver',
                              getattr(program.banner_image, size_key).url),
                'width':
                program.banner_image.field.variations[size_key]['width'],
                'height':
                program.banner_image.field.variations[size_key]['height']
            }
            for size_key in program.banner_image.field.variations
        }

        self.assertDictEqual(field.to_representation(program.banner_image),
                             expected)
    def create_program(self, courses=None):
        organizations = [OrganizationFactory(partner=self.partner)]
        person = PersonFactory()

        if courses is None:
            courses = [CourseFactory(partner=self.partner)]
            CourseRunFactory(course=courses[0], staff=[person])

        program = 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),
            instructor_ordering=PersonFactory.create_batch(1),
            banner_image=make_image_file('test_banner.jpg'),
            video=VideoFactory(),
            partner=self.partner)
        return program
    def test_excluded_course_run(self, course_runs):
        course_list = []
        course_run_list = []
        excluded_course_run_list = []
        non_excluded_course_run_list = []
        for run in course_runs:
            course_run = CourseRunFactory(course__partner=self.partner, course__title=run['title'],
                                          status=CourseRunStatus.Published)
            course_list.append(course_run.course)
            course_run_list.append(course_run)
            if run['excluded']:
                excluded_course_run_list.append(course_run)
            else:
                non_excluded_course_run_list.append(course_run)

        program = ProgramFactory(
            courses=course_list,
            status=ProgramStatus.Active,
            excluded_course_runs=excluded_course_run_list
        )
        self.reindex_courses(program)

        with self.assertNumQueries(5):
            response = self.get_response('software', path=self.list_path)

        assert response.status_code == 200
        response_data = response.json()

        assert response_data['count'] == len(course_run_list)
        for result in response_data['results']:
            for course_run in excluded_course_run_list:
                if result.get('title') == course_run.title:
                    assert result.get('program_types') == []

            for course_run in non_excluded_course_run_list:
                if result.get('title') == course_run.title:
                    assert result.get('program_types') == course_run.program_types
Exemple #23
0
    def test_query_count_exclude_expired_course_run(self, exclude_expired,
                                                    expected_queries):
        """ Verify that there is no query explosion when excluding expired course runs. """
        program = ProgramFactory(partner=self.partner,
                                 status=ProgramStatus.Active)
        course_run = CourseRunFactory(course__partner=self.partner,
                                      status=CourseRunStatus.Published)
        course_run2 = CourseRunFactory(course=course_run.course,
                                       status=CourseRunStatus.Published)
        course_run3 = CourseRunFactory(course=course_run.course,
                                       status=CourseRunStatus.Published)
        course_run4 = CourseRunFactory(course=course_run.course,
                                       status=CourseRunStatus.Published)
        self.reindex_courses(program)

        query = {'partner': self.partner.short_code}
        if exclude_expired:
            query['exclude_expired_course_run'] = 'True'

        # Filter results by partner
        with self.assertNumQueries(expected_queries):
            response = self.get_response(query,
                                         endpoint='api:v1:search-all-list')
        assert response.status_code == 200
        response_data = response.json()
        expected = [
            self.serialize_course_run_search(run)
            for run in (course_run, course_run2, course_run3, course_run4)
        ] + [
            self.serialize_program_search(program),
            # We need to render the json, and then parse it again, to get all of the formatted
            # data the same as the data coming out of search.
            json.loads(JSONRenderer().render(
                self.serialize_course_search(
                    course_run.course)).decode('utf-8')),
        ]
        self.assertCountEqual(response_data['results'], expected)
    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_excluded_course_run(self, course_runs):
        course_list = []
        course_run_list = []
        excluded_course_run_list = []
        non_excluded_course_run_list = []
        for run in course_runs:
            course_run = CourseRunFactory(course__partner=self.partner,
                                          course__title=run['title'],
                                          status=CourseRunStatus.Published)
            course_list.append(course_run.course)
            course_run_list.append(course_run)
            if run['excluded']:
                excluded_course_run_list.append(course_run)
            else:
                non_excluded_course_run_list.append(course_run)

        ProgramFactory(courses=course_list,
                       status=ProgramStatus.Active,
                       excluded_course_runs=excluded_course_run_list)

        with self.assertNumQueries(4):
            response = self.get_response('software', faceted=False)

        self.assertEqual(response.status_code, 200)
        response_data = response.json()

        self.assertEqual(response_data['count'], len(course_run_list))
        for result in response_data['results']:
            for course_run in excluded_course_run_list:
                if result.get('title') == course_run.title:
                    self.assertEqual(result.get('program_types'), [])

            for course_run in non_excluded_course_run_list:
                if result.get('title') == course_run.title:
                    self.assertEqual(result.get('program_types'),
                                     course_run.program_types)
Exemple #26
0
    def test_typeahead_partner_filter(self):
        """ Ensure that a partner param limits results to that partner. """
        course_runs = []
        programs = []

        for partner in ['edx', 'other']:
            title = 'Belongs to partner ' + partner
            partner = PartnerFactory(short_code=partner)
            course_runs.append(
                CourseRunFactory(title=title,
                                 course=CourseFactory(partner=partner)))
            programs.append(
                ProgramFactory(title=title,
                               partner=partner,
                               status=ProgramStatus.Active))
        response = self.get_response({'q': 'partner'}, 'edx')
        self.assertEqual(response.status_code, 200)
        edx_course_run = course_runs[0]
        edx_program = programs[0]
        self.assertDictEqual(
            response.data, {
                'course_runs': [self.serialize_course_run(edx_course_run)],
                'programs': [self.serialize_program(edx_program)]
            })
Exemple #27
0
    def test_typeahead_authoring_organizations_partial_search(self):
        """ Test typeahead response with partial organization matching. """
        authoring_organizations = OrganizationFactory.create_batch(3)
        course_run = CourseRunFactory.create(course__partner=self.partner)
        program = ProgramFactory.create(partner=self.partner)
        for authoring_organization in authoring_organizations:
            course_run.authoring_organizations.add(authoring_organization)
            program.authoring_organizations.add(authoring_organization)
        course_run.save()
        program.save()
        partial_key = authoring_organizations[0].key[0:5]

        response = self.get_response({'q': partial_key})
        self.assertEqual(response.status_code, 200)

        # This call is flaky in Travis. It is reliable locally, but occasionally in our CI environment,
        # this call won't contain the data for course_runs and programs. Instead of relying on the factories
        # we now explicitly add the authoring organizations to a course_run and program and call .save()
        # in order to update the search indexes.
        expected = {
            'course_runs': [self.serialize_course_run_search(course_run)],
            'programs': [self.serialize_program_search(program)]
        }
        self.assertDictEqual(response.data, expected)
 def test_special_character_synonyms(self):
     """ Test that synonyms work with special characters (non ascii) """
     ProgramFactory(title='spanish', partner=self.partner)
     response1 = self.process_response({'q': 'spanish'})
     response2 = self.process_response({'q': 'español'})
     self.assertDictEqual(response1, response2)
Exemple #29
0
 def setUp(self):
     super(UploadToFieldNamePathTests, self).setUp()
     self.program = ProgramFactory()
 def test_to_representation(self):
     """ Should be using provided serializer, rather than the slug """
     program = ProgramFactory()
     serializer = SlugRelatedFieldWithReadSerializer(slug_field='uuid', queryset=Program.objects.all(),
                                                     read_serializer=ProgramSerializer())
     self.assertIsInstance(serializer.to_representation(program), dict)
    def test_update_node_alias(self):
        """
        Verify that the publisher attempts to create a new alias when necessary
        and deletes an old alias, if one existed, and that appropriate exceptions
        are raised for non-200 status codes.
        """
        # No previous object is provided. Create a new node and make sure
        # title alias created, by default, based on the title is deleted
        # and a new alias based on marketing slug is created.
        self.mock_api_client()
        self.mock_get_alias_form()
        self.mock_get_delete_form(self.obj.title)
        self.mock_delete_alias()
        self.mock_get_delete_form(self.obj.marketing_slug)
        self.mock_add_alias()

        self.publisher.update_node_alias(self.obj, self.node_id, None)

        assert responses.calls[-1].request.url == '{}/add'.format(
            self.publisher.alias_api_base)

        responses.reset()

        # Same scenario, but this time a non-200 status code is returned during
        # alias creation. An exception should be raised.
        self.mock_api_client()
        self.mock_get_alias_form()
        self.mock_get_delete_form(self.obj.title)
        self.mock_delete_alias()
        self.mock_get_delete_form(self.obj.marketing_slug)
        self.mock_add_alias(status=500)

        with pytest.raises(AliasCreateError):
            self.publisher.update_node_alias(self.obj, self.node_id, None)

        responses.reset()

        # A previous object is provided, but the marketing slug hasn't changed.
        # Neither alias creation nor alias deletion should occur.
        self.mock_api_client()
        self.mock_get_delete_form(self.obj.marketing_slug)

        self.publisher.update_node_alias(self.obj, self.node_id, self.obj)

        responses.reset()

        # A previous object is provided, and the marketing slug has changed.
        # Both alias creation and alias deletion should occur.
        previous_obj = ProgramFactory()

        self.mock_api_client()
        self.mock_get_delete_form(self.obj.marketing_slug)
        self.mock_get_delete_form(previous_obj.marketing_slug)
        self.mock_delete_alias_form()
        self.mock_delete_alias()
        self.mock_get_alias_form()
        self.mock_get_delete_form(self.obj.marketing_slug)
        self.mock_add_alias()

        self.publisher.update_node_alias(self.obj, self.node_id, previous_obj)

        assert any('/add' in call.request.url for call in responses.calls)
        assert any(
            '/list/{}'.format(previous_obj.marketing_slug) in call.request.url
            for call in responses.calls)

        responses.reset()

        # Same scenario, but this time a non-200 status code is returned during
        # alias deletion. An exception should be raised.
        self.mock_api_client()
        self.mock_get_delete_form(self.obj.marketing_slug)
        self.mock_get_delete_form(previous_obj.marketing_slug)
        self.mock_delete_alias_form()
        self.mock_delete_alias(status=500)

        with pytest.raises(AliasDeleteError):
            self.publisher.update_node_alias(self.obj, self.node_id,
                                             previous_obj)
Exemple #32
0
 def test_marketable_exclusions(self):
     """ Verify the method excludes Programs without a marketing slug. """
     ProgramFactory(marketing_slug='')
     assert Program.objects.marketable().count() == 0
Exemple #33
0
 def test_marketable(self, status, is_marketable):
     """ Verify the method filters Programs to those which are active and have marketing slugs. """
     program = ProgramFactory(status=status)
     expected = [program] if is_marketable else []
     assert list(Program.objects.marketable()) == expected
 def test_create_command_overwrite(self):
     # Verify that the program can be overwritten
     ProgramFactory(title='test-program', subtitle='test')
     call_command('create_test_program', *self.command_args)
     test_program = Program.objects.get(title='test-program')
     assert test_program.subtitle != 'test'
 def build_program(self, **kwargs):
     """ Build a Program that will be visible in search results."""
     kwargs.update({'status': ProgramStatus.Active})
     return ProgramFactory(**kwargs)
class MarketingSitePublisherTests(MarketingSitePublisherTestMixin):
    """
    Unit test cases for the MarketingSitePublisher
    """
    def setUp(self):
        super(MarketingSitePublisherTests, self).setUp()
        self.program = ProgramFactory()
        self.program.partner.marketing_site_url_root = self.api_root
        self.program.partner.marketing_site_api_username = self.username
        self.program.partner.marketing_site_api_password = self.password
        self.program.type = ProgramType.objects.get(name='MicroMasters')
        self.program.save()  # pylint: disable=no-member
        self.api_client = MarketingSiteAPIClient(
            self.username,
            self.password,
            self.api_root
        )

    def test_get_node_data(self):
        publisher = MarketingSitePublisher()
        publish_data = publisher._get_node_data(self.program, self.user_id)  # pylint: disable=protected-access
        expected = {
            'type': str(self.program.type).lower(),
            'title': self.program.title,
            'field_uuid': str(self.program.uuid),
            'uuid': str(self.program.uuid),
            'author': {
                'id': self.user_id,
            },
            'status': 1 if self.program.status == ProgramStatus.Active else 0
        }
        self.assertDictEqual(publish_data, expected)

    @responses.activate
    def test_get_node_id(self):
        self.mock_api_client(200)
        self.mock_node_retrieval(self.program.uuid)
        publisher = MarketingSitePublisher()
        node_id = publisher._get_node_id(self.api_client, self.program.uuid)  # pylint: disable=protected-access
        self.assert_responses_call_count(4)
        self.assertEqual(node_id, self.nid)

    @responses.activate
    def test_get_non_existent_node_id(self):
        self.mock_api_client(200)
        self.mock_node_retrieval(self.program.uuid, exists=False)
        publisher = MarketingSitePublisher()
        node_id = publisher._get_node_id(self.api_client, self.program.uuid)  # pylint: disable=protected-access
        self.assertIsNone(node_id)

    @responses.activate
    def test_edit_node(self):
        self.mock_api_client(200)
        self.mock_node_edit(200)
        publisher = MarketingSitePublisher()
        publish_data = publisher._get_node_data(self.program, self.user_id)  # pylint: disable=protected-access
        publisher._edit_node(self.api_client, self.nid, publish_data)  # pylint: disable=protected-access
        self.assert_responses_call_count(4)

    @responses.activate
    def test_edit_node_failed(self):
        self.mock_api_client(200)
        self.mock_node_edit(500)
        publisher = MarketingSitePublisher()
        publish_data = publisher._get_node_data(self.program, self.user_id)  # pylint: disable=protected-access
        with self.assertRaises(ProgramPublisherException):
            publisher._edit_node(self.api_client, self.nid, publish_data)  # pylint: disable=protected-access

    @responses.activate
    def test_create_node(self):
        self.mock_api_client(200)
        expected = {
            'list': [{
                'nid': self.nid
            }]
        }
        self.mock_node_create(expected, 201)
        publisher = MarketingSitePublisher()
        publish_data = publisher._get_node_data(self.program, self.user_id)  # pylint: disable=protected-access
        data = publisher._create_node(self.api_client, publish_data)  # pylint: disable=protected-access
        self.assertEqual(data, expected)

    @responses.activate
    def test_create_node_failed(self):
        self.mock_api_client(200)
        self.mock_node_create({}, 500)
        publisher = MarketingSitePublisher()
        publish_data = publisher._get_node_data(self.program, self.user_id)  # pylint: disable=protected-access
        with self.assertRaises(ProgramPublisherException):
            publisher._create_node(self.api_client, publish_data)  # pylint: disable=protected-access

    @responses.activate
    def test_publish_program_create(self):
        self.mock_api_client(200)
        expected = {
            'list': [{
                'nid': self.nid
            }]
        }
        self.mock_node_retrieval(self.program.uuid, exists=False)
        self.mock_node_create(expected, 201)
        publisher = MarketingSitePublisher()
        publisher.publish_program(self.program)
        self.assert_responses_call_count(6)

    @responses.activate
    def test_publish_program_edit(self):
        self.mock_api_client(200)
        self.mock_node_retrieval(self.program.uuid)
        self.mock_node_edit(200)
        publisher = MarketingSitePublisher()
        publisher.publish_program(self.program)
        self.assert_responses_call_count(6)

    @responses.activate
    def test_publish_modified_program(self):
        self.mock_api_client(200)
        self.mock_node_retrieval(self.program.uuid)
        self.mock_node_edit(200)
        program_before = ProgramFactory()
        publisher = MarketingSitePublisher(program_before)
        publisher.publish_program(self.program)
        self.assert_responses_call_count(6)

    @responses.activate
    def test_publish_unmodified_program(self):
        self.mock_api_client(200)
        publisher = MarketingSitePublisher(self.program)
        publisher.publish_program(self.program)
        self.assert_responses_call_count(0)

    @responses.activate
    def test_publish_xseries_program(self):
        self.program.type = ProgramType.objects.get(name='XSeries')
        publisher = MarketingSitePublisher()
        publisher.publish_program(self.program)
        self.assert_responses_call_count(0)

    @responses.activate
    def test_publish_program_no_credential(self):
        self.program.partner.marketing_site_api_password = None
        self.program.partner.marketing_site_api_username = None
        publisher = MarketingSitePublisher()
        with self.assertRaises(ProgramPublisherException):
            publisher.publish_program(self.program)
            self.assert_responses_call_count(0)

    @responses.activate
    def test_publish_delete_program(self):
        self.mock_api_client(200)
        self.mock_node_retrieval(self.program.uuid)
        self.mock_node_delete(204)
        publisher = MarketingSitePublisher()
        publisher.delete_program(self.program)
        self.assert_responses_call_count(5)

    @responses.activate
    def test_publish_delete_non_existent_program(self):
        self.mock_api_client(200)
        self.mock_node_retrieval(self.program.uuid, exists=False)
        publisher = MarketingSitePublisher()
        publisher.delete_program(self.program)
        self.assert_responses_call_count(4)