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 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 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 _create_single_course_curriculum(external_key, curriculum_name,):
     course_run = factories.CourseRunFactory(
         external_key=external_key
     )
     curriculum = factories.CurriculumFactory(
         name=curriculum_name,
         program=None,
     )
     factories.CurriculumCourseMembershipFactory(
         course=course_run.course,
         curriculum=curriculum,
     )
     return course_run, curriculum
 def setUpClass(cls):
     """
     Sets up test data for testting multiple collisions of external_keys
     """
     super().setUpClass()
     cls.course_run_1a = CourseRun.objects.get(key='course-run-id/course-1a/test')
     cls.course_run_2b = CourseRun.objects.get(key='course-run-id/course-2b/test')
     cls.course_run_3c = CourseRun.objects.get(key='course-run-id/course-3c/test')
     cls.course = factories.CourseFactory()
     cls.colliding_course_run_1a = factories.CourseRunFactory(course=cls.course, external_key='ext-key-course-1a')
     cls.colliding_course_run_2b = factories.CourseRunFactory(course=cls.course, external_key='ext-key-course-2b')
     cls.colliding_course_run_3c = factories.CourseRunFactory(course=cls.course, external_key='ext-key-course-3c')
     cls.curriculum = factories.CurriculumFactory()
     cls._add_courses_to_curriculum(cls.curriculum, cls.course)
 def test_create_new_curriculum(self):
     """ create should be unaffected, impossible to create circular ref """
     factories.CurriculumFactory(program=self.program_2)