def test_results_filtered_by_default_partner(self):
        """ Verify the search results only include items related to the default partner if no partner is
        specified on the request. If a partner is included, the data should be filtered to the requested partner. """
        course_run = CourseRunFactory(course__partner=self.partner, status=CourseRunStatus.Published)
        program = ProgramFactory(partner=self.partner, status=ProgramStatus.Active)

        # This data should NOT be in the results
        other_partner = PartnerFactory()
        other_course_run = CourseRunFactory(course__partner=other_partner, status=CourseRunStatus.Published)
        other_program = ProgramFactory(partner=other_partner, status=ProgramStatus.Active)
        assert other_program.partner.short_code != self.partner.short_code
        assert other_course_run.course.partner.short_code != self.partner.short_code

        response = self.get_response()
        assert response.status_code == 200
        response_data = response.json()
        assert response_data['objects']['results'] == \
            [self.serialize_program_search(program), self.serialize_course_run_search(course_run)]

        # Filter results by partner
        response = self.get_response({'partner': other_partner.short_code})
        assert response.status_code == 200
        response_data = response.json()
        assert response_data['objects']['results'] == \
            [self.serialize_program_search(other_program), self.serialize_course_run_search(other_course_run)]
    def test_results_filtered_by_default_partner(self):
        """ Verify the search results only include items related to the default partner if no partner is
        specified on the request. If a partner is included, the data should be filtered to the requested partner. """
        course_run = CourseRunFactory(course__partner=self.partner,
                                      status=CourseRunStatus.Published)
        program = ProgramFactory(partner=self.partner,
                                 status=ProgramStatus.Active)

        # This data should NOT be in the results
        other_partner = PartnerFactory()
        other_course_run = CourseRunFactory(course__partner=other_partner,
                                            status=CourseRunStatus.Published)
        other_program = ProgramFactory(partner=other_partner,
                                       status=ProgramStatus.Active)
        self.assertNotEqual(other_program.partner.short_code,
                            self.partner.short_code)
        self.assertNotEqual(other_course_run.course.partner.short_code,
                            self.partner.short_code)

        response = self.get_response()
        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)
        ])

        # Filter results by partner
        response = self.get_response({'partner': other_partner.short_code})
        self.assertEqual(response.status_code, 200)
        response_data = json.loads(response.content.decode('utf-8'))
        self.assertListEqual(response_data['objects']['results'], [
            self.serialize_program(other_program),
            self.serialize_course_run(other_course_run)
        ])
Exemple #3
0
    def setUp(self):
        super().setUp()
        self.user = UserFactory()
        self.client.force_authenticate(self.user)
        self.catalog = CatalogFactory(query='*:*', program_query='*:*', viewers=[self.user])

        self.enrollment_end = datetime.datetime.now(pytz.UTC) + datetime.timedelta(days=30)
        self.course_end = datetime.datetime.now(pytz.UTC) + datetime.timedelta(days=60)
        self.course_run = CourseRunFactory(enrollment_end=self.enrollment_end, end=self.course_end)
        self.course = self.course_run.course

        # Generate test programs
        self.test_image = make_image_file('test_banner.jpg')
        self.masters_program_type = ProgramType.objects.get(slug=ProgramType.MASTERS)
        self.microbachelors_program_type = ProgramType.objects.get(slug=ProgramType.MICROBACHELORS)
        self.ms_program = ProgramFactory(
            type=self.masters_program_type,
            courses=[self.course],
            banner_image=self.test_image,
        )
        self.program = ProgramFactory(
            type=self.microbachelors_program_type,
            courses=[self.course],
            banner_image=self.test_image,
        )

        self.affiliate_url = reverse('api:v1:partners:programs_affiliate_window-detail', kwargs={'pk': self.catalog.id})
    def test_exclude_unavailable_program_types(self, path, serializer, result_location_keys, program_status,
                                               expected_queries):
        """ Verify that unavailable programs do not show in the program_types representation. """
        course_run = CourseRunFactory(course__partner=self.partner, course__title='Software Testing',
                                      status=CourseRunStatus.Published)
        active_program = ProgramFactory(courses=[course_run.course], status=ProgramStatus.Active)
        ProgramFactory(courses=[course_run.course], status=program_status)
        self.reindex_courses(active_program)

        with self.assertNumQueries(expected_queries):
            response = self.get_response('software', path=path)
            assert response.status_code == 200
            response_data = response.json()

            # Validate the search results
            expected = {
                'count': 1,
                'results': [
                    self.serialize_course_run_search(course_run, serializer=serializer)
                ]
            }
            self.assertDictContainsSubset(expected, response_data)

            # Check that the program is indeed the active one.
            for key in result_location_keys:
                response_data = response_data[key]
            assert response_data == active_program.type.name
Exemple #5
0
 def test_typeahead_org_course_runs_come_up_first(self):
     """ Test typeahead response to ensure org is taken into account. """
     MITx = OrganizationFactory(key='MITx')
     HarvardX = OrganizationFactory(key='HarvardX')
     mit_run = CourseRunFactory(authoring_organizations=[MITx, HarvardX],
                                title='MIT Testing1',
                                course__partner=self.partner)
     harvard_run = CourseRunFactory(authoring_organizations=[HarvardX],
                                    title='MIT Testing2',
                                    course__partner=self.partner)
     mit_program = ProgramFactory(authoring_organizations=[MITx, HarvardX],
                                  title='MIT Testing1',
                                  partner=self.partner)
     harvard_program = ProgramFactory(authoring_organizations=[HarvardX],
                                      title='MIT Testing2',
                                      partner=self.partner)
     response = self.get_response({'q': 'mit'})
     self.assertEqual(response.status_code, 200)
     expected = {
         'course_runs': [
             self.serialize_course_run_search(mit_run),
             self.serialize_course_run_search(harvard_run)
         ],
         'programs': [
             self.serialize_program_search(mit_program),
             self.serialize_program_search(harvard_program)
         ]
     }
     self.assertDictEqual(response.data, expected)
Exemple #6
0
 def test_unpublished_and_hidden_courses(self):
     """ Verify that typeahead does not return unpublished or hidden courses
     or programs that are not active. """
     title = "supply"
     course_run = CourseRunFactory(title=title,
                                   course__partner=self.partner)
     CourseRunFactory(title=title + "unpublished",
                      status=CourseRunStatus.Unpublished,
                      course__partner=self.partner)
     CourseRunFactory(title=title + "hidden",
                      hidden=True,
                      course__partner=self.partner)
     program = ProgramFactory(title=title,
                              status=ProgramStatus.Active,
                              partner=self.partner)
     ProgramFactory(title=title + "unpublished",
                    status=ProgramStatus.Unpublished,
                    partner=self.partner)
     query = "suppl"
     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_get_choices_cutoff(self):
     """ We should slice the queryset if provided a cutoff parameter """
     ProgramFactory()
     ProgramFactory()
     serializer = SlugRelatedFieldWithReadSerializer(slug_field='uuid', queryset=Program.objects.all(),
                                                     read_serializer=ProgramSerializer())
     self.assertEqual(len(serializer.get_choices()), 2)
     self.assertEqual(len(serializer.get_choices(cutoff=1)), 1)
Exemple #8
0
    def test_program_type_boosting(self, program_type):
        """Verify MicroMasters and Professional Certificate are boosted over XSeries."""
        ProgramFactory(type=ProgramType.objects.get(translations__name_t='XSeries'))
        test_record = ProgramFactory(type=ProgramType.objects.get(translations__name_t=program_type))

        search_results = SearchQuerySet().models(Program).all()
        assert len(search_results) == 2
        assert search_results[0].score > search_results[1].score
        assert str(test_record.type) == str(search_results[0].type)
    def test_only_matching_partner(self):
        pathway = PathwayFactory(partner=self.partner)
        pathway.programs.add(ProgramFactory(partner=pathway.partner))

        non_partner_pathway = PathwayFactory()
        non_partner_pathway.programs.add(ProgramFactory(partner=non_partner_pathway.partner))

        response = self.client.get(self.list_path)
        assert response.status_code == 200
        assert response.data['results'] == self.serialize_pathway([pathway], many=True)
Exemple #10
0
    def test_program_type_boosting(self, program_type):
        """ Verify MicroMasters and Professional Certificate are boosted over XSeries."""
        ProgramFactory(type=ProgramType.objects.get(name='XSeries'))
        test_record = ProgramFactory(type=ProgramType.objects.get(
            name=program_type))

        search_results = SearchQuerySet().models(Program).all()
        self.assertEqual(2, len(search_results))
        self.assertGreater(search_results[0].score, search_results[1].score)
        self.assertEqual(str(test_record.type), str(search_results[0].type))
Exemple #11
0
 def test_program_type_boosting(self, program_type):
     """Verify MicroMasters and Professional Certificate are boosted over XSeries."""
     ProgramFactory(type=ProgramType.objects.get(
         translations__name_t='XSeries'))
     test_record = ProgramFactory(type=ProgramType.objects.get(
         translations__name_t=program_type))
     search_results = ProgramDocument.search().query(
         ESDSLQ('match_all')).execute()
     assert len(search_results) == 2
     assert search_results[0].meta['score'] > search_results[1].meta['score']
     assert str(test_record.type) == str(search_results[0].type)
Exemple #12
0
    def setUp(self):
        super(TestLoadProgramFixture, self).setUp()
        self.pk_generator = itertools.count(1)

        stored_site, created = Site.objects.get_or_create(  # pylint: disable=unused-variable
            domain='example.com')
        self.default_partner = Partner.objects.create(site=stored_site,
                                                      name='edX',
                                                      short_code='edx')

        SeatType.objects.all().delete()
        ProgramType.objects.all().delete()

        self.partner = PartnerFactory(name='Test')
        self.organization = OrganizationFactory(partner=self.partner)
        self.seat_type_verified = SeatTypeFactory(name='Verified',
                                                  slug='verified')
        self.program_type_masters = ProgramTypeFactory(
            name='Masters',
            slug='masters',
            applicable_seat_types=[self.seat_type_verified])

        self.program_type_mm = ProgramTypeFactory(
            name='MicroMasters',
            slug='micromasters',
            applicable_seat_types=[self.seat_type_verified])

        self.course = CourseFactory(
            partner=self.partner, authoring_organizations=[self.organization])
        self.course_run = CourseRunFactory(course=self.course)
        self.program = ProgramFactory(
            type=self.program_type_masters,
            partner=self.partner,
            authoring_organizations=[self.organization])
        self.course_mm = CourseFactory(
            partner=self.partner, authoring_organizations=[self.organization])
        self.course_run_mm = CourseRunFactory(course=self.course)
        self.program_mm = ProgramFactory(
            type=self.program_type_mm,
            partner=self.partner,
            authoring_organizations=[self.organization],
            courses=[self.course_mm])
        self.curriculum = CurriculumFactory(program=self.program)
        self.curriculum_course_membership = CurriculumCourseMembershipFactory(
            course=self.course, curriculum=self.curriculum)
        self.curriculum_program_membership = CurriculumProgramMembershipFactory(
            program=self.program_mm, curriculum=self.curriculum)

        self.program_2 = ProgramFactory(
            type=self.program_type_masters,
            partner=self.partner,
            authoring_organizations=[self.organization])

        self._mock_oauth_request()
Exemple #13
0
 def testNormalRun(self):
     program = ProgramFactory()
     program1 = ProgramFactory()
     self.config.program_hooks = '''{uuid}:Bananas in pajamas
     {uuid1}:Are coming down the stairs'''.format(uuid=program.uuid, uuid1=program1.uuid)
     self.config.save()
     call_command('modify_program_hooks')
     program.refresh_from_db()
     program1.refresh_from_db()
     self.assertEqual(program.marketing_hook, 'Bananas in pajamas')
     self.assertEqual(program1.marketing_hook, 'Are coming down the stairs')
 def test_typeahead_hidden_programs(self):
     """ Verify that typeahead does not return hidden programs. """
     title = "hiddenprogram"
     program = ProgramFactory(title=title, hidden=False, status=ProgramStatus.Active, partner=self.partner)
     ProgramFactory(title=program.title + 'hidden', hidden=True, status=ProgramStatus.Active, partner=self.partner)
     response = self.get_response({'q': program.title})
     self.assertEqual(response.status_code, 200)
     response_data = response.json()
     expected_response_data = {
         'course_runs': [],
         'programs': [self.serialize_program_search(program)]
     }
     self.assertDictEqual(response_data, expected_response_data)
Exemple #15
0
    def test_filter_by_status(self):
        """ Verify the endpoint allows programs to filtered by one, or more, statuses. """
        active = ProgramFactory(status=ProgramStatus.Active, partner=self.partner)
        retired = ProgramFactory(status=ProgramStatus.Retired, partner=self.partner)

        url = self.list_path + '?status=active'
        self.assert_list_results(url, [active], 10)

        url = self.list_path + '?status=retired'
        self.assert_list_results(url, [retired], 10)

        url = self.list_path + '?status=active&status=retired'
        self.assert_list_results(url, [retired, active], 10)
    def test_results_only_include_published_objects(self):
        """ Verify the search results only include items with status set to 'Published'. """
        # These items should NOT be in the results
        CourseRunFactory(course__partner=self.partner, status=CourseRunStatus.Unpublished)
        ProgramFactory(partner=self.partner, status=ProgramStatus.Unpublished)

        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()
        assert response_data['objects']['results'] == \
            [self.serialize_program_search(program), self.serialize_course_run_search(course_run)]
Exemple #17
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)
Exemple #18
0
    def test_filter_by_hidden(self):
        """ Endpoint should filter programs by their hidden attribute value. """
        hidden = ProgramFactory(hidden=True, partner=self.partner)
        not_hidden = ProgramFactory(hidden=False, partner=self.partner)

        url = self.list_path + '?hidden=True'
        self.assert_list_results(url, [hidden], 11)

        url = self.list_path + '?hidden=False'
        self.assert_list_results(url, [not_hidden], 11)

        url = self.list_path + '?hidden=1'
        self.assert_list_results(url, [hidden], 11)

        url = self.list_path + '?hidden=0'
        self.assert_list_results(url, [not_hidden], 11)
Exemple #19
0
    def test_uuids_only(self):
        """
        Verify that the list view returns a simply list of UUIDs when the
        uuids_only query parameter is passed.
        """
        active = ProgramFactory.create_batch(3, partner=self.partner)
        retired = [
            ProgramFactory(status=ProgramStatus.Retired, partner=self.partner)
        ]
        programs = active + retired

        querystring = {'uuids_only': 1}
        url = '{base}?{query}'.format(
            base=self.list_path, query=urllib.parse.urlencode(querystring))
        response = self.client.get(url)

        assert set(response.data) == {program.uuid for program in programs}

        # Verify that filtering (e.g., by status) is still supported.
        querystring['status'] = ProgramStatus.Retired
        url = '{base}?{query}'.format(
            base=self.list_path, query=urllib.parse.urlencode(querystring))
        response = self.client.get(url)

        assert set(response.data) == {program.uuid for program in retired}
Exemple #20
0
 def test_retrieve_without_course_runs(self, django_assert_num_queries):
     """ Verify the endpoint returns data for a program even if the program's courses have no course runs. """
     course = CourseFactory(partner=self.partner)
     program = ProgramFactory(courses=[course], partner=self.partner)
     with django_assert_num_queries(FuzzyInt(27, 2)):
         response = self.assert_retrieve_success(program)
     assert response.data == self.serialize_program(program)
Exemple #21
0
 def test_retrieve_without_course_runs(self):
     """ Verify the endpoint returns data for a program even if the program's courses have no course runs. """
     course = CourseFactory()
     program = ProgramFactory(courses=[course])
     with self.assertNumQueries(19):
         response = self.assert_retrieve_success(program)
     assert response.data == self.serialize_program(program)
    def _define_course_metadata(self):
        # Add course runs, courses, and programs to DB to copy data into
        courses = {}
        # Course runs map to courses in the way opaque keys would (without actually using opaque keys code)
        course_to_run_mapping = {
            '00test/00test/00test': '00test/00test',
            '00test/00test/01test': '00test/00test',
            '00test/01test/00test': '00test/01test',
            '00test/01test/01test': '00test/01test',
            '00test/01test/02test': '00test/01test',
            '00test/02test/00test': '00test/02test'
        }
        for course_summary in self.mocked_data:
            course_run_key = course_summary['course_id']
            course_key = course_to_run_mapping[course_run_key]
            if course_key in courses:
                course = courses[course_key]
                course_run = CourseRunFactory(key=course_summary['course_id'],
                                              course=course)
                course_run.save()
            else:
                course = CourseFactory(key=course_key)
                course.save()
                course_run = CourseRunFactory(key=course_summary['course_id'],
                                              course=course)
                course_run.save()
                courses[course_key] = course_run.course

        # Create a program with all of the courses we created
        program = ProgramFactory()
        program.courses.set(courses.values())  # pylint: disable=no-member
 def test_stemmed_synonyms(self):
     """ Test that synonyms work with stemming from the snowball analyzer """
     title = 'Running'
     ProgramFactory(title=title, partner=self.partner)
     response1 = self.process_response({'q': 'running'})
     response2 = self.process_response({'q': 'jogging'})
     self.assertDictEqual(response1, response2)
 def test_title_synonyms(self):
     """ Test that synonyms work for terms in the title """
     CourseRunFactory(title='HTML', course__partner=self.partner)
     ProgramFactory(title='HTML', partner=self.partner)
     response1 = self.process_response({'q': 'HTML5'})
     response2 = self.process_response({'q': 'HTML'})
     self.assertDictEqual(response1, response2)
Exemple #25
0
 def testWeirdCharactersInHookText(self):
     program = ProgramFactory()
     self.config.program_hooks = '%s:+:[{])(%%' % program.uuid
     self.config.save()
     call_command('modify_program_hooks')
     program.refresh_from_db()
     self.assertEqual(program.marketing_hook, '+:[{])(%')
    def test_with_exclusions(self):
        """
        Test serializer with course_run exclusions within program
        """
        request = make_request()
        course = CourseFactory()
        excluded_runs = []
        course_runs = CourseRunFactory.create_batch(2, course=course)
        excluded_runs.append(course_runs[0])
        program = ProgramFactory(courses=[course],
                                 excluded_course_runs=excluded_runs)

        serializer_context = {
            'request': request,
            'program': program,
            'course_runs': list(program.course_runs)
        }
        serializer = MinimalProgramCourseSerializer(course,
                                                    context=serializer_context)

        expected = MinimalCourseSerializer(course,
                                           context=serializer_context).data
        expected['course_runs'] = MinimalCourseRunSerializer([course_runs[1]],
                                                             many=True,
                                                             context={
                                                                 'request':
                                                                 request
                                                             }).data
        self.assertDictEqual(serializer.data, expected)
    def test_with_published_course_runs_only_context(self):
        """ Verify setting the published_course_runs_only context value excludes unpublished course runs. """
        # Create a program and course. The course should have both published and un-published course runs.
        request = make_request()
        course = CourseFactory()
        program = ProgramFactory(courses=[course])
        unpublished_course_run = CourseRunFactory(
            status=CourseRunStatus.Unpublished, course=course)
        CourseRunFactory(status=CourseRunStatus.Published, course=course)

        # We do NOT expect the results to included the unpublished data
        expected = MinimalCourseSerializer(course,
                                           context={
                                               'request': request
                                           }).data
        expected['course_runs'] = [
            course_run for course_run in expected['course_runs']
            if course_run['key'] != str(unpublished_course_run.key)
        ]
        self.assertEqual(len(expected['course_runs']), 1)

        serializer = MinimalProgramCourseSerializer(
            course,
            context={
                'request': request,
                'program': program,
                'published_course_runs_only': True,
                'course_runs': list(program.course_runs),
            })

        self.assertSequenceEqual(serializer.data, expected)
 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())
     assert isinstance(serializer.to_representation(program), dict)
Exemple #29
0
 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)
 def test_get_exclude_deleted_programs(self):
     """ Verify the endpoint returns no deleted associated programs """
     ProgramFactory(courses=[self.course], status=ProgramStatus.Deleted)
     url = reverse('api:v1:course-detail', kwargs={'key': self.course.key})
     with self.assertNumQueries(18):
         response = self.client.get(url)
         self.assertEqual(response.status_code, 200)
         self.assertEqual(response.data.get('programs'), [])