def setUp(self):
        super().setUp()

        self.maxDiff = None

        self.project = obj_build.make_project(
            # Future closing_time
            closing_time=timezone.now() + datetime.timedelta(days=1))
        self.course = self.project.course

        self.ag_test_suite = obj_build.make_ag_test_suite(self.project)
        self.ag_test_case = obj_build.make_ag_test_case(self.ag_test_suite)
        self.ag_test_cmd = obj_build.make_full_ag_test_command(
            self.ag_test_case)

        self.student_test_suite = obj_build.make_student_test_suite(
            self.project)

        self.client = APIClient()
        self.base_url = reverse('all-ultimate-submission-results',
                                kwargs={'project_pk': self.project.pk})

        # For use by self._make_group_with_submissions only
        self._num_groups = 0

        # This is to make sure we use the right group queryset
        other_project = obj_build.make_project()
        other_group = obj_build.make_group(project=other_project)
        other_submission = obj_build.make_finished_submission(other_group)
예제 #2
0
    def test_copy_course(self):
        proj1 = obj_build.make_project()
        course = proj1.course
        proj2 = obj_build.make_project(course)

        admins = obj_build.make_admin_users(course, 4)
        staff = obj_build.make_staff_users(course, 3)
        students = obj_build.make_student_users(course, 5)
        handgraders = obj_build.make_handgrader_users(course, 2)

        self.assertNotEqual(0, course.staff.count())
        self.assertNotEqual(0, course.students.count())
        self.assertNotEqual(0, course.handgraders.count())

        name = 'stove'
        new_course = copy_course(course, name, Semester.summer, 2019)

        self.assertEqual(name, new_course.name)
        self.assertEqual(Semester.summer, new_course.semester)
        self.assertEqual(2019, new_course.year)

        self.assertCountEqual(admins, new_course.admins.all())
        self.assertSequenceEqual([], new_course.staff.all())
        self.assertSequenceEqual([], new_course.students.all())
        self.assertSequenceEqual([], new_course.handgraders.all())

        old_project_pks = {proj.pk for proj in course.projects.all()}
        new_project_pks = {proj.pk for proj in new_course.projects.all()}
        self.assertTrue(old_project_pks.isdisjoint(new_project_pks))

        self.assertSetEqual({proj.name
                             for proj in course.projects.all()},
                            {proj.name
                             for proj in new_course.projects.all()})
    def setUp(self):
        super().setUp()

        self.maxDiff = None

        self.client = APIClient()

        self.project = obj_build.make_project(
            ultimate_submission_policy=ag_models.UltimateSubmissionPolicy.
            most_recent, )

        self.url = reverse('project-ultimate-submission-scores',
                           kwargs={'pk': self.project.pk})

        self.admin = obj_build.make_admin_user(self.project.course)

        self.ag_test_suite = obj_build.make_ag_test_suite(project=self.project)
        self.ag_test_case = obj_build.make_ag_test_case(
            ag_test_suite=self.ag_test_suite)
        self.ag_test_cmd = obj_build.make_full_ag_test_command(
            ag_test_case=self.ag_test_case)

        self.student_group = obj_build.make_group(project=self.project,
                                                  num_members=2)
        self.student_submission = obj_build.make_finished_submission(
            self.student_group)
        self.student_result = obj_build.make_incorrect_ag_test_command_result(
            ag_test_command=self.ag_test_cmd,
            submission=self.student_submission)

        self.student_submission = update_denormalized_ag_test_results(
            self.student_submission.pk)
        self.student_result_fdbk = SubmissionResultFeedback(
            self.student_submission, ag_models.FeedbackCategory.max,
            AGTestPreLoader(self.project))

        self.assertEqual(0, self.student_result_fdbk.total_points)
        self.assertNotEqual(0, self.student_result_fdbk.total_points_possible)

        self.staff_group = obj_build.make_group(
            project=self.project, members_role=obj_build.UserRole.admin)
        self.staff_submission = obj_build.make_finished_submission(
            self.staff_group)
        self.staff_result = obj_build.make_correct_ag_test_command_result(
            ag_test_command=self.ag_test_cmd, submission=self.staff_submission)

        self.staff_submission = update_denormalized_ag_test_results(
            self.staff_submission.pk)
        self.staff_result_fdbk = SubmissionResultFeedback(
            self.staff_submission, ag_models.FeedbackCategory.max,
            AGTestPreLoader(self.project))

        self.assertNotEqual(0, self.staff_result_fdbk.total_points)
        self.assertNotEqual(0, self.staff_result_fdbk.total_points_possible)

        # Make sure we use the right queryset
        other_project = obj_build.make_project(course=self.project.course)
        other_group = obj_build.make_group(project=other_project)
        other_submission = obj_build.make_finished_submission(other_group)
예제 #4
0
    def setUp(self):
        super().setUp()
        self.project = obj_build.make_project()

        # Make sure we use the right group queryset
        other_project = obj_build.make_project(course=self.project.course)
        other_group = obj_build.make_group(project=other_project)
        other_subimssion = obj_build.make_finished_submission(other_group)
    def setUp(self):
        super().setUp()

        self.hidden_project = obj_build.make_project()
        self.course = self.hidden_project.course
        self.visible_project = obj_build.make_project(course=self.course,
                                                      visible_to_students=True)
        self.all_projects = [self.hidden_project, self.visible_project]

        self.client = APIClient()
        self.url = reverse('projects', kwargs={'pk': self.course.pk})
    def test_get_num_queued_submissions(self):
        client = APIClient()

        course = obj_build.make_course()
        admin = obj_build.make_admin_user(course)
        proj_kwargs = {'visible_to_students': True, 'guests_can_submit': True}
        no_submits = obj_build.make_project(course, **proj_kwargs)
        with_submits1 = obj_build.make_project(course, **proj_kwargs)
        with_submits2 = obj_build.make_project(course, **proj_kwargs)

        group_with_submits1 = obj_build.make_group(project=with_submits1)
        group_with_submits2 = obj_build.make_group(project=with_submits2)

        g1_statuses = [
            ag_models.Submission.GradingStatus.queued,
            ag_models.Submission.GradingStatus.finished_grading,
            ag_models.Submission.GradingStatus.removed_from_queue,
            ag_models.Submission.GradingStatus.received,
            ag_models.Submission.GradingStatus.being_graded,
            ag_models.Submission.GradingStatus.error
        ]

        for grading_status in g1_statuses:
            obj_build.make_submission(status=grading_status,
                                      group=group_with_submits1)

        for i in range(3):
            obj_build.make_submission(
                status=ag_models.Submission.GradingStatus.queued,
                group=group_with_submits2)

        client.force_authenticate(admin)
        response = client.get(
            reverse('project-num-queued-submissions',
                    kwargs={'pk': no_submits.pk}))
        self.assertEqual(status.HTTP_200_OK, response.status_code)
        self.assertEqual(0, response.data)

        response = client.get(
            reverse('project-num-queued-submissions',
                    kwargs={'pk': with_submits1.pk}))
        self.assertEqual(status.HTTP_200_OK, response.status_code)
        self.assertEqual(1, response.data)

        response = client.get(
            reverse('project-num-queued-submissions',
                    kwargs={'pk': with_submits2.pk}))
        self.assertEqual(status.HTTP_200_OK, response.status_code)
        self.assertEqual(3, response.data)
예제 #7
0
    def test_get_ultimate_submission_most_recent_submission_doesnt_count_for_user(
            self):
        project = obj_build.make_project(visible_to_students=True,
                                         hide_ultimate_submission_fdbk=False,
                                         ultimate_submission_policy=ag_models.
                                         UltimateSubmissionPolicy.most_recent)
        course = project.course

        counts_for_user = obj_build.make_student_user(course)
        does_not_count_for_user = obj_build.make_student_user(course)

        group = obj_build.make_group(
            members=[counts_for_user, does_not_count_for_user],
            project=project)

        second_most_recent_submission = obj_build.make_finished_submission(
            group=group)
        most_recent_submission = obj_build.make_finished_submission(
            group=group, does_not_count_for=[does_not_count_for_user.username])

        self.client.force_authenticate(counts_for_user)
        response = self.client.get(self.ultimate_submission_url(group))
        self.assertEqual(status.HTTP_200_OK, response.status_code)
        self.assertEqual(most_recent_submission.to_dict(), response.data)

        self.client.force_authenticate(does_not_count_for_user)
        response = self.client.get(self.ultimate_submission_url(group))
        self.assertEqual(status.HTTP_200_OK, response.status_code)
        self.assertEqual(second_most_recent_submission.to_dict(),
                         response.data)
 def test_non_admin_create_permission_denied(self):
     project = obj_build.make_project()
     [staff] = obj_build.make_staff_users(project.course, 1)
     self.do_permission_denied_create_test(
         ag_models.RerunSubmissionsTask.objects, APIClient(), staff,
         reverse('rerun_submissions_tasks',
                 kwargs={'project_pk': project.pk}), {})
예제 #9
0
 def test_copy_project_new_name_same_course(self):
     project = obj_build.make_project()
     name = 'steve'
     new_project = copy_project(project, project.course, name)
     self.assertEqual(new_project.course, project.course)
     self.assertNotEqual(project, new_project)
     self.assertEqual(name, new_project.name)
예제 #10
0
    def test_groups_sorted_by_least_alphabetical_username(self):
        self.maxDiff = None

        project = obj_build.make_project(max_group_size=3,
                                         guests_can_submit=True)
        [admin] = obj_build.make_admin_users(project.course, 1)

        group1_user1 = User.objects.create(username='******')
        group1 = ag_models.Group.objects.validate_and_create(
            members=[group1_user1], project=project)

        group2_user1 = User.objects.create(username='******')
        group2_user2 = User.objects.create(username='******')
        group2 = ag_models.Group.objects.validate_and_create(
            members=[group2_user1, group2_user2], project=project)

        group3_user1 = User.objects.create(username='******')
        group3_user2 = User.objects.create(username='******')
        group3_user3 = User.objects.create(username='******')
        group3 = ag_models.Group.objects.validate_and_create(
            members=[group3_user1, group3_user2, group3_user3],
            project=project)

        expected = [group2.to_dict(),
                    group3.to_dict(),
                    group1.to_dict()]  # type: List[dict]
        for group_dict in expected:
            group_dict['member_names'] = list(
                sorted(group_dict['member_names']))

        self.client.force_authenticate(admin)
        response = self.client.get(
            reverse('groups', kwargs={'project_pk': project.pk}))
        self.assertEqual(expected, response.data)
예제 #11
0
    def setUp(self):
        super().setUp()
        self.project = obj_build.make_project()
        self.client = APIClient()
        self.url = reverse('ag_test_suites',
                           kwargs={'project_pk': self.project.pk})

        self.create_data = {'name': 'adslkfjals;dkjfa;lsdkjf'}
예제 #12
0
    def setUp(self):
        super().setUp()
        self.project = obj_build.make_project()
        self.client = APIClient()
        self.url = reverse('student_test_suites',
                           kwargs={'project_pk': self.project.pk})

        self.create_data = {'name': 'some suite'}
예제 #13
0
    def setUp(self):
        super().setUp()

        self.project = obj_build.make_project(max_group_size=2)
        self.course = self.project.course

        self.student_users = unsorted_users(obj_build.make_student_users(self.course, 2))
        self.staff_users = unsorted_users(obj_build.make_staff_users(self.course, 2))
        self.guest_group = obj_build.make_users(2)
    def setUp(self):
        super().setUp()

        self.client = APIClient()
        self.project = obj_build.make_project()
        self.admin = obj_build.make_admin_user(self.project.course)

        self.other_course = obj_build.make_course()
        self.other_course.admins.add(self.admin)
    def test_create_criterion_results_on_create(self):
        [admin] = obj_build.make_admin_users(self.course, 1)
        self.client.force_authenticate(admin)

        # Create HandgradingResult
        submission = obj_build.make_submission(
            group=obj_build.make_group(project=self.handgrading_rubric.project))
        handgrading_result = hg_models.HandgradingResult.objects.validate_and_create(
            submission=submission,
            group=submission.group,
            handgrading_rubric=self.handgrading_rubric)

        # Create dummy submissions and groups with no submissions. These should not be affected
        dummy_submission = obj_build.make_submission(
            group=obj_build.make_group(project=self.handgrading_rubric.project))
        dummy_submission = obj_build.make_submission(
            group=obj_build.make_group(project=self.handgrading_rubric.project))
        group_with_no_submission = obj_build.make_group(project=self.handgrading_rubric.project)
        group_with_no_submission = obj_build.make_group(project=self.handgrading_rubric.project)

        self.assertEqual(0, handgrading_result.criterion_results.count())
        self.assertEqual(1, hg_models.HandgradingResult.objects.count())

        # Create dummy project with its own groups and HandgradingResults.
        #   These should not be affected
        dummy_project = obj_build.make_project(course=self.handgrading_rubric.project.course)
        dummy_handgrading_rubric = hg_models.HandgradingRubric.objects.validate_and_create(
            points_style=hg_models.PointsStyle.start_at_max_and_subtract,
            max_points=0,
            show_grades_and_rubric_to_students=False,
            handgraders_can_leave_comments=True,
            handgraders_can_adjust_points=True,
            project=dummy_project)
        dummy_submission = obj_build.make_submission(
            group=obj_build.make_group(project=self.handgrading_rubric.project))
        dummy_handgrading_result = hg_models.HandgradingResult.objects.validate_and_create(
            submission=dummy_submission,
            group=dummy_submission.group,
            handgrading_rubric=dummy_handgrading_rubric)

        self.assertEqual(0, hg_models.CriterionResult.objects.count())
        self.assertEqual(2, hg_models.HandgradingResult.objects.count())

        # Create Criterion, which should create a CriterionResult for above HandgradingResult
        response = self.client.post(self.url, self.data)
        self.assertEqual(status.HTTP_201_CREATED, response.status_code)

        handgrading_result.refresh_from_db()
        self.assertEqual(1, handgrading_result.criterion_results.count())
        self.assertEqual(1, hg_models.CriterionResult.objects.count())

        criterion_results = handgrading_result.to_dict()["criterion_results"]
        self.assertFalse(criterion_results[0]["selected"])
        self.assertEqual(criterion_results[0]["criterion"], response.data)
예제 #16
0
    def setUp(self):
        super().setUp()
        self.project = obj_build.make_project()
        self.course = self.project.course

        self.counts_for_user = obj_build.make_student_user(self.course)
        self.does_not_count_for_user = obj_build.make_student_user(self.course)

        self.group = obj_build.make_group(
            members=[self.counts_for_user, self.does_not_count_for_user],
            project=self.project)
예제 #17
0
    def test_error_student_file_needed_that_belongs_to_other_project(self):
        other_project = obj_build.make_project(course=self.project.course)
        other_student_file = obj_build.make_expected_student_file(
            other_project)
        with self.assertRaises(exceptions.ValidationError) as cm:
            ag_models.StudentTestSuite.objects.validate_and_create(
                name=self.name,
                project=self.project,
                student_files_needed=[other_student_file.pk])

        self.assertIn('student_files_needed', cm.exception.message_dict)
    def setUp(self):
        super().setUp()
        self.initial_num_bonus_submissions = 10
        self.project = obj_build.make_project(
            num_bonus_submissions=self.initial_num_bonus_submissions)

        self.groups = [
            obj_build.make_group(project=self.project) for i in range(5)
        ]

        # Make sure bonus submissions are only changed for self.project
        self.other_project = obj_build.make_project(course=self.project.course,
                                                    num_bonus_submissions=3)
        self.other_groups = [
            obj_build.make_group(project=self.other_project) for i in range(5)
        ]

        self.admin = obj_build.make_admin_user(self.project.course)
        self.url = reverse('edit-bonus-submissions',
                           kwargs={'project_pk': self.project.pk})
        self.client = APIClient()
예제 #19
0
    def setUp(self):
        super().setUp()
        self.project = obj_build.make_project()
        [self.creator] = obj_build.make_admin_users(self.project.course, 1)

        self.ag_test_suite = obj_build.make_ag_test_suite(self.project)
        self.ag_test_case = obj_build.make_ag_test_case(self.ag_test_suite)
        self.student_test_suite = obj_build.make_student_test_suite(
            self.project)

        self.submission = obj_build.make_submission(group=obj_build.make_group(
            project=self.project))
예제 #20
0
    def test_error_stdin_instructor_file_belongs_to_other_project(self):
        other_project = obj_build.make_project(course=self.project.course)
        other_instructor_file = obj_build.make_instructor_file(
            project=other_project)

        with self.assertRaises(exceptions.ValidationError) as cm:
            ag_models.AGTestCommand.objects.validate_and_create(
                name=self.name,
                ag_test_case=self.ag_test,
                cmd='true',
                stdin_source=ag_models.StdinSource.instructor_file,
                stdin_instructor_file=other_instructor_file)

        self.assertIn('stdin_instructor_file', cm.exception.message_dict)
    def test_view_calls_copy_project(self):
        dummy_project = obj_build.make_project(self.other_course)
        mock_copy_project = mock.Mock(return_value=dummy_project)
        with mock.patch(
                'autograder.rest_api.views.project_views.project_views.copy_project',
                new=mock_copy_project):
            self.client.force_authenticate(self.admin)
            response = self.client.post(
                self.get_url(self.project, self.other_course))

            mock_copy_project.assert_called_once_with(
                project=self.project,
                target_course=self.other_course,
                new_project_name=None)
예제 #22
0
    def test_user_passed_to_get_ultimate_submission_func(self):
        project = obj_build.make_project(visible_to_students=True,
                                         hide_ultimate_submission_fdbk=False)
        group = obj_build.make_group(project=project)

        mocked_get_ultimate_submission = mock.Mock(return_value=None)

        with mock.patch(
                'autograder.rest_api.views.group_views.get_ultimate_submission',
                new=mocked_get_ultimate_submission):
            self.client.force_authenticate(group.members.first())
            response = self.client.get(self.ultimate_submission_url(group))
            self.assertEqual(status.HTTP_404_NOT_FOUND, response.status_code)

            mocked_get_ultimate_submission.assert_called_once_with(
                group, user=group.members.first())
예제 #23
0
    def test_no_stdin_specified_redirects_devnull(self):
        # If no stdin is redirected, this command will time out.
        # If /dev/null is redirected it should terminate normally.
        # This behavior is handled by the autograder_sandbox library.
        cmd = 'python3 -c "import sys; sys.stdin.read(); print(\'done\')"'

        # Run command from args
        with AutograderSandbox() as sandbox:
            result = tasks.run_command_from_args(cmd,
                                                 sandbox,
                                                 max_num_processes=10,
                                                 max_stack_size=10000000,
                                                 max_virtual_memory=500000000,
                                                 timeout=2)
            self.assertFalse(result.timed_out)
            self.assertEqual(0, result.return_code)
            self.assertEqual('done\n', result.stdout.read().decode())

        # Run ag command
        with AutograderSandbox() as sandbox:
            ag_command = ag_models.AGCommand.objects.validate_and_create(
                cmd=cmd, process_spawn_limit=10, time_limit=2)
            result = tasks.run_ag_command(ag_command, sandbox)
            self.assertFalse(result.timed_out)
            self.assertEqual(0, result.return_code)
            self.assertEqual('done\n', result.stdout.read().decode())

        project = obj_build.make_project()
        ag_test_suite = ag_models.AGTestSuite.objects.validate_and_create(
            name='Suite', project=project)
        ag_test_case = ag_models.AGTestCase.objects.validate_and_create(
            name='Case', ag_test_suite=ag_test_suite)
        # Run ag test command
        with AutograderSandbox() as sandbox:
            ag_test_command = ag_models.AGTestCommand.objects.validate_and_create(
                ag_test_case=ag_test_case,
                name='Read stdin',
                cmd=cmd,
                stdin_source=ag_models.StdinSource.none,
                time_limit=2,
                process_spawn_limit=10)
            result = tasks.run_ag_test_command(ag_test_command, sandbox,
                                               ag_test_suite)
            self.assertFalse(result.timed_out)
            self.assertEqual(0, result.return_code)
            self.assertEqual('done\n', result.stdout.read().decode())
    def setUp(self):
        super().setUp()
        self.maxDiff = None

        self.client = APIClient()
        self.course = obj_build.make_course()
        self.project = obj_build.make_project(course=self.course)
        self.assertEqual(ag_models.UltimateSubmissionPolicy.most_recent,
                         self.project.ultimate_submission_policy)

        self.rubric = hg_models.HandgradingRubric.objects.validate_and_create(
            project=self.project,
            points_style=hg_models.PointsStyle.start_at_max_and_subtract,
            max_points=43)

        [self.staff] = obj_build.make_staff_users(self.course, 1)
        [self.handgrader] = obj_build.make_handgrader_users(self.course, 1)
    def setUp(self):
        super().setUp()

        self.client = APIClient()

        # This submission that belongs to another project shouldn't
        # prevent us from downloading files for our project.
        obj_build.make_submission(
            status=ag_models.Submission.GradingStatus.being_graded)

        self.files = [
            SimpleUploadedFile('file1.txt', b'adsfadslkfajsdkfj'),
            SimpleUploadedFile('file2.txt', b'asdqeirueinfaksdnfaadf'),
            SimpleUploadedFile('file3.txt', b'cmxcnajsddhadf')
        ]

        self.files_by_name = dict(
            zip([file_.name for file_ in self.files], self.files))

        max_group_size = 3
        self.project = obj_build.make_project(visible_to_students=True,
                                              max_group_size=max_group_size)
        ag_models.ExpectedStudentFile.objects.validate_and_create(
            project=self.project, pattern='*', max_num_matches=3)
        self.student_group1 = obj_build.make_group(project=self.project)
        self.group1_submission1 = obj_build.make_finished_submission(
            submitted_files=self.files[:1], group=self.student_group1)
        self.group1_submission2 = obj_build.make_finished_submission(
            submitted_files=self.files[:2], group=self.student_group1)

        self.student_group2 = obj_build.make_group(num_members=max_group_size,
                                                   project=self.project)
        self.group2_submission1 = obj_build.make_finished_submission(
            submitted_files=self.files[-1:], group=self.student_group2)

        self.staff_group = obj_build.make_group(
            project=self.project, members_role=obj_build.UserRole.staff)
        self.staff_submission1 = obj_build.make_finished_submission(
            submitted_files=self.files, group=self.staff_group)

        self.no_submissions_group = obj_build.make_group(project=self.project)

        [self.admin] = obj_build.make_admin_users(self.project.course, 1)
    def setUp(self):
        super().setUp()

        self.maxDiff = None

        self.project = obj_build.make_project(
            # Future closing_time
            closing_time=timezone.now() + datetime.timedelta(days=1))
        self.course = self.project.course

        self.ag_test_suite = obj_build.make_ag_test_suite(self.project)
        self.ag_test_case = obj_build.make_ag_test_case(self.ag_test_suite)
        self.ag_test_cmd = obj_build.make_full_ag_test_command(
            self.ag_test_case)

        self.student_test_suite = obj_build.make_student_test_suite(
            self.project)

        self.ag_test_preloader = AGTestPreLoader(self.project)
    def setUp(self):
        super().setUp()

        self.project = obj_build.make_project()
        [self.admin] = obj_build.make_admin_users(self.project.course, 1)

        self.task1 = ag_models.RerunSubmissionsTask.objects.validate_and_create(
            creator=self.admin,
            project=self.project,
        )  # type: ag_models.RerunSubmissionsTask

        self.task2 = ag_models.RerunSubmissionsTask.objects.validate_and_create(
            creator=self.admin,
            project=self.project,
        )  # type: ag_models.RerunSubmissionsTask

        self.client = APIClient()
        self.url = reverse('rerun_submissions_tasks',
                           kwargs={'project_pk': self.project.pk})
    def setUp(self):
        super().setUp()

        self.project = obj_build.make_project()
        [self.admin] = obj_build.make_admin_users(self.project.course, 1)
        self.submission = obj_build.make_submission(
            group=obj_build.make_group())

        # Create a rerun task using the api so that it gets run and we have a
        # real celery task ID to look up.
        create_client = APIClient()
        create_client.force_authenticate(self.admin)
        create_url = reverse('rerun_submissions_tasks',
                             kwargs={'project_pk': self.project.pk})

        create_response = create_client.post(create_url, {})
        self.rerun_task = ag_models.RerunSubmissionsTask.objects.get(
            pk=create_response.data['pk'])

        self.client = APIClient()
        self.url = reverse('rerun-submissions-task-detail',
                           kwargs={'pk': self.rerun_task.pk})
예제 #29
0
 def test_error_non_unique_name(self):
     project = obj_build.make_project()
     with self.assertRaises(exceptions.ValidationError):
         copy_project(project, project.course, project.name)
예제 #30
0
    def test_copy_project(self):
        # In new project, hide_ultimate_submission_fdbk should be set to True,
        # visible_to_students should be set to False,
        # and guests_can_submit should be set to False
        project = obj_build.make_project(hide_ultimate_submission_fdbk=False,
                                         visible_to_students=True)
        instructor_file1 = obj_build.make_instructor_file(project)
        instructor_file2 = obj_build.make_instructor_file(project)
        student_file1 = obj_build.make_expected_student_file(project)
        student_file2 = obj_build.make_expected_student_file(project)

        suite1 = obj_build.make_ag_test_suite(
            project,
            instructor_files_needed=[instructor_file1],
            student_files_needed=[student_file1])
        case1 = obj_build.make_ag_test_case(suite1)
        cmd1 = obj_build.make_full_ag_test_command(
            case1,
            expected_stderr_source=ag_models.ExpectedOutputSource.
            instructor_file,
            expected_stderr_instructor_file=instructor_file2)
        cmd2 = obj_build.make_full_ag_test_command(
            case1,
            set_arbitrary_points=False,
            expected_stdout_source=ag_models.ExpectedOutputSource.
            instructor_file,
            expected_stdout_instructor_file=instructor_file1)

        suite2 = obj_build.make_ag_test_suite(
            project,
            instructor_files_needed=[instructor_file1, instructor_file2],
            student_files_needed=[student_file2])
        case2 = obj_build.make_ag_test_case(suite2)
        cmd3 = obj_build.make_full_ag_test_command(
            case2,
            set_arbitrary_expected_vals=False,
            stdin_source=ag_models.StdinSource.instructor_file,
            stdin_instructor_file=instructor_file2)
        case3 = obj_build.make_ag_test_case(suite2)

        suite3 = obj_build.make_ag_test_suite(project)

        student_suite1 = obj_build.make_student_test_suite(
            project,
            instructor_files_needed=[instructor_file1, instructor_file2],
            student_files_needed=[student_file1],
            setup_command={
                'name': 'stave',
                'cmd': 'yorp'
            })

        student_suite2 = obj_build.make_student_test_suite(
            project,
            instructor_files_needed=[instructor_file1],
            student_files_needed=[student_file1, student_file2])

        student_suite3 = obj_build.make_student_test_suite(project)

        other_course = obj_build.make_course()
        new_project = copy_project(project, other_course)
        self.assertTrue(new_project.hide_ultimate_submission_fdbk)
        self.assertFalse(new_project.visible_to_students)

        self.assertEqual(project.name, new_project.name)
        self.assertEqual(other_course, new_project.course)
        self.assertNotEqual(project.course, other_course)

        ignore_fields = [
            'pk', 'course', 'last_modified', 'instructor_files',
            'expected_student_files'
        ]
        expected_ag_tests = _pop_many(project.to_dict(), ignore_fields)
        expected_ag_tests.update({
            'visible_to_students': False,
            'hide_ultimate_submission_fdbk': True
        })
        self.assertEqual(expected_ag_tests,
                         _pop_many(new_project.to_dict(), ignore_fields))

        self.assertEqual(project.instructor_files.count(),
                         new_project.instructor_files.count())
        for old_file, new_file in itertools.zip_longest(
                sorted(project.instructor_files.all(),
                       key=lambda obj: obj.name),
                sorted(new_project.instructor_files.all(),
                       key=lambda obj: obj.name)):
            self.assertNotEqual(new_file.pk, old_file.pk)
            self.assertNotEqual(new_file.abspath, old_file.abspath)

            self.assertEqual(old_file.name, new_file.name)
            with old_file.open() as old_f, new_file.open() as new_f:
                self.assertEqual(old_f.read(), new_f.read())

        self.assertEqual(project.expected_student_files.count(),
                         new_project.expected_student_files.count())
        for old_expected_file, new_expected_file in itertools.zip_longest(
                project.expected_student_files.order_by('pattern'),
                new_project.expected_student_files.order_by('pattern')):
            self.assertNotEqual(old_expected_file.pk, new_expected_file.pk)

            self.assertEqual(
                _pop_many(old_expected_file.to_dict(), ['pk', 'project']),
                _pop_many(new_expected_file.to_dict(), ['pk', 'project']))

        old_suite_pks = {suite.pk for suite in project.ag_test_suites.all()}
        new_suite_pks = {
            suite.pk
            for suite in new_project.ag_test_suites.all()
        }
        self.assertTrue(old_suite_pks.isdisjoint(new_suite_pks))

        old_case_pks = {
            case.pk
            for case in ag_models.AGTestCase.objects.filter(
                ag_test_suite__project=project)
        }