예제 #1
0
    def setUpClass(cls):
        """
        Sets up the tree for testing external course keys

        program          1         2
                        / \\       |
        curriculum    1    2      3
                      |     \\   / \\
        course        1        2     3
        """
        super().setUpClass()
        cls.program_1 = factories.ProgramFactory(title='program_1')
        cls.program_2 = factories.ProgramFactory(title='program_2')
        cls.programs = [None, cls.program_1, cls.program_2]
        cls.course_1 = cls._create_course_and_runs(1)
        cls.course_2 = cls._create_course_and_runs(2)
        cls.course_3 = cls._create_course_and_runs(3)
        cls.curriculum_1 = factories.CurriculumFactory(
            name='curriculum_1',
            program=cls.program_1,
        )
        cls.curriculum_2 = factories.CurriculumFactory(
            name='curriculum_2',
            program=cls.program_1,
        )
        cls.curriculum_3 = factories.CurriculumFactory(
            name='curriculum_3',
            program=cls.program_2,
        )
        cls.curriculums = [None, cls.curriculum_1, cls.curriculum_2, cls.curriculum_3]
        cls._add_courses_to_curriculum(cls.curriculum_1, cls.course_1)
        cls._add_courses_to_curriculum(cls.curriculum_2, cls.course_2)
        cls._add_courses_to_curriculum(cls.curriculum_3, cls.course_2, cls.course_3)
예제 #2
0
 def test_program_types(self):
     """ Verify the property retrieves program types correctly based on programs. """
     courses = [self.course_run.course]
     program = factories.ProgramFactory(courses=courses)
     other_program = factories.ProgramFactory(courses=courses)
     self.assertCountEqual(self.course_run.program_types,
                           [program.type.name, other_program.type.name])
예제 #3
0
    def test_program_with_different_partner(self):
        """
        Tests that contained programs can't be for the wrong partner
        """
        partner1 = PartnerFactory()
        partner2 = PartnerFactory()
        program1 = factories.ProgramFactory(partner=partner1)
        program2 = factories.ProgramFactory(partner=partner2,
                                            title='partner2 program')
        data = {
            'partner': partner1.id,
            'name': 'Name',
            'org_name': 'Org',
            'email': '*****@*****.**',
            'programs': [program1.id, program2.id],
            'pathway_type': PathwayType.INDUSTRY.value,
        }
        form = PathwayAdminForm(data=data)

        self.assertDictEqual(
            form.errors, {
                '__all__': [
                    'These programs are for a different partner than the pathway itself: partner2 program'
                ]
            })
예제 #4
0
 def test_unpublished_program_types(self):
     """ Verify the property exludes program types that are unpublished. """
     courses = [self.course_run.course]
     program = factories.ProgramFactory(courses=courses)
     factories.ProgramFactory(courses=courses,
                              status=ProgramStatus.Unpublished)
     self.assertEqual(self.course_run.program_types, [program.type.name])
예제 #5
0
    def test_mix_of_curriculums_with_and_without_programs(self):
        course_a = self._create_course_and_runs('a')
        course_b = self._create_course_and_runs('b')
        course_c = self._create_course_and_runs('c')
        program_1 = factories.ProgramFactory(title='program_1')
        program_2 = factories.ProgramFactory(title='program_2')
        curriculum_1 = factories.CurriculumFactory(program=program_1)
        curriculum_2 = factories.CurriculumFactory(program=program_2)
        curriculum_3 = factories.CurriculumFactory(program=None)
        curriculum_4 = factories.CurriculumFactory(program=None)
        self._add_courses_to_curriculum(curriculum_1, course_a, course_b)
        self._add_courses_to_curriculum(curriculum_2, course_a, course_b)
        self._add_courses_to_curriculum(curriculum_3, course_a, course_b, course_c)
        self._add_courses_to_curriculum(curriculum_4, course_a, course_b, course_c)

        course_run = course_a.course_runs.first()
        course_run_ca = CourseRun.objects.get(external_key='ext-key-course-ca')
        message = _duplicate_external_key_message([course_run_ca])
        with self.assertNumQueries(FuzzyInt(6, 1)):  # 3 Selects
            with self.assertRaisesRegex(ValidationError, escape(message)):
                course_run.external_key = course_run_ca.external_key
                course_run.save()

        with self.assertNumQueries(FuzzyInt(36, 1)):
            course_run.external_key = 'some-safe-key'
            course_run.save()
예제 #6
0
 def test_exclude_deleted_program_types(self):
     """ Verify the program types property exclude programs that are deleted """
     active_program = factories.ProgramFactory(
         courses=[self.course_run.course])
     factories.ProgramFactory(courses=[self.course_run.course],
                              status=ProgramStatus.Deleted)
     self.assertEqual(self.course_run.program_types,
                      [active_program.type.name])
예제 #7
0
    def test_one_click_purchase_eligible_with_unpublished_runs(self):
        """ Verify that program with unpublished course runs is one click purchase eligible. """

        verified_seat_type, __ = SeatType.objects.get_or_create(
            name=Seat.VERIFIED)
        program_type = factories.ProgramTypeFactory(
            applicable_seat_types=[verified_seat_type])
        published_course_run = factories.CourseRunFactory(
            end=None, enrollment_end=None, status=CourseRunStatus.Published)
        unpublished_course_run = factories.CourseRunFactory(
            end=None,
            enrollment_end=None,
            status=CourseRunStatus.Unpublished,
            course=published_course_run.course)
        factories.SeatFactory(course_run=published_course_run,
                              type=Seat.VERIFIED,
                              upgrade_deadline=None)
        factories.SeatFactory(course_run=unpublished_course_run,
                              type=Seat.VERIFIED,
                              upgrade_deadline=None)
        program = factories.ProgramFactory(
            courses=[published_course_run.course],
            one_click_purchase_enabled=True,
            type=program_type,
        )
        self.assertTrue(program.is_program_eligible_for_one_click_purchase)
예제 #8
0
 def test_title_synonyms(self):
     """ Test that synonyms work for terms in the title """
     factories.CourseRunFactory(title='HTML', course__partner=self.partner)
     factories.ProgramFactory(title='HTML', partner=self.partner)
     response1 = self.process_response({'q': 'HTML5'})
     response2 = self.process_response({'q': 'HTML'})
     assert response1 == response2
예제 #9
0
    def create_program_with_seats(self):
        currency = Currency.objects.get(code='USD')

        course_run = factories.CourseRunFactory()
        course_run.course.canonical_course_run = course_run
        course_run.course.save()
        factories.SeatFactory(type='audit',
                              currency=currency,
                              course_run=course_run,
                              price=0)
        factories.SeatFactory(type='credit',
                              currency=currency,
                              course_run=course_run,
                              price=600)
        factories.SeatFactory(type='verified',
                              currency=currency,
                              course_run=course_run,
                              price=100)

        applicable_seat_types = SeatType.objects.filter(
            slug__in=['credit', 'verified'])
        program_type = factories.ProgramTypeFactory(
            applicable_seat_types=applicable_seat_types)

        return factories.ProgramFactory(type=program_type,
                                        courses=[course_run.course])
예제 #10
0
 def test_queryset_method_returns_eligible_programs(self):
     """ Verify that one click purchase eligible programs pass the filter. """
     verified_seat_type, __ = SeatType.objects.get_or_create(
         name=Seat.VERIFIED)
     program_type = factories.ProgramTypeFactory(
         applicable_seat_types=[verified_seat_type])
     program_filter = ProgramEligibilityFilter(None,
                                               {self.parameter_name: 1},
                                               None, None)
     course_run = factories.CourseRunFactory(
         end=None,
         enrollment_end=None,
     )
     factories.SeatFactory(course_run=course_run,
                           type='verified',
                           upgrade_deadline=None)
     one_click_purchase_eligible_program = factories.ProgramFactory(
         type=program_type,
         courses=[course_run.course],
         one_click_purchase_enabled=True,
     )
     with self.assertNumQueries(12):
         self.assertEqual(
             list(program_filter.queryset({}, Program.objects.all())),
             [one_click_purchase_eligible_program])
예제 #11
0
    def setUp(self):
        super().setUp()
        # ContentTypeManager uses a cache to speed up ContentType retrieval. This
        # cache persists across tests. This is fine in the context of a regular
        # TestCase which uses a transaction to reset the database between tests.
        # However, it becomes a problem in subclasses of TransactionTestCase which
        # truncate all tables to reset the database between tests. When tables are
        # truncated, ContentType objects in the ContentTypeManager's cache become
        # stale. Attempting to use these stale objects in tests such as the ones
        # below, which create LogEntry objects as a side-effect of interacting with
        # the admin, will result in IntegrityErrors on databases that check foreign
        # key constraints (e.g., MySQL). Preemptively clearing the cache prevents
        # stale ContentType objects from being used.
        ContentType.objects.clear_cache()

        self.site.domain = self.live_server_url.strip('http://')
        self.site.save()

        self.course_runs = factories.CourseRunFactory.create_batch(2)
        self.courses = [course_run.course for course_run in self.course_runs]

        self.excluded_course_run = factories.CourseRunFactory(course=self.courses[0])
        self.program = factories.ProgramFactory(
            courses=self.courses, excluded_course_runs=[self.excluded_course_run], status=ProgramStatus.Unpublished
        )

        self.user = UserFactory(is_staff=True, is_superuser=True)
        self._login()
예제 #12
0
 def test_stemmed_synonyms(self):
     """ Test that synonyms work with stemming from the snowball analyzer """
     title = 'Running'
     factories.ProgramFactory(title=title, partner=self.partner)
     response1 = self.process_response({'q': 'running'})
     response2 = self.process_response({'q': 'jogging'})
     assert response1 == response2
예제 #13
0
 def test_queryset_method_returns_all_programs(self):
     """ Verify that all programs pass the filter. """
     verified_seat_type = factories.SeatTypeFactory.verified()
     program_type = factories.ProgramTypeFactory(applicable_seat_types=[verified_seat_type])
     program_filter = ProgramEligibilityFilter(None, {}, None, None)
     course_run = factories.CourseRunFactory()
     factories.SeatFactory(course_run=course_run, type=verified_seat_type, upgrade_deadline=None)
     one_click_purchase_eligible_program = factories.ProgramFactory(
         type=program_type,
         courses=[course_run.course],
         one_click_purchase_enabled=True
     )
     one_click_purchase_ineligible_program = factories.ProgramFactory(courses=[course_run.course])
     with self.assertNumQueries(1):
         assert list(program_filter.queryset({}, Program.objects.all())) == \
                [one_click_purchase_eligible_program, one_click_purchase_ineligible_program]
예제 #14
0
 def setUp(self):
     super().setUp()
     # Disable marketing site password just to save us from having to mock the responses
     self.partner = factories.PartnerFactory(
         marketing_site_api_password=None)
     self.person = factories.PersonFactory(partner=self.partner,
                                           given_name='Person')
     self.target = factories.PersonFactory(partner=self.partner,
                                           given_name='Target')
     self.instructor1 = factories.PersonFactory(partner=self.partner,
                                                given_name='Instructor1')
     self.instructor2 = factories.PersonFactory(partner=self.partner,
                                                given_name='Instructor2')
     self.instructor3 = factories.PersonFactory(partner=self.partner,
                                                given_name='Instructor3')
     self.position = factories.PositionFactory(person=self.person)
     self.social1 = factories.PersonSocialNetworkFactory(person=self.person)
     self.social2 = factories.PersonSocialNetworkFactory(person=self.person)
     self.endorsement = factories.EndorsementFactory(endorser=self.person)
     self.course = factories.CourseFactory(partner=self.partner)
     self.courserun1 = factories.CourseRunFactory(course=self.course,
                                                  staff=[
                                                      self.instructor1,
                                                      self.person,
                                                      self.instructor2,
                                                      self.instructor3,
                                                  ])
     self.courserun2 = factories.CourseRunFactory(course=self.course,
                                                  staff=[
                                                      self.instructor1,
                                                      self.instructor2,
                                                      self.person,
                                                      self.instructor3,
                                                  ])
     self.program = factories.ProgramFactory(courses=[self.course],
                                             instructor_ordering=[
                                                 self.person,
                                                 self.instructor1,
                                                 self.instructor2,
                                                 self.instructor3,
                                             ])
     self.publisher_course = publisher_factories.CourseFactory()
     self.publisher_courserun1 = publisher_factories.CourseRunFactory(
         course=self.publisher_course,
         staff=[
             self.person,
             self.instructor1,
             self.instructor2,
             self.instructor3,
         ])
     self.publisher_courserun2 = publisher_factories.CourseRunFactory(
         course=self.publisher_course,
         staff=[
             self.instructor1,
             self.instructor2,
             self.instructor3,
             self.person,
         ])
예제 #15
0
 def test_course_runs(self):
     """
     Verify that we only fetch course runs for the program, and not other course runs for other programs and that the
     property returns the set of associated CourseRuns minus those that are explicitly excluded.
     """
     course_run = factories.CourseRunFactory()
     factories.ProgramFactory(courses=[course_run.course])
     # Verify that course run is not returned in set
     self.assertEqual(set(self.program.course_runs), set(self.course_runs))
예제 #16
0
 def test_queryset_method_returns_ineligible_programs(self):
     """ Verify programs ineligible for one-click purchase do not pass the filter. """
     program_filter = ProgramEligibilityFilter(None, {self.parameter_name: 0}, None, None)
     one_click_purchase_ineligible_program = factories.ProgramFactory(one_click_purchase_enabled=False)
     with self.assertNumQueries(4):
         self.assertEqual(
             list(program_filter.queryset({}, Program.objects.all())),
             [one_click_purchase_ineligible_program]
         )
예제 #17
0
    def test_one_click_purchase_eligible(self):
        """ Verify that program is one click purchase eligible. """
        verified_seat_type, __ = SeatType.objects.get_or_create(
            name=Seat.VERIFIED)
        program_type = factories.ProgramTypeFactory(
            applicable_seat_types=[verified_seat_type])

        # Program has one_click_purchase_enabled set to True,
        # all courses have one course run, all course runs have
        # verified seat types
        courses = []
        for __ in range(3):
            course_run = factories.CourseRunFactory(end=None,
                                                    enrollment_end=None)
            factories.SeatFactory(course_run=course_run,
                                  type=Seat.VERIFIED,
                                  upgrade_deadline=None)
            courses.append(course_run.course)
        program = factories.ProgramFactory(
            courses=courses,
            one_click_purchase_enabled=True,
            type=program_type,
        )
        self.assertTrue(program.is_program_eligible_for_one_click_purchase)

        # Program has one_click_purchase_enabled set to True,
        # course has all course runs excluded except one which
        # has verified seat type
        course_run = factories.CourseRunFactory(end=None, enrollment_end=None)
        factories.SeatFactory(course_run=course_run,
                              type=Seat.VERIFIED,
                              upgrade_deadline=None)
        course = course_run.course
        excluded_course_runs = [
            factories.CourseRunFactory(course=course),
            factories.CourseRunFactory(course=course)
        ]
        program = factories.ProgramFactory(
            courses=[course],
            excluded_course_runs=excluded_course_runs,
            one_click_purchase_enabled=True,
            type=program_type,
        )
        self.assertTrue(program.is_program_eligible_for_one_click_purchase)
예제 #18
0
    def setUp(self):
        super(AdminTests, self).setUp()
        self.user = UserFactory(is_staff=True, is_superuser=True)
        self.client.login(username=self.user.username, password=USER_PASSWORD)
        self.course_runs = factories.CourseRunFactory.create_batch(3)
        self.courses = [course_run.course for course_run in self.course_runs]

        self.excluded_course_run = factories.CourseRunFactory(course=self.courses[0])
        self.program = factories.ProgramFactory(
            courses=self.courses, excluded_course_runs=[self.excluded_course_run]
        )
예제 #19
0
    def setUpClass(cls):
        super().setUpClass()
        cls.user = UserFactory(is_staff=True, is_superuser=True)
        cls.course_runs = factories.CourseRunFactory.create_batch(3)
        cls.courses = [course_run.course for course_run in cls.course_runs]

        cls.excluded_course_run = factories.CourseRunFactory(course=cls.courses[0])
        cls.program = factories.ProgramFactory(
            courses=cls.courses,
            excluded_course_runs=[cls.excluded_course_run],
            partner=cls.partner,  # cls.partner provided by SiteMixin.setUpClass()
        )
예제 #20
0
    def setUpTestData(cls):
        """
        Set up program structure to test for cycles

        program           p1
                        /    \\
        curriculum     c1      c2
                      /  \\   /  \\
        program      p2    p3     p4
                     |     |
        curriculum   c3    c4
                     | \\  |
        program      p5   p6
        """
        super().setUpTestData()
        cls.program_1 = factories.ProgramFactory(title='program_1')
        cls.program_2 = factories.ProgramFactory(title='program_2')
        cls.program_3 = factories.ProgramFactory(title='program_3')
        cls.program_4 = factories.ProgramFactory(title='program_4')
        cls.program_5 = factories.ProgramFactory(title='program_5')
        cls.program_6 = factories.ProgramFactory(title='program_6')

        cls.curriculum_1 = factories.CurriculumFactory(name='curriculum_1', program=cls.program_1)
        cls.curriculum_2 = factories.CurriculumFactory(name='curriculum_2', program=cls.program_1)
        cls.curriculum_3 = factories.CurriculumFactory(name='curriculum_3', program=cls.program_2)
        cls.curriculum_4 = factories.CurriculumFactory(name='curriculum_4', program=cls.program_3)

        factories.CurriculumProgramMembershipFactory(curriculum=cls.curriculum_1, program=cls.program_2)
        factories.CurriculumProgramMembershipFactory(curriculum=cls.curriculum_1, program=cls.program_3)
        factories.CurriculumProgramMembershipFactory(curriculum=cls.curriculum_2, program=cls.program_3)
        factories.CurriculumProgramMembershipFactory(curriculum=cls.curriculum_2, program=cls.program_4)
        factories.CurriculumProgramMembershipFactory(curriculum=cls.curriculum_3, program=cls.program_5)
        factories.CurriculumProgramMembershipFactory(curriculum=cls.curriculum_3, program=cls.program_6)
        factories.CurriculumProgramMembershipFactory(curriculum=cls.curriculum_4, program=cls.program_6)
예제 #21
0
    def create_program_with_multiple_course_runs(self, set_all_dates=True):
        currency = Currency.objects.get(code='USD')
        single_course_course_runs = factories.CourseRunFactory.create_batch(3)
        course = factories.CourseFactory()
        course_runs_same_course = factories.CourseRunFactory.create_batch(
            3, course=course)
        for course_run in single_course_course_runs:
            factories.SeatFactory(type='audit',
                                  currency=currency,
                                  course_run=course_run,
                                  price=0)
            factories.SeatFactory(type='verified',
                                  currency=currency,
                                  course_run=course_run,
                                  price=10)
            course_run.course.canonical_course_run = course_run
            course_run.course.save()

        day_separation = 1
        now = datetime.datetime.utcnow()

        for course_run in course_runs_same_course:
            if set_all_dates or day_separation < 2:
                date_delta = datetime.timedelta(days=day_separation)
                course_run.enrollment_start = now - date_delta
                course_run.end = now + datetime.timedelta(weeks=day_separation)
            else:
                course_run.enrollment_start = None
                course_run.end = None
            course_run.save()
            factories.SeatFactory(type='audit',
                                  currency=currency,
                                  course_run=course_run,
                                  price=0)
            factories.SeatFactory(type='verified',
                                  currency=currency,
                                  course_run=course_run,
                                  price=(day_separation * 100))
            day_separation += 1
        course.canonical_course_run = course_runs_same_course[2]
        course.save()
        applicable_seat_types = SeatType.objects.filter(slug__in=['verified'])
        program_type = factories.ProgramTypeFactory(
            applicable_seat_types=applicable_seat_types)

        program_courses = [
            course_run.course for course_run in single_course_course_runs
        ]
        program_courses.append(course)

        return factories.ProgramFactory(type=program_type,
                                        courses=program_courses)
예제 #22
0
    def setUp(self):
        super().setUp()

        self.course_runs = factories.CourseRunFactory.create_batch(2)
        self.courses = [course_run.course for course_run in self.course_runs]

        self.excluded_course_run = factories.CourseRunFactory(course=self.courses[0])
        self.program = factories.ProgramFactory(
            courses=self.courses, excluded_course_runs=[self.excluded_course_run], status=ProgramStatus.Unpublished
        )

        self.user = UserFactory(is_staff=True, is_superuser=True)
        self._login()
예제 #23
0
 def test_modify_curriculum(self):
     course_run_1a = CourseRun.objects.get(key='course-run-id/course-1a/test')
     _, curriculum_4 = self._create_single_course_curriculum('ext-key-course-1a', 'curriculum_4')
     new_program = factories.ProgramFactory(
         curricula=[curriculum_4]
     )
     message = _duplicate_external_key_message([course_run_1a])
     with self.assertNumQueries(5):
         with self.assertRaisesRegex(ValidationError, escape(message)):
             curriculum_4.program = self.program_1
             curriculum_4.save()
     curriculum_4.refresh_from_db()
     assert curriculum_4.program == new_program
예제 #24
0
 def setUp(self):
     super(ProgramTests, self).setUp()
     transcript_languages = LanguageTag.objects.all()[:2]
     subjects = factories.SubjectFactory.create_batch(2)
     self.course_runs = factories.CourseRunFactory.create_batch(
         3,
         transcript_languages=transcript_languages,
         course__subjects=subjects)
     self.courses = [course_run.course for course_run in self.course_runs]
     self.excluded_course_run = factories.CourseRunFactory(
         course=self.courses[0])
     self.program = factories.ProgramFactory(
         courses=self.courses,
         excluded_course_runs=[self.excluded_course_run])
예제 #25
0
    def test_program_with_same_partner(self):
        """
        Test happy path with same program partner as parent pathway
        """
        partner1 = PartnerFactory()
        program1 = factories.ProgramFactory(partner=partner1)
        data = {
            'partner': partner1.id,
            'name': 'Name',
            'org_name': 'Org',
            'email': '*****@*****.**',
            'programs': [program1.id]
        }
        form = PathwayAdminForm(data=data)

        self.assertDictEqual(form.errors, {})
예제 #26
0
 def test_org_synonyms(self):
     """ Test that synonyms work for organization names """
     title = 'UniversityX'
     authoring_organizations = [
         factories.OrganizationFactory(name='University')
     ]
     factories.CourseRunFactory(
         title=title,
         course__partner=self.partner,
         authoring_organizations=authoring_organizations)
     factories.ProgramFactory(
         title=title,
         partner=self.partner,
         authoring_organizations=authoring_organizations)
     response1 = self.process_response({'q': title})
     response2 = self.process_response({'q': 'University'})
     assert response1 == response2
예제 #27
0
    def test_canonical_course_seats(self):
        """ Test canonical course seats returns only canonical course run's applicable seats """
        currency = Currency.objects.get(code='USD')

        course = factories.CourseFactory()
        course_runs_same_course = factories.CourseRunFactory.create_batch(
            3, course=course)
        for course_run in course_runs_same_course:
            factories.SeatFactory(type='verified',
                                  currency=currency,
                                  course_run=course_run,
                                  price=100)
        course.canonical_course_run = course_runs_same_course[0]
        course.save()

        applicable_seat_types = SeatType.objects.filter(slug__in=['verified'])
        program_type = factories.ProgramTypeFactory(
            applicable_seat_types=applicable_seat_types)

        program = factories.ProgramFactory(type=program_type, courses=[course])

        self.assertEqual(set(course.canonical_course_run.seats.all()),
                         set(program.canonical_seats))
예제 #28
0
 def assert_one_click_purchase_ineligible_program(
         self,
         end=None,
         enrollment_start=None,
         enrollment_end=None,
         seat_type=Seat.VERIFIED,
         upgrade_deadline=None,
         one_click_purchase_enabled=True,
         excluded_course_runs=None,
         program_type=None):
     course_run = factories.CourseRunFactory(
         end=end,
         enrollment_start=enrollment_start,
         enrollment_end=enrollment_end)
     factories.SeatFactory(course_run=course_run,
                           type=seat_type,
                           upgrade_deadline=upgrade_deadline)
     program = factories.ProgramFactory(
         courses=[course_run.course],
         excluded_course_runs=excluded_course_runs,
         one_click_purchase_enabled=one_click_purchase_enabled,
         type=program_type,
     )
     self.assertFalse(program.is_program_eligible_for_one_click_purchase)
예제 #29
0
 def test_special_character_synonyms(self):
     """ Test that synonyms work with special characters (non ascii) """
     factories.ProgramFactory(title='spanish', partner=self.partner)
     response1 = self.process_response({'q': 'spanish'})
     response2 = self.process_response({'q': 'español'})
     assert response1 == response2
예제 #30
0
 def setUp(self):
     super(SignalsTest, self).setUp()
     self.program = factories.ProgramFactory(type=ProgramType.objects.get(
         name='MicroMasters'))