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)
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])
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' ] })
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])
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()
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])
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)
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
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])
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])
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()
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
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]
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, ])
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))
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] )
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)
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] )
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() )
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)
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)
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()
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
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])
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, {})
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
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))
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)
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
def setUp(self): super(SignalsTest, self).setUp() self.program = factories.ProgramFactory(type=ProgramType.objects.get( name='MicroMasters'))