def is_ready_for_grading(self): if self.submitted_at is None: return False else: now = get_datetime_now_utc() deadline = self.assignment.deadline + timedelta(days=self.extensions_used) if now > deadline: return True else: return False
def is_ready_for_grading(self): if self.submitted_at is None: return False else: now = get_datetime_now_utc() deadline = self.assignment.deadline + timedelta( days=self.extensions_used) if now > deadline: return True else: return False
def student_assignment_show_deadline(ctx, course, assignment_id, utc): assignment = course.get_assignment(assignment_id) if assignment is None: print("Assignment %s does not exist" % assignment_id) ctx.exit(CHISUBMIT_FAIL) now_utc = get_datetime_now_utc() now_local = convert_datetime_to_local(now_utc) deadline_utc = assignment.deadline deadline_local = convert_datetime_to_local(deadline_utc) print(assignment.name) print() if utc: print(" Now (Local): %s" % now_local.isoformat(" ")) print(" Deadline (Local): %s" % deadline_local.isoformat(" ")) print() print(" Now (UTC): %s" % now_utc.isoformat(" ")) print(" Deadline (UTC): %s" % deadline_utc.isoformat(" ")) else: print(" Now: %s" % now_local.isoformat(" ")) print(" Deadline: %s" % deadline_local.isoformat(" ")) print() extensions = compute_extensions_needed(now_utc, deadline_utc) if extensions == 0: diff = deadline_utc - now_utc else: diff = now_utc - deadline_utc days = diff.days hours = diff.seconds // 3600 minutes = (diff.seconds // 60) % 60 seconds = diff.seconds % 60 if extensions == 0: print("The deadline has not yet passed") print("You have %i days, %i hours, %i minutes, %i seconds left" % (days, hours, minutes, seconds)) else: print( "The deadline passed %i days, %i hours, %i minutes, %i seconds ago" % (days, hours, minutes, seconds)) print( "If you submit your assignment now, you will need to use %i extensions" % extensions) return CHISUBMIT_SUCCESS
def test_incorrect_insufficient_extensions_in_team(self): user = User.objects.get(username='******') self.client.force_authenticate(user=user) deadline = get_datetime_now_utc() - timedelta(hours=23 + 24 + 24) assignment_obj = Assignment.objects.get(assignment_id="pa1") assignment_obj.deadline = deadline assignment_obj.save() url = reverse('submit', args=["cmsc40100", "student1-student2", "pa1"]) post_data = { "commit_sha": "COMMITSHATEST", } response = self.client.post(url, data=post_data) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
def test_incorrect_insufficient_extensions_in_team(self): user = User.objects.get(username='******') self.client.force_authenticate(user=user) deadline = get_datetime_now_utc() - timedelta(hours=23 + 24 + 24) assignment_obj = Assignment.objects.get(assignment_id = "pa1") assignment_obj.deadline = deadline assignment_obj.save() url = reverse('submit', args=["cmsc40100", "student1-student2", "pa1"]) post_data = { "commit_sha": "COMMITSHATEST", } response = self.client.post(url, data = post_data) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
def student_assignment_show_deadline(ctx, course, assignment_id, utc): assignment = course.get_assignment(assignment_id) if assignment is None: print("Assignment %s does not exist" % assignment_id) ctx.exit(CHISUBMIT_FAIL) now_utc = get_datetime_now_utc() now_local = convert_datetime_to_local(now_utc) deadline_utc = assignment.deadline deadline_local = convert_datetime_to_local(deadline_utc) print(assignment.name) print() if utc: print(" Now (Local): %s" % now_local.isoformat(" ")) print(" Deadline (Local): %s" % deadline_local.isoformat(" ")) print() print(" Now (UTC): %s" % now_utc.isoformat(" ")) print(" Deadline (UTC): %s" % deadline_utc.isoformat(" ")) else: print(" Now: %s" % now_local.isoformat(" ")) print(" Deadline: %s" % deadline_local.isoformat(" ")) print() extensions = compute_extensions_needed(now_utc, deadline_utc) if extensions == 0: diff = deadline_utc - now_utc else: diff = now_utc - deadline_utc days = diff.days hours = diff.seconds // 3600 minutes = (diff.seconds//60)%60 seconds = diff.seconds%60 if extensions == 0: print("The deadline has not yet passed") print("You have %i days, %i hours, %i minutes, %i seconds left" % (days, hours, minutes, seconds)) else: print("The deadline passed %i days, %i hours, %i minutes, %i seconds ago" % (days, hours, minutes, seconds)) print("If you submit your assignment now, you will need to use %i extensions" % extensions) return CHISUBMIT_SUCCESS
def test_correct_one_extension(self): user = User.objects.get(username='******') self.client.force_authenticate(user=user) deadline = get_datetime_now_utc() - timedelta(hours=23) assignment_obj = Assignment.objects.get(assignment_id="pa1") assignment_obj.deadline = deadline assignment_obj.save() url = reverse('submit', args=["cmsc40100", "student1-student2", "pa1"]) post_data = {"commit_sha": "COMMITSHATEST", "extensions": 1} response = self.client.post(url, data=post_data) self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(response.data["in_grace_period"], False) self.assertEqual(response.data["submission"]["extensions_used"], 1) self.assertEqual(response.data["extensions_before"], 2) self.assertEqual(response.data["extensions_after"], 1)
def has_assignment_ready_for_grading(self, assignment, when=None): ta = self.get_assignment(assignment.id) if ta is None: return False if ta.submitted_at is None: return False if when is None: when = get_datetime_now_utc() deadline = assignment.deadline + timedelta(days=ta.extensions_used) if when > deadline: return True else: return False
def test_correct_one_extension_grace_period(self): user = User.objects.get(username='******') self.client.force_authenticate(user=user) deadline = get_datetime_now_utc() - timedelta(hours=24, minutes=10) assignment_obj = Assignment.objects.get(assignment_id = "pa1") assignment_obj.deadline = deadline assignment_obj.grace_period = timedelta(minutes=15) assignment_obj.save() url = reverse('submit', args=["cmsc40100", "student1-student2", "pa1"]) post_data = { "commit_sha": "COMMITSHATEST", } response = self.client.post(url, data = post_data) self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(response.data["in_grace_period"], True) self.assertEqual(response.data["submission"]["extensions_used"], 1) self.assertEqual(response.data["extensions_before"], 2) self.assertEqual(response.data["extensions_after"], 1)
def test_incorrect_insufficient_extensions_in_team_extensions_override(self): user = User.objects.get(username='******') self.client.force_authenticate(user=user) deadline = get_datetime_now_utc() - timedelta(hours=23 + 24 + 24) assignment_obj = Assignment.objects.get(assignment_id = "pa1") assignment_obj.deadline = deadline assignment_obj.save() url = reverse('submit', args=["cmsc40100", "student1-student2", "pa1"]) post_data = { "commit_sha": "COMMITSHATEST", "extensions_override": 2 } response = self.client.post(url, data = post_data) self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(response.data["in_grace_period"], False) self.assertEqual(response.data["submission"]["extensions_used"], 2) self.assertEqual(response.data["extensions_override"], 2) self.assertEqual(response.data["extensions_before"], 2) self.assertEqual(response.data["extensions_after"], 0)
def test_complete_with_extensions_per_team(self, runner): course_id = u"cmsc40200" course_name = u"Foobarmentals of Foobar" admin_id = u"admin" instructor_ids = [u"instructor"] grader_ids= [u"grader"] student_ids = [u"student1", u"student2", u"student3", u"student4"] all_users = instructor_ids + grader_ids + student_ids admin, instructors, graders, students = self.create_clients(runner, admin_id, instructor_ids, grader_ids, student_ids, course_id, verbose = True) self.create_users(admin, all_users) self.create_course(admin, course_id, course_name) result = admin.run("admin course set-attribute %s default_extensions 2" % (course_id)) self.assertEqual(result.exit_code, 0) result = admin.run("admin course set-attribute %s extension_policy per-team" % (course_id)) self.assertEqual(result.exit_code, 0) self.add_users_to_course(admin, course_id, instructors, graders, students) teams = ["student1-student2", "student3-student4"] students_team = [students[0:2], students[2:4]] deadline = get_datetime_now_utc() - timedelta(hours=23) deadline = convert_datetime_to_local(deadline) deadline = deadline.replace(tzinfo=None).isoformat(sep=" ") result = instructors[0].run("instructor assignment add", ["pa1", "Programming Assignment 1", deadline]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor assignment set-attribute", ["pa1", "min_students", "2"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor assignment set-attribute", ["pa1", "max_students", "2"]) self.assertEqual(result.exit_code, 0) pa1_rubric = """Points: - The PA1 Tests: Points Possible: 50 Points Obtained: - The PA1 Design: Points Possible: 50 Points Obtained: Total Points: 0 / 100 """ with open("pa1.rubric.txt", "w") as f: f.write(pa1_rubric) result = instructors[0].run("instructor assignment add-rubric", ["pa1", "pa1.rubric.txt"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor assignment show-rubric", ["pa1"]) self.assertEqual(result.exit_code, 0) deadline = get_datetime_now_utc() - timedelta(hours=49) deadline = deadline.isoformat(sep=" ") result = instructors[0].run("instructor assignment add", ["pa2", "Programming Assignment 2", deadline]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor assignment set-attribute", ["pa2", "min_students", "2"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor assignment set-attribute", ["pa2", "max_students", "2"]) self.assertEqual(result.exit_code, 0) pa2_rubric = """Points: - The PA2 Tests: Points Possible: 50 Points Obtained: - The PA2 Design: Points Possible: 50 Points Obtained: Total Points: 0 / 100 """ with open("pa2.rubric.txt", "w") as f: f.write(pa2_rubric) result = instructors[0].run("instructor assignment add-rubric", ["pa2", "pa2.rubric.txt"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor assignment show-rubric", ["pa2"]) self.assertEqual(result.exit_code, 0) result = admin.run("admin course show", ["--include-users", "--include-assignments", course_id]) self.assertEqual(result.exit_code, 0) self.register_team(students_team[0], teams[0], "pa1", course_id) self.register_team(students_team[1], teams[1], "pa1", course_id) self.register_team(students_team[0], teams[0], "pa2", course_id) result = students_team[0][0].run("student team list") self.assertEqual(result.exit_code, 0) self.assertIn(teams[0], result.output) self.assertNotIn(teams[1], result.output) result = students_team[1][0].run("student team list") self.assertEqual(result.exit_code, 0) self.assertIn(teams[1], result.output) self.assertNotIn(teams[0], result.output) result = students_team[0][0].run("student team show", [teams[0]]) self.assertEqual(result.exit_code, 0) result = students_team[0][0].run("student team show", [teams[1]]) self.assertEqual(result.exit_code, CHISUBMIT_FAIL) result = students_team[1][0].run("student team show", [teams[1]]) self.assertEqual(result.exit_code, 0) result = students_team[1][0].run("student team show", [teams[0]]) self.assertEqual(result.exit_code, CHISUBMIT_FAIL) result = instructors[0].run("instructor team list") self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor team show", [teams[0]]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor team show", [teams[1]]) self.assertEqual(result.exit_code, 0) team_git_paths, team_git_repos, team_commits = self.create_team_repos(admin, course_id, teams, students_team) # Submit with just the right number result = students_team[0][0].run("student assignment submit", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS) result = students_team[0][0].run("student team show", [teams[0]]) self.assertEqual(result.exit_code, 0) # Try submitting an already-submitted assignment, with the same # commit as before (without --commit-sha) result = students_team[0][0].run("student assignment submit", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_FAIL) # Try submitting an already-submitted assignment, with the same # commit as before (with --commit-sha) result = students_team[0][0].run("student assignment submit", ["pa1", "--yes", "--commit-sha", team_commits[0][1].hexsha]) self.assertEqual(result.exit_code, CHISUBMIT_FAIL) # Submit an already-submitted assignment result = students_team[0][0].run("student assignment submit", ["pa1", "--yes", "--commit-sha", team_commits[0][0].hexsha]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS) result = students_team[0][0].run("student team show", [teams[0]]) self.assertEqual(result.exit_code, 0) # Try submitting for a project the team is not registered for result = students_team[1][0].run("student assignment submit", ["pa2", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_FAIL) result = students_team[1][0].run("student assignment submit", ["pa1", "--yes", "--commit-sha", team_commits[1][0].hexsha]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS) result = students_team[1][0].run("student assignment submit", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS) result = instructors[0].run("instructor grading list-submissions", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor team pull-repos", ["repos/all/"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor team pull-repos", ["--assignment", "pa1", "repos/pa1/"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor team pull-repos", ["--assignment", "pa1", "repos/ready/", "--only-ready-for-grading"]) self.assertEqual(result.exit_code, 0) # Let the deadline "pass" new_now = get_datetime_now_utc() + timedelta(hours=2) set_testing_now(new_now) print() print("~~~ Time has moved 'forward' by two hours ~~~") print() result = instructors[0].run("instructor grading list-submissions", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor team pull-repos", ["repos/all/"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor team pull-repos", ["--assignment", "pa1", "repos/pa1/"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor team pull-repos", ["--assignment", "pa1", "repos/ready/", "--only-ready-for-grading"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading create-grading-repos", ["--master", "pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading assign-graders", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading list-grader-assignments", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading push-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) result = graders[0].run("grader pull-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) team1_grading_repo_path = "chisubmit-test/repositories/%s/%s/%s" % (course_id, "pa1", teams[0]) team2_grading_repo_path = "chisubmit-test/repositories/%s/%s/%s" % (course_id, "pa1", teams[1]) team_git_repos[0], team_git_paths[0] = graders[0].get_local_git_repository(team1_grading_repo_path) team_git_repos[1], team_git_paths[1] = graders[0].get_local_git_repository(team2_grading_repo_path) team1_rubric_path = "%s/pa1.rubric.txt" % team_git_paths[0] team2_rubric_path = "%s/pa1.rubric.txt" % team_git_paths[1] team1_rubric = """Points: - The PA1 Tests: Points Possible: 50 Points Obtained: 45 - The PA1 Design: Points Possible: 50 Points Obtained: 30 Penalties: Used O(n^156) algorithm: -10 Submitted code in a Word document: -30 Bonuses: Worked alone: 15 Total Points: 50 / 100 Comments: > None""" with open(team1_rubric_path, "w") as f: f.write(team1_rubric) result = graders[0].run("grader validate-rubrics", ["pa1", "--only", teams[0]]) self.assertEqual(result.exit_code, 0) team_git_repos[0].index.add(["pa1.rubric.txt"]) team_git_repos[0].index.commit("Finished grading") with open("%s/bar" % team_git_paths[1], "a") as f: f.write("Great job!\n") team2_rubric = """Points: - The PA1 Tests: Points Possible: 50 Points Obtained: 50 - The PA1 Design: Points Possible: 50 Points Obtained: 45 Total Points: 95 / 100 Comments: > Great job!""" with open(team2_rubric_path, "w") as f: f.write(team2_rubric) result = graders[0].run("grader validate-rubrics", ["pa1", "--only", teams[1]]) self.assertEqual(result.exit_code, 0) team_git_repos[1].index.add(["pa1.rubric.txt"]) team_git_repos[1].index.add(["bar"]) team_git_repos[1].index.commit("Finished grading") result = graders[0].run("grader validate-rubrics", ["pa1"]) self.assertEqual(result.exit_code, 0) result = graders[0].run("grader push-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading pull-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) result = graders[0].run("instructor grading validate-rubrics", ["pa1", "--only", teams[0]]) self.assertEqual(result.exit_code, 0) result = graders[0].run("instructor grading validate-rubrics", ["pa1", "--only", teams[1]]) self.assertEqual(result.exit_code, 0) result = graders[0].run("instructor grading validate-rubrics", ["pa1", "--grader", "grader"]) self.assertEqual(result.exit_code, 0) result = graders[0].run("instructor grading validate-rubrics", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading show-grading-status", ["--by-grader", "pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading collect-rubrics", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading show-grading-status", ["--use-stored-grades", "--by-grader", "pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading list-grades") self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading push-grading", ["--to-students", "--yes", "pa1"]) self.assertEqual(result.exit_code, 0) team_git_repos[0], team_git_paths[0] = students_team[0][0].get_local_git_repository(teams[0]) team_git_repos[0].remote("origin").pull("pa1-grading:pa1-grading") team_git_repos[0].heads["pa1-grading"].checkout() self.assertTrue(os.path.exists(team_git_paths[0] + "/pa1.rubric.txt")) team_git_repos[1], team_git_paths[1] = students_team[1][0].get_local_git_repository(teams[1]) team_git_repos[1].remote("origin").pull("pa1-grading:pa1-grading") team_git_repos[1].heads["pa1-grading"].checkout() self.assertTrue(os.path.exists(team_git_paths[0] + "/pa1.rubric.txt")) self.assertIn("Great job!", open(team_git_paths[1]+"/bar").read())
def test_complete_with_extensions_per_team(self, runner): course_id = u"cmsc40200" course_name = u"Foobarmentals of Foobar" admin_id = u"admin" instructor_ids = [u"instructor"] grader_ids = [u"grader"] student_ids = [u"student1", u"student2", u"student3", u"student4"] all_users = instructor_ids + grader_ids + student_ids admin, instructors, graders, students = self.create_clients( runner, admin_id, instructor_ids, grader_ids, student_ids, course_id, verbose=True) self.create_users(admin, all_users) self.create_course(admin, course_id, course_name) result = admin.run( "admin course set-attribute %s default_extensions 2" % (course_id)) self.assertEqual(result.exit_code, 0) result = admin.run( "admin course set-attribute %s extension_policy per-team" % (course_id)) self.assertEqual(result.exit_code, 0) self.add_users_to_course(admin, course_id, instructors, graders, students) teams = ["student1-student2", "student3-student4"] students_team = [students[0:2], students[2:4]] deadline = get_datetime_now_utc() - timedelta(hours=23) deadline = convert_datetime_to_local(deadline) deadline = deadline.replace(tzinfo=None).isoformat(sep=" ") result = instructors[0].run( "instructor assignment add", ["pa1", "Programming Assignment 1", deadline]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor assignment set-attribute", ["pa1", "min_students", "2"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor assignment set-attribute", ["pa1", "max_students", "2"]) self.assertEqual(result.exit_code, 0) pa1_rubric = """Points: - The PA1 Tests: Points Possible: 50 Points Obtained: - The PA1 Design: Points Possible: 50 Points Obtained: Total Points: 0 / 100 """ with open("pa1.rubric.txt", "w") as f: f.write(pa1_rubric) result = instructors[0].run("instructor assignment add-rubric", ["pa1", "pa1.rubric.txt"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor assignment show-rubric", ["pa1"]) self.assertEqual(result.exit_code, 0) deadline = get_datetime_now_utc() - timedelta(hours=49) deadline = deadline.isoformat(sep=" ") result = instructors[0].run( "instructor assignment add", ["pa2", "Programming Assignment 2", deadline]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor assignment set-attribute", ["pa2", "min_students", "2"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor assignment set-attribute", ["pa2", "max_students", "2"]) self.assertEqual(result.exit_code, 0) pa2_rubric = """Points: - The PA2 Tests: Points Possible: 50 Points Obtained: - The PA2 Design: Points Possible: 50 Points Obtained: Total Points: 0 / 100 """ with open("pa2.rubric.txt", "w") as f: f.write(pa2_rubric) result = instructors[0].run("instructor assignment add-rubric", ["pa2", "pa2.rubric.txt"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor assignment show-rubric", ["pa2"]) self.assertEqual(result.exit_code, 0) result = admin.run( "admin course show", ["--include-users", "--include-assignments", course_id]) self.assertEqual(result.exit_code, 0) self.register_team(students_team[0], teams[0], "pa1", course_id) self.register_team(students_team[1], teams[1], "pa1", course_id) self.register_team(students_team[0], teams[0], "pa2", course_id) result = students_team[0][0].run("student team list") self.assertEqual(result.exit_code, 0) self.assertIn(teams[0], result.output) self.assertNotIn(teams[1], result.output) result = students_team[1][0].run("student team list") self.assertEqual(result.exit_code, 0) self.assertIn(teams[1], result.output) self.assertNotIn(teams[0], result.output) result = students_team[0][0].run("student team show", [teams[0]]) self.assertEqual(result.exit_code, 0) result = students_team[0][0].run("student team show", [teams[1]]) self.assertEqual(result.exit_code, CHISUBMIT_FAIL) result = students_team[1][0].run("student team show", [teams[1]]) self.assertEqual(result.exit_code, 0) result = students_team[1][0].run("student team show", [teams[0]]) self.assertEqual(result.exit_code, CHISUBMIT_FAIL) result = instructors[0].run("instructor team list") self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor team show", [teams[0]]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor team show", [teams[1]]) self.assertEqual(result.exit_code, 0) team_git_paths, team_git_repos, team_commits = self.create_team_repos( admin, course_id, teams, students_team) # Submit with just the right number result = students_team[0][0].run("student assignment submit", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS) result = students_team[0][0].run("student team show", [teams[0]]) self.assertEqual(result.exit_code, 0) # Try submitting an already-submitted assignment, with the same # commit as before (without --commit-sha) result = students_team[0][0].run("student assignment submit", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_FAIL) # Try submitting an already-submitted assignment, with the same # commit as before (with --commit-sha) result = students_team[0][0].run( "student assignment submit", ["pa1", "--yes", "--commit-sha", team_commits[0][1].hexsha]) self.assertEqual(result.exit_code, CHISUBMIT_FAIL) # Submit an already-submitted assignment result = students_team[0][0].run( "student assignment submit", ["pa1", "--yes", "--commit-sha", team_commits[0][0].hexsha]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS) result = students_team[0][0].run("student team show", [teams[0]]) self.assertEqual(result.exit_code, 0) # Try submitting for a project the team is not registered for result = students_team[1][0].run("student assignment submit", ["pa2", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_FAIL) result = students_team[1][0].run( "student assignment submit", ["pa1", "--yes", "--commit-sha", team_commits[1][0].hexsha]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS) result = students_team[1][0].run("student assignment submit", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS) result = instructors[0].run("instructor grading list-submissions", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor team pull-repos", ["repos/all/"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor team pull-repos", ["--assignment", "pa1", "repos/pa1/"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor team pull-repos", [ "--assignment", "pa1", "repos/ready/", "--only-ready-for-grading" ]) self.assertEqual(result.exit_code, 0) # Let the deadline "pass" new_now = get_datetime_now_utc() + timedelta(hours=2) set_testing_now(new_now) print() print("~~~ Time has moved 'forward' by two hours ~~~") print() result = instructors[0].run("instructor grading list-submissions", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor team pull-repos", ["repos/all/"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor team pull-repos", ["--assignment", "pa1", "repos/pa1/"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor team pull-repos", [ "--assignment", "pa1", "repos/ready/", "--only-ready-for-grading" ]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading create-grading-repos", ["--master", "pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading assign-graders", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run( "instructor grading list-grader-assignments", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading push-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) result = graders[0].run("grader pull-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) team1_grading_repo_path = "chisubmit-test/repositories/%s/%s/%s" % ( course_id, "pa1", teams[0]) team2_grading_repo_path = "chisubmit-test/repositories/%s/%s/%s" % ( course_id, "pa1", teams[1]) team_git_repos[0], team_git_paths[0] = graders[ 0].get_local_git_repository(team1_grading_repo_path) team_git_repos[1], team_git_paths[1] = graders[ 0].get_local_git_repository(team2_grading_repo_path) team1_rubric_path = "%s/pa1.rubric.txt" % team_git_paths[0] team2_rubric_path = "%s/pa1.rubric.txt" % team_git_paths[1] team1_rubric = """Points: - The PA1 Tests: Points Possible: 50 Points Obtained: 45 - The PA1 Design: Points Possible: 50 Points Obtained: 30 Penalties: Used O(n^156) algorithm: -10 Submitted code in a Word document: -30 Bonuses: Worked alone: 15 Total Points: 50 / 100 Comments: > None""" with open(team1_rubric_path, "w") as f: f.write(team1_rubric) result = graders[0].run("grader validate-rubrics", ["pa1", "--only", teams[0]]) self.assertEqual(result.exit_code, 0) team_git_repos[0].index.add(["pa1.rubric.txt"]) team_git_repos[0].index.commit("Finished grading") with open("%s/bar" % team_git_paths[1], "a") as f: f.write("Great job!\n") team2_rubric = """Points: - The PA1 Tests: Points Possible: 50 Points Obtained: 50 - The PA1 Design: Points Possible: 50 Points Obtained: 45 Total Points: 95 / 100 Comments: > Great job!""" with open(team2_rubric_path, "w") as f: f.write(team2_rubric) result = graders[0].run("grader validate-rubrics", ["pa1", "--only", teams[1]]) self.assertEqual(result.exit_code, 0) team_git_repos[1].index.add(["pa1.rubric.txt"]) team_git_repos[1].index.add(["bar"]) team_git_repos[1].index.commit("Finished grading") result = graders[0].run("grader validate-rubrics", ["pa1"]) self.assertEqual(result.exit_code, 0) result = graders[0].run("grader push-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading pull-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) result = graders[0].run("instructor grading validate-rubrics", ["pa1", "--only", teams[0]]) self.assertEqual(result.exit_code, 0) result = graders[0].run("instructor grading validate-rubrics", ["pa1", "--only", teams[1]]) self.assertEqual(result.exit_code, 0) result = graders[0].run("instructor grading validate-rubrics", ["pa1", "--grader", "grader"]) self.assertEqual(result.exit_code, 0) result = graders[0].run("instructor grading validate-rubrics", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading show-grading-status", ["--by-grader", "pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading collect-rubrics", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run( "instructor grading show-grading-status", ["--use-stored-grades", "--by-grader", "pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading list-grades") self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading push-grading", ["--to-students", "--yes", "pa1"]) self.assertEqual(result.exit_code, 0) team_git_repos[0], team_git_paths[0] = students_team[0][ 0].get_local_git_repository(teams[0]) team_git_repos[0].remote("origin").pull("pa1-grading:pa1-grading") team_git_repos[0].heads["pa1-grading"].checkout() self.assertTrue(os.path.exists(team_git_paths[0] + "/pa1.rubric.txt")) team_git_repos[1], team_git_paths[1] = students_team[1][ 0].get_local_git_repository(teams[1]) team_git_repos[1].remote("origin").pull("pa1-grading:pa1-grading") team_git_repos[1].heads["pa1-grading"].checkout() self.assertTrue(os.path.exists(team_git_paths[0] + "/pa1.rubric.txt")) self.assertIn("Great job!", open(team_git_paths[1] + "/bar").read())
def test_complete_with_registration_cancellation(self, runner): course_id = u"cmsc40300" course_name = u"Foobarmentals of Foobar II" admin_id = u"admin" instructor_ids = [u"instructor"] grader_ids = [u"grader"] student_ids = [u"student1", u"student2", u"student3", u"student4"] all_users = instructor_ids + grader_ids + student_ids admin, instructors, graders, students = self.create_clients( runner, admin_id, instructor_ids, grader_ids, student_ids, course_id, verbose=True) self.create_users(admin, all_users) self.create_course(admin, course_id, course_name) course = Course.get_by_course_id(course_id) self.assertIsNotNone(course) self.assertEqual(course.name, course_name) result = admin.run( "admin course set-attribute %s default_extensions 2" % (course_id)) self.assertEqual(result.exit_code, 0) result = admin.run( "admin course set-attribute %s extension_policy per-student" % (course_id)) self.assertEqual(result.exit_code, 0) self.add_users_to_course(admin, course_id, instructors, graders, students) deadline = get_datetime_now_utc() - timedelta(minutes=5) deadline = deadline.isoformat(sep=" ") result = instructors[0].run( "instructor assignment add", ["pa1", "Programming Assignment 1", deadline]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor assignment set-attribute", ["pa1", "max_students", "2"]) self.assertEqual(result.exit_code, 0) teams = [u"student1-student2", u"student3-student4"] students_team = [(students[0], students[1]), (students[2], students[3])] self.register_team(students_team[0], teams[0], "pa1", course_id) self.register_team(students_team[1], teams[1], "pa1", course_id) _, _, team_commits = self.create_team_repos(admin, course_id, teams[0:2], students_team[0:2]) # Team 0 cancels their registration, which they can do because they haven't submitted yet. result = students_team[0][0].run( "student assignment cancel-registration", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS) # Team 0 tries to cancel their registration again, which doesn't work. There's nothing to cancel. result = students_team[0][0].run( "student assignment cancel-registration", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_FAIL) # Team 0 registers again result = students_team[0][0].run( "student assignment register", ["pa1", "--partner", students_team[0][1].user_id]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS) # Team 1 submits. result = students_team[1][0].run("student assignment submit", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS) # Team 1 tries to cancel their registration, which doesn't work. They have a submission. result = students_team[1][0].run( "student assignment cancel-registration", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_FAIL) # Team 1 cancels their submission result = students_team[1][0].run("student assignment cancel-submit", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS) # Team 1 can now cancel their registration. result = students_team[1][0].run( "student assignment cancel-registration", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS) for team, student_team in zip(teams, students_team): result = student_team[0].run("student team show", [team]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS)
def test_complete_with_extensions_per_team(self, runner): course_id = u"cmsc40200" course_name = u"Foobarmentals of Foobar" admin_id = u"admin" instructor_ids = [u"instructor"] grader_ids= [u"grader"] student_ids = [u"student1", u"student2", u"student3", u"student4"] all_users = instructor_ids + grader_ids + student_ids admin, instructors, graders, students = self.create_clients(runner, course_id, admin_id, instructor_ids, grader_ids, student_ids) self.create_users(admin, all_users) self.create_course(admin, course_id, course_name) result = admin.run("admin course set-option %s default-extensions 2" % (course_id)) self.assertEquals(result.exit_code, 0) result = admin.run("admin course set-option %s extension-policy per_team" % (course_id)) self.assertEquals(result.exit_code, 0) self.add_users_to_course(admin, course_id, instructors, graders, students) teams = ["the-flaming-foobars", "the-magnificent-mallocs"] students_team = [students[0:2], students[2:4]] deadline = get_datetime_now_utc() - timedelta(hours=23) deadline = convert_datetime_to_local(deadline) deadline = deadline.replace(tzinfo=None).isoformat(sep=" ") result = instructors[0].run("instructor assignment add", ["pa1", "Programming Assignment 1", deadline]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor assignment add-grade-component", ["pa1", "tests", "The PA1 Tests", "50"]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor assignment add-grade-component", ["pa1", "design", "The PA1 Design", "50"]) self.assertEquals(result.exit_code, 0) deadline = get_datetime_now_utc() - timedelta(hours=49) deadline = deadline.isoformat(sep=" ") result = instructors[0].run("instructor assignment add", ["pa2", "Programming Assignment 2", deadline]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor assignment add-grade-component", ["pa2", "tests", "The PA2 Tests", "50"]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor assignment add-grade-component", ["pa2", "design", "The PA2 Design", "50"]) self.assertEquals(result.exit_code, 0) result = admin.run("admin course show", ["--include-users", "--include-assignments", course_id]) self.assertEquals(result.exit_code, 0) self.register_team(students_team[0], teams[0], "pa1", course_id) self.register_team(students_team[1], teams[1], "pa1", course_id) self.register_team(students_team[0], teams[0], "pa2", course_id) result = students_team[0][0].run("student team list") self.assertEquals(result.exit_code, 0) self.assertIn(teams[0], result.output) self.assertNotIn(teams[1], result.output) result = students_team[1][0].run("student team list") self.assertEquals(result.exit_code, 0) self.assertIn(teams[1], result.output) self.assertNotIn(teams[0], result.output) result = students_team[0][0].run("student team show", [teams[1]]) self.assertEquals(result.exit_code, CHISUBMIT_FAIL) result = students_team[1][0].run("student team show", [teams[0]]) self.assertEquals(result.exit_code, CHISUBMIT_FAIL) result = instructors[0].run("instructor team set-attribute", [teams[0], "alias", "foobar "+teams[0]]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor team set-attribute", [teams[1], "alias", "foobar "+teams[1]]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor team list") self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor team show", [teams[0]]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor team show", [teams[1]]) self.assertEquals(result.exit_code, 0) team_git_paths, team_git_repos, team_commits = self.create_team_repos(admin, course_id, teams, students_team) # Try to submit without enough extensions result = students_team[0][0].run("student assignment submit", [teams[0], "pa1", team_commits[0][0].hexsha, "--extensions", "0", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_FAIL) # Try to submit with too many extensions result = students_team[0][0].run("student assignment submit", [teams[0], "pa1", team_commits[0][0].hexsha, "--extensions", "2", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_FAIL) # Submit with just the right number result = students_team[0][0].run("student assignment submit", [teams[0], "pa1", team_commits[0][0].hexsha, "--extensions", "1", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) result = students_team[0][0].run("student team show", [teams[0]]) self.assertEquals(result.exit_code, 0) # Try submitting an already-submitted assignment result = students_team[0][0].run("student assignment submit", [teams[0], "pa1", team_commits[0][1].hexsha, "--extensions", "1", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_FAIL) # Try submitting an already-submitted assignment, with the same # commit as before result = students_team[0][0].run("student assignment submit", [teams[0], "pa1", team_commits[0][0].hexsha, "--extensions", "1", "--yes", "--force"]) self.assertEquals(result.exit_code, CHISUBMIT_FAIL) # Submit an already-submitted assignment result = students_team[0][0].run("student assignment submit", [teams[0], "pa1", team_commits[0][1].hexsha, "--extensions", "1", "--yes", "--force"]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) result = students_team[0][0].run("student team show", [teams[0]]) self.assertEquals(result.exit_code, 0) # Try requesting more extensions than the team has result = students_team[0][0].run("student assignment submit", [teams[0], "pa2", team_commits[0][1].hexsha, "--extensions", "3", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_FAIL) # Try submitting for a project the team is not registered for result = students_team[1][0].run("student assignment submit", [teams[1], "pa2", team_commits[1][1].hexsha, "--extensions", "0", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_FAIL) result = students_team[1][0].run("student assignment submit", [teams[1], "pa1", team_commits[1][1].hexsha, "--extensions", "1", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) result = instructors[0].run("instructor grading list-submissions", ["pa1"]) self.assertEquals(result.exit_code, 0) # Let the deadline "pass" new_now = get_datetime_now_utc() + timedelta(hours=2) set_testing_now(new_now) print print "~~~ Time has moved 'forward' by two hours ~~~" print result = instructors[0].run("instructor grading list-submissions", ["pa1"]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor grading create-grading-repos", ["pa1"]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor grading create-grading-branches", ["pa1"]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor grading set-grade", [teams[0], "pa1", "tests", "100"]) self.assertEquals(result.exit_code, 1) result = instructors[0].run("instructor grading set-grade", [teams[0], "pa1", "tests", "40"]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor grading set-grade", [teams[1], "pa1", "tests", "45"]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor grading list-grades") self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor grading set-grade", [teams[0], "pa1", "tests", "50"]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor grading list-grades") self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor grading add-rubrics", ["pa1", "--commit"]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor grading assign-graders", ["pa1"]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor grading list-grader-assignments", ["pa1"]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor grading push-grading-branches", ["--to-staging", "pa1"]) self.assertEquals(result.exit_code, 0) result = graders[0].run("grader create-local-grading-repos", [graders[0].user_id, "pa1"]) self.assertEquals(result.exit_code, 0) team1_grading_repo_path = ".chisubmit/repositories/%s/%s/%s" % (course_id, "pa1", teams[0]) team2_grading_repo_path = ".chisubmit/repositories/%s/%s/%s" % (course_id, "pa1", teams[1]) team_git_repos[0], team_git_paths[0] = graders[0].get_local_git_repository(team1_grading_repo_path) team_git_repos[1], team_git_paths[1] = graders[0].get_local_git_repository(team2_grading_repo_path) team1_rubric_path = "%s/pa1.rubric.txt" % team_git_paths[0] team2_rubric_path = "%s/pa1.rubric.txt" % team_git_paths[1] team1_rubric = """Points: The PA1 Tests: Points Possible: 50 Points Obtained: 45 The PA1 Design: Points Possible: 50 Points Obtained: 30 Penalties: Used O(n^156) algorithm: -10 Submitted code in a Word document: -30 Total Points: 35 / 100 Comments: > None""" with open(team1_rubric_path, "w") as f: f.write(team1_rubric) result = graders[0].run("grader validate-rubrics", [graders[0].user_id, "pa1", "--only", teams[0]]) self.assertEquals(result.exit_code, 0) team_git_repos[0].index.add(["pa1.rubric.txt"]) team_git_repos[0].index.commit("Finished grading") with open("%s/bar" % team_git_paths[1], "a") as f: f.write("Great job!\n") team2_rubric = """Points: The PA1 Tests: Points Possible: 50 Points Obtained: 50 The PA1 Design: Points Possible: 50 Points Obtained: 45 Total Points: 95 / 100 Comments: > Great job!""" with open(team2_rubric_path, "w") as f: f.write(team2_rubric) result = graders[0].run("grader validate-rubrics", [graders[0].user_id, "pa1", "--only", teams[1]]) self.assertEquals(result.exit_code, 0) team_git_repos[1].index.add(["pa1.rubric.txt"]) team_git_repos[1].index.add(["bar"]) team_git_repos[1].index.commit("Finished grading") result = graders[0].run("grader validate-rubrics", [graders[0].user_id, "pa1"]) self.assertEquals(result.exit_code, 0) result = graders[0].run("grader push-grading-branches", [graders[0].user_id, "pa1"]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor grading pull-grading-branches", ["--from-staging", "pa1"]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor grading collect-rubrics", ["pa1"]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor grading list-grades") self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor grading push-grading-branches", ["--to-students", "pa1"]) self.assertEquals(result.exit_code, 0) team_git_repos[0], team_git_paths[0] = students_team[0][0].get_local_git_repository(teams[0]) team_git_repos[0].remote("origin").pull("pa1-grading:pa1-grading") team_git_repos[0].heads["pa1-grading"].checkout() self.assertTrue(os.path.exists(team_git_paths[0] + "/pa1.rubric.txt")) team_git_repos[1], team_git_paths[1] = students_team[1][0].get_local_git_repository(teams[1]) team_git_repos[1].remote("origin").pull("pa1-grading:pa1-grading") team_git_repos[1].heads["pa1-grading"].checkout() self.assertTrue(os.path.exists(team_git_paths[0] + "/pa1.rubric.txt")) self.assertIn("Great job!", open(team_git_paths[1]+"/bar").read())
def test_complete_with_registration_cancellation(self, runner): course_id = u"cmsc40300" course_name = u"Foobarmentals of Foobar II" admin_id = u"admin" instructor_ids = [u"instructor"] grader_ids= [u"grader"] student_ids = [u"student1", u"student2", u"student3", u"student4"] all_users = instructor_ids + grader_ids + student_ids admin, instructors, graders, students = self.create_clients(runner, admin_id, instructor_ids, grader_ids, student_ids, course_id, verbose = True) self.create_users(admin, all_users) self.create_course(admin, course_id, course_name) course = Course.get_by_course_id(course_id) self.assertIsNotNone(course) self.assertEqual(course.name, course_name) result = admin.run("admin course set-attribute %s default_extensions 2" % (course_id)) self.assertEqual(result.exit_code, 0) result = admin.run("admin course set-attribute %s extension_policy per-student" % (course_id)) self.assertEqual(result.exit_code, 0) self.add_users_to_course(admin, course_id, instructors, graders, students) deadline = get_datetime_now_utc() - timedelta(minutes=5) deadline = deadline.isoformat(sep=" ") result = instructors[0].run("instructor assignment add", ["pa1", "Programming Assignment 1", deadline]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor assignment set-attribute", ["pa1", "max_students", "2"]) self.assertEqual(result.exit_code, 0) teams = [u"student1-student2", u"student3-student4"] students_team = [ (students[0], students[1]), (students[2], students[3])] self.register_team(students_team[0], teams[0], "pa1", course_id) self.register_team(students_team[1], teams[1], "pa1", course_id) _, _, team_commits = self.create_team_repos(admin, course_id, teams[0:2], students_team[0:2]) # Team 0 cancels their registration, which they can do because they haven't submitted yet. result = students_team[0][0].run("student assignment cancel-registration", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS) # Team 0 tries to cancel their registration again, which doesn't work. There's nothing to cancel. result = students_team[0][0].run("student assignment cancel-registration", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_FAIL) # Team 0 registers again result = students_team[0][0].run("student assignment register", ["pa1", "--partner", students_team[0][1].user_id]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS) # Team 1 submits. result = students_team[1][0].run("student assignment submit", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS) # Team 1 tries to cancel their registration, which doesn't work. They have a submission. result = students_team[1][0].run("student assignment cancel-registration", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_FAIL) # Team 1 cancels their submission result = students_team[1][0].run("student assignment cancel-submit", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS) # Team 1 can now cancel their registration. result = students_team[1][0].run("student assignment cancel-registration", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS) for team, student_team in zip(teams, students_team): result = student_team[0].run("student team show", [team]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS)
def test_complete_with_extensions_per_team(self, runner): course_id = u"cmsc40200" course_name = u"Foobarmentals of Foobar" admin_id = u"admin" instructor_ids = [u"instructor"] grader_ids = [u"grader"] student_ids = [u"student1", u"student2", u"student3", u"student4"] all_users = instructor_ids + grader_ids + student_ids admin, instructors, graders, students = self.create_clients( runner, course_id, admin_id, instructor_ids, grader_ids, student_ids) self.create_users(admin, all_users) self.create_course(admin, course_id, course_name) result = admin.run("admin course set-option %s default-extensions 2" % (course_id)) self.assertEquals(result.exit_code, 0) result = admin.run( "admin course set-option %s extension-policy per_team" % (course_id)) self.assertEquals(result.exit_code, 0) self.add_users_to_course(admin, course_id, instructors, graders, students) teams = ["the-flaming-foobars", "the-magnificent-mallocs"] students_team = [students[0:2], students[2:4]] deadline = get_datetime_now_utc() - timedelta(hours=23) deadline = convert_datetime_to_local(deadline) deadline = deadline.replace(tzinfo=None).isoformat(sep=" ") result = instructors[0].run( "instructor assignment add", ["pa1", "Programming Assignment 1", deadline]) self.assertEquals(result.exit_code, 0) result = instructors[0].run( "instructor assignment add-grade-component", ["pa1", "tests", "The PA1 Tests", "50"]) self.assertEquals(result.exit_code, 0) result = instructors[0].run( "instructor assignment add-grade-component", ["pa1", "design", "The PA1 Design", "50"]) self.assertEquals(result.exit_code, 0) deadline = get_datetime_now_utc() - timedelta(hours=49) deadline = deadline.isoformat(sep=" ") result = instructors[0].run( "instructor assignment add", ["pa2", "Programming Assignment 2", deadline]) self.assertEquals(result.exit_code, 0) result = instructors[0].run( "instructor assignment add-grade-component", ["pa2", "tests", "The PA2 Tests", "50"]) self.assertEquals(result.exit_code, 0) result = instructors[0].run( "instructor assignment add-grade-component", ["pa2", "design", "The PA2 Design", "50"]) self.assertEquals(result.exit_code, 0) result = admin.run( "admin course show", ["--include-users", "--include-assignments", course_id]) self.assertEquals(result.exit_code, 0) self.register_team(students_team[0], teams[0], "pa1", course_id) self.register_team(students_team[1], teams[1], "pa1", course_id) self.register_team(students_team[0], teams[0], "pa2", course_id) result = students_team[0][0].run("student team list") self.assertEquals(result.exit_code, 0) self.assertIn(teams[0], result.output) self.assertNotIn(teams[1], result.output) result = students_team[1][0].run("student team list") self.assertEquals(result.exit_code, 0) self.assertIn(teams[1], result.output) self.assertNotIn(teams[0], result.output) result = students_team[0][0].run("student team show", [teams[1]]) self.assertEquals(result.exit_code, CHISUBMIT_FAIL) result = students_team[1][0].run("student team show", [teams[0]]) self.assertEquals(result.exit_code, CHISUBMIT_FAIL) result = instructors[0].run("instructor team set-attribute", [teams[0], "alias", "foobar " + teams[0]]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor team set-attribute", [teams[1], "alias", "foobar " + teams[1]]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor team list") self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor team show", [teams[0]]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor team show", [teams[1]]) self.assertEquals(result.exit_code, 0) team_git_paths, team_git_repos, team_commits = self.create_team_repos( admin, course_id, teams, students_team) # Try to submit without enough extensions result = students_team[0][0].run("student assignment submit", [ teams[0], "pa1", team_commits[0][0].hexsha, "--extensions", "0", "--yes" ]) self.assertEquals(result.exit_code, CHISUBMIT_FAIL) # Try to submit with too many extensions result = students_team[0][0].run("student assignment submit", [ teams[0], "pa1", team_commits[0][0].hexsha, "--extensions", "2", "--yes" ]) self.assertEquals(result.exit_code, CHISUBMIT_FAIL) # Submit with just the right number result = students_team[0][0].run("student assignment submit", [ teams[0], "pa1", team_commits[0][0].hexsha, "--extensions", "1", "--yes" ]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) result = students_team[0][0].run("student team show", [teams[0]]) self.assertEquals(result.exit_code, 0) # Try submitting an already-submitted assignment result = students_team[0][0].run("student assignment submit", [ teams[0], "pa1", team_commits[0][1].hexsha, "--extensions", "1", "--yes" ]) self.assertEquals(result.exit_code, CHISUBMIT_FAIL) # Try submitting an already-submitted assignment, with the same # commit as before result = students_team[0][0].run("student assignment submit", [ teams[0], "pa1", team_commits[0][0].hexsha, "--extensions", "1", "--yes", "--force" ]) self.assertEquals(result.exit_code, CHISUBMIT_FAIL) # Submit an already-submitted assignment result = students_team[0][0].run("student assignment submit", [ teams[0], "pa1", team_commits[0][1].hexsha, "--extensions", "1", "--yes", "--force" ]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) result = students_team[0][0].run("student team show", [teams[0]]) self.assertEquals(result.exit_code, 0) # Try requesting more extensions than the team has result = students_team[0][0].run("student assignment submit", [ teams[0], "pa2", team_commits[0][1].hexsha, "--extensions", "3", "--yes" ]) self.assertEquals(result.exit_code, CHISUBMIT_FAIL) # Try submitting for a project the team is not registered for result = students_team[1][0].run("student assignment submit", [ teams[1], "pa2", team_commits[1][1].hexsha, "--extensions", "0", "--yes" ]) self.assertEquals(result.exit_code, CHISUBMIT_FAIL) result = students_team[1][0].run("student assignment submit", [ teams[1], "pa1", team_commits[1][1].hexsha, "--extensions", "1", "--yes" ]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) result = instructors[0].run("instructor grading list-submissions", ["pa1"]) self.assertEquals(result.exit_code, 0) # Let the deadline "pass" new_now = get_datetime_now_utc() + timedelta(hours=2) set_testing_now(new_now) print print "~~~ Time has moved 'forward' by two hours ~~~" print result = instructors[0].run("instructor grading list-submissions", ["pa1"]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor grading create-grading-repos", ["pa1"]) self.assertEquals(result.exit_code, 0) result = instructors[0].run( "instructor grading create-grading-branches", ["pa1"]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor grading set-grade", [teams[0], "pa1", "tests", "100"]) self.assertEquals(result.exit_code, 1) result = instructors[0].run("instructor grading set-grade", [teams[0], "pa1", "tests", "40"]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor grading set-grade", [teams[1], "pa1", "tests", "45"]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor grading list-grades") self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor grading set-grade", [teams[0], "pa1", "tests", "50"]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor grading list-grades") self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor grading add-rubrics", ["pa1", "--commit"]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor grading assign-graders", ["pa1"]) self.assertEquals(result.exit_code, 0) result = instructors[0].run( "instructor grading list-grader-assignments", ["pa1"]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor grading push-grading-branches", ["--to-staging", "pa1"]) self.assertEquals(result.exit_code, 0) result = graders[0].run("grader create-local-grading-repos", [graders[0].user_id, "pa1"]) self.assertEquals(result.exit_code, 0) team1_grading_repo_path = ".chisubmit/repositories/%s/%s/%s" % ( course_id, "pa1", teams[0]) team2_grading_repo_path = ".chisubmit/repositories/%s/%s/%s" % ( course_id, "pa1", teams[1]) team_git_repos[0], team_git_paths[0] = graders[ 0].get_local_git_repository(team1_grading_repo_path) team_git_repos[1], team_git_paths[1] = graders[ 0].get_local_git_repository(team2_grading_repo_path) team1_rubric_path = "%s/pa1.rubric.txt" % team_git_paths[0] team2_rubric_path = "%s/pa1.rubric.txt" % team_git_paths[1] team1_rubric = """Points: The PA1 Tests: Points Possible: 50 Points Obtained: 45 The PA1 Design: Points Possible: 50 Points Obtained: 30 Penalties: Used O(n^156) algorithm: -10 Submitted code in a Word document: -30 Total Points: 35 / 100 Comments: > None""" with open(team1_rubric_path, "w") as f: f.write(team1_rubric) result = graders[0].run( "grader validate-rubrics", [graders[0].user_id, "pa1", "--only", teams[0]]) self.assertEquals(result.exit_code, 0) team_git_repos[0].index.add(["pa1.rubric.txt"]) team_git_repos[0].index.commit("Finished grading") with open("%s/bar" % team_git_paths[1], "a") as f: f.write("Great job!\n") team2_rubric = """Points: The PA1 Tests: Points Possible: 50 Points Obtained: 50 The PA1 Design: Points Possible: 50 Points Obtained: 45 Total Points: 95 / 100 Comments: > Great job!""" with open(team2_rubric_path, "w") as f: f.write(team2_rubric) result = graders[0].run( "grader validate-rubrics", [graders[0].user_id, "pa1", "--only", teams[1]]) self.assertEquals(result.exit_code, 0) team_git_repos[1].index.add(["pa1.rubric.txt"]) team_git_repos[1].index.add(["bar"]) team_git_repos[1].index.commit("Finished grading") result = graders[0].run("grader validate-rubrics", [graders[0].user_id, "pa1"]) self.assertEquals(result.exit_code, 0) result = graders[0].run("grader push-grading-branches", [graders[0].user_id, "pa1"]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor grading pull-grading-branches", ["--from-staging", "pa1"]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor grading collect-rubrics", ["pa1"]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor grading list-grades") self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor grading push-grading-branches", ["--to-students", "pa1"]) self.assertEquals(result.exit_code, 0) team_git_repos[0], team_git_paths[0] = students_team[0][ 0].get_local_git_repository(teams[0]) team_git_repos[0].remote("origin").pull("pa1-grading:pa1-grading") team_git_repos[0].heads["pa1-grading"].checkout() self.assertTrue(os.path.exists(team_git_paths[0] + "/pa1.rubric.txt")) team_git_repos[1], team_git_paths[1] = students_team[1][ 0].get_local_git_repository(teams[1]) team_git_repos[1].remote("origin").pull("pa1-grading:pa1-grading") team_git_repos[1].heads["pa1-grading"].checkout() self.assertTrue(os.path.exists(team_git_paths[0] + "/pa1.rubric.txt")) self.assertIn("Great job!", open(team_git_paths[1] + "/bar").read())
def student_assignment_cancel_submit(ctx, course, team_id, assignment_id, yes): assignment = course.get_assignment(assignment_id) if assignment is None: print "Assignment %s does not exist" % assignment_id ctx.exit(CHISUBMIT_FAIL) team = course.get_team(team_id) if team is None: print "Team %s does not exist" % team_id ctx.exit(CHISUBMIT_FAIL) ta = team.get_assignment(assignment_id) if ta is None: print "Team %s is not registered for assignment %s" % (team_id, assignment_id) ctx.exit(CHISUBMIT_FAIL) if ta.submitted_at is None: print "Team %s has not made a submission for assignment %s," % (team_id, assignment_id) print "so there is nothing to cancel." ctx.exit(CHISUBMIT_FAIL) if ta.submitted_at is not None: now = get_datetime_now_utc() deadline = assignment.deadline + timedelta(days=ta.extensions_used) if now > deadline: print "You cannot cancel this submission." print "You made a submission before the deadline, and the deadline has passed." ctx.exit(CHISUBMIT_FAIL) conn = create_connection(course, ctx.obj['config']) if conn is None: print "Could not connect to git server." ctx.exit(CHISUBMIT_FAIL) submission_commit = conn.get_commit(course, team, ta.commit_sha) print print "This is your existing submission for assignment %s:" % assignment.id print if submission_commit is None: print "WARNING: Previously submitted commit '%s' is not in the repository!" % ta.commit_sha else: print_commit(submission_commit) print print "Are you sure you want to cancel this submission? (y/n): ", if not yes: yesno = raw_input() else: yesno = 'y' print 'y' if yesno in ('y', 'Y', 'yes', 'Yes', 'YES'): response = assignment.cancel(team_id) # TODO: Can't do this until GitLab supports updating tags # # message = "Extensions: %i\n" % extensions_requested # if submission_tag is None: # conn.create_submission_tag(course, team, tag_name, message, commit.sha) # else: # conn.update_submission_tag(course, team, tag_name, message, commit.sha) print if response["success"]: print "Your submission has been cancelled." else: print "ERROR: Your submission was not cancelled."
def test_complete_with_extensions_per_student(self, runner): course_id = u"cmsc40300" course_name = u"Foobarmentals of Foobar II" admin_id = u"admin" instructor_ids = [u"instructor"] grader_ids = [u"grader"] student_ids = [u"student1", u"student2", u"student3", u"student4"] all_users = instructor_ids + grader_ids + student_ids admin, instructors, graders, students = self.create_clients( runner, admin_id, instructor_ids, grader_ids, student_ids, course_id, verbose=True) self.create_users(admin, all_users) self.create_course(admin, course_id, course_name) course = Course.get_by_course_id(course_id) self.assertIsNotNone(course) self.assertEquals(course.name, course_name) result = admin.run( "admin course set-attribute %s default_extensions 3" % (course_id)) self.assertEquals(result.exit_code, 0) result = admin.run( "admin course set-attribute %s extension_policy per-student" % (course_id)) self.assertEquals(result.exit_code, 0) self.add_users_to_course(admin, course_id, instructors, graders, students) deadline = get_datetime_now_utc() - timedelta(hours=23) deadline = deadline.replace(tzinfo=None).isoformat(sep=" ") result = instructors[0].run( "instructor assignment add", ["pa1", "Programming Assignment 1", deadline]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor assignment set-attribute", ["pa1", "max_students", "2"]) self.assertEquals(result.exit_code, 0) deadline = get_datetime_now_utc() - timedelta(hours=47) deadline = deadline.isoformat(sep=" ") result = instructors[0].run( "instructor assignment add", ["pa2", "Programming Assignment 2", deadline]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor assignment set-attribute", ["pa2", "max_students", "2"]) self.assertEquals(result.exit_code, 0) deadline = get_datetime_now_utc() - timedelta(hours=47) deadline = deadline.isoformat(sep=" ") result = instructors[0].run( "instructor assignment add", ["pa3", "Programming Assignment 3", deadline]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor assignment set-attribute", ["pa3", "max_students", "2"]) self.assertEquals(result.exit_code, 0) deadline = get_datetime_now_utc() - timedelta(hours=23) deadline = deadline.replace(tzinfo=None).isoformat(sep=" ") result = instructors[0].run( "instructor assignment add", ["pa4", "Programming Assignment 4", deadline]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor assignment set-attribute", ["pa4", "max_students", "2"]) self.assertEquals(result.exit_code, 0) deadline = get_datetime_now_utc() + timedelta(hours=2) deadline = deadline.replace(tzinfo=None).isoformat(sep=" ") result = instructors[0].run( "instructor assignment add", ["pa5", "Programming Assignment 5", deadline]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor assignment set-attribute", ["pa5", "max_students", "2"]) self.assertEquals(result.exit_code, 0) teams = [ u"student1-student2", u"student3-student4", u"student1-student3", u"student2-student4" ] students_team = [ (students[0], students[1]), (students[2], students[3]), (students[0], students[2]), (students[1], students[3]) ] self.register_team(students_team[0], teams[0], "pa1", course_id) self.register_team(students_team[1], teams[1], "pa2", course_id) team_git_paths, team_git_repos, team_commits = self.create_team_repos( admin, course_id, teams[0:2], students_team[0:2]) self.register_team(students_team[2], teams[2], "pa3", course_id) self.register_team(students_team[2], teams[2], "pa4", course_id) self.register_team(students_team[2], teams[2], "pa5", course_id) self.register_team(students_team[3], teams[3], "pa3", course_id) self.register_team(students_team[3], teams[3], "pa4", course_id) self.register_team(students_team[3], teams[3], "pa5", course_id) x, y, z = self.create_team_repos(admin, course_id, teams[2:4], students_team[2:4]) team_git_paths += x team_git_repos += y team_commits += z for s in students: result = s.run("student course show-extensions") self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) # Team 0 submits with one extension to pa1 # Student 0 and 1 now have 2 extensions left each result = students_team[0][0].run("student assignment submit", ["pa1", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) s1 = course.get_student( get_user_by_username(students_team[0][0].user_id)) s2 = course.get_student( get_user_by_username(students_team[0][1].user_id)) t = course.get_team(teams[0]) self.assertEqual(t.get_extensions_available(), 2) self.assertEqual(s1.get_extensions_available(), 2) self.assertEqual(s2.get_extensions_available(), 2) for s in students: result = s.run("student course show-extensions") self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) # Team 1 submits with two extensions to pa2 # Student 2 and 3 now have 1 extension left each result = students_team[1][0].run("student assignment submit", ["pa2", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) s1 = course.get_student( get_user_by_username(students_team[1][0].user_id)) s2 = course.get_student( get_user_by_username(students_team[1][1].user_id)) t = course.get_team(teams[1]) self.assertEqual(t.get_extensions_available(), 1) self.assertEqual(s1.get_extensions_available(), 1) self.assertEqual(s2.get_extensions_available(), 1) for s in students: result = s.run("student course show-extensions") self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) result = students_team[0][0].run("student team show", [teams[0]]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) result = students_team[1][0].run("student team show", [teams[1]]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) # Now we have two new teams: # # Team 2 with Student 0 and 2, with 2 and 1 extensions left respectively. # This team can only submit to projects requiring one extension # # Team 3 with Student 1 and 3, with 2 and 1 extensions left respectively. # This team can only submit to projects requiring one extension # Team 2 tries to submit to pa3, but they are denied because they would # need two extensions to submit. result = students_team[2][0].run("student assignment submit", ["pa3", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_FAIL) s1 = course.get_student( get_user_by_username(students_team[2][0].user_id)) s2 = course.get_student( get_user_by_username(students_team[2][1].user_id)) t = course.get_team(teams[2]) self.assertEqual(t.get_extensions_available(), 1) self.assertEqual(s1.get_extensions_available(), 2) self.assertEqual(s2.get_extensions_available(), 1) # Team 2 tries submitting to pa4 and it goes through because it only # requires one extensions result = students_team[2][0].run("student assignment submit", ["pa4", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) s1 = course.get_student( get_user_by_username(students_team[2][0].user_id)) s2 = course.get_student( get_user_by_username(students_team[2][1].user_id)) t = course.get_team(teams[2]) self.assertEqual(t.get_extensions_available(), 0) self.assertEqual(s1.get_extensions_available(), 1) self.assertEqual(s2.get_extensions_available(), 0) for s in students: result = s.run("student course show-extensions") self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) # Team 2 tries submitting to pa5 with zero extensions and is accepted result = students_team[2][0].run("student assignment submit", ["pa5", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) s1 = course.get_student( get_user_by_username(students_team[2][0].user_id)) s2 = course.get_student( get_user_by_username(students_team[2][1].user_id)) t = course.get_team(teams[2]) self.assertEqual(t.get_extensions_available(), 0) self.assertEqual(s1.get_extensions_available(), 1) self.assertEqual(s2.get_extensions_available(), 0) for s in students: result = s.run("student course show-extensions") self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) # Team 3 tries submitting to pa5 and is accepted (doesn't require extensions) result = students_team[3][0].run("student assignment submit", ["pa5", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) s1 = course.get_student( get_user_by_username(students_team[3][0].user_id)) s2 = course.get_student( get_user_by_username(students_team[3][1].user_id)) t = course.get_team(teams[3]) self.assertEqual(t.get_extensions_available(), 1) self.assertEqual(s1.get_extensions_available(), 2) self.assertEqual(s2.get_extensions_available(), 1) for team, student_team in zip(teams, students_team): result = student_team[0].run("student team show", [team]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) for s in students: result = s.run("student course show-extensions") self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS)
def test_complete_with_submission_grace_period(self, runner): course_id = u"cmsc40300" course_name = u"Foobarmentals of Foobar II" admin_id = u"admin" instructor_ids = [u"instructor"] grader_ids= [u"grader"] student_ids = [u"student1", u"student2", u"student3", u"student4"] all_users = instructor_ids + grader_ids + student_ids admin, instructors, graders, students = self.create_clients(runner, admin_id, instructor_ids, grader_ids, student_ids, course_id, verbose = True) self.create_users(admin, all_users) self.create_course(admin, course_id, course_name) course = Course.get_by_course_id(course_id) self.assertIsNotNone(course) self.assertEquals(course.name, course_name) result = admin.run("admin course set-attribute %s default_extensions 2" % (course_id)) self.assertEquals(result.exit_code, 0) result = admin.run("admin course set-attribute %s extension_policy per-student" % (course_id)) self.assertEquals(result.exit_code, 0) self.add_users_to_course(admin, course_id, instructors, graders, students) deadline = get_datetime_now_utc() - timedelta(minutes=5) deadline = deadline.isoformat(sep=" ") result = instructors[0].run("instructor assignment add", ["pa1", "Programming Assignment 1", deadline]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor assignment set-attribute", ["pa1", "max_students", "2"]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor assignment set-attribute", ["pa1", "grace_period", "00:15"]) self.assertEquals(result.exit_code, 0) teams = [u"student1-student2", u"student3-student4"] students_team = [ (students[0], students[1]), (students[2], students[3])] self.register_team(students_team[0], teams[0], "pa1", course_id) self.register_team(students_team[1], teams[1], "pa1", course_id) _, _, team_commits = self.create_team_repos(admin, course_id, teams[0:2], students_team[0:2]) # Team 0 submits during the grace period, and doesn't have to use an extension. result = students_team[0][0].run("student assignment submit", ["pa1", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) t = course.get_team(teams[0]) self.assertEqual(t.get_extensions_available(), 2) # Let the grace period "pass" new_now = get_datetime_now_utc() + timedelta(minutes=11) set_testing_now(new_now) print print "~~~ Time has moved 'forward' to one minute after the grace period hours ~~~" print # Team 1 submits and has to use an extensions because the grace period is over result = students_team[1][0].run("student assignment submit", ["pa1", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) t = course.get_team(teams[1]) self.assertEqual(t.get_extensions_available(), 1) for team, student_team in zip(teams, students_team): result = student_team[0].run("student team show", [team]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS)
def test_complete_with_submission_cancelling(self, runner): course_id = u"cmsc40300" course_name = u"Foobarmentals of Foobar II" admin_id = u"admin" instructor_ids = [u"instructor"] grader_ids= [u"grader"] student_ids = [u"student1", u"student2", u"student3", u"student4"] all_users = instructor_ids + grader_ids + student_ids admin, instructors, graders, students = self.create_clients(runner, admin_id, instructor_ids, grader_ids, student_ids, course_id, verbose = True) self.create_users(admin, all_users) self.create_course(admin, course_id, course_name) result = admin.run("admin course set-attribute %s default_extensions 3" % (course_id)) self.assertEqual(result.exit_code, 0) result = admin.run("admin course set-attribute %s extension_policy per-student" % (course_id)) self.assertEqual(result.exit_code, 0) self.add_users_to_course(admin, course_id, instructors, graders, students) deadline = get_datetime_now_utc() - timedelta(hours=23) deadline = deadline.isoformat(sep=" ") result = instructors[0].run("instructor assignment add", ["pa1", "Programming Assignment 1", deadline]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor assignment set-attribute", ["pa1", "max_students", "2"]) self.assertEqual(result.exit_code, 0) teams = [u"student1-student2", u"student3-student4"] students_team = [ (students[0], students[1]), (students[2], students[3])] self.register_team(students_team[0], teams[0], "pa1", course_id) self.register_team(students_team[1], teams[1], "pa1", course_id) _, _, team_commits = self.create_team_repos(admin, course_id, teams[0:2], students_team[0:2]) # Team 0 cancels their submission # Fails because there is nothing to cancel result = students_team[0][0].run("student assignment cancel-submit", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_FAIL) # Team 0 and 1 submit with one extension to pa1 result = students_team[0][0].run("student assignment submit", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS) result = students_team[1][0].run("student assignment submit", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS) # Team 0 cancels their submission result = students_team[0][0].run("student assignment cancel-submit", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS) # Team 0 cancels their submission (again) # Fails because there is nothing to cancel result = students_team[0][0].run("student assignment cancel-submit", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_FAIL) # Team 1 resubmits and is successful because the deadline hasn't passed yet result = students_team[1][0].run("student assignment submit", ["pa1", "--yes", "--commit-sha", team_commits[1][0].hexsha]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS) # Let the deadline "pass" new_now = get_datetime_now_utc() + timedelta(hours=2) set_testing_now(new_now) print() print("~~~ Time has moved 'forward' by two hours ~~~") print() # Team 1 cancels their submission and submits again. While the deadline # has passed, the instructor has not yet created the grading repos, # so the students can still cancel their submission. result = students_team[1][0].run("student assignment cancel-submit", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS) result = students_team[1][0].run("student assignment submit", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS) # The instructor waits 24 hours to create the grading repos # (this allows Team 1's repo to be ready for grading) new_now = get_datetime_now_utc() + timedelta(hours=24) set_testing_now(new_now) print() print("~~~ Time has moved 'forward' by 24 hours ~~~") print() # Instructor creates master grading repos. This flags the repo for Team 1 as sent to the graders. result = instructors[0].run("instructor grading create-grading-repos", ["--master", "pa1"]) self.assertEqual(result.exit_code, 0) # Team 0 submits and is successful because they cancelled their previous submission result = students_team[0][0].run("student assignment submit", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS) # Team 1 submits and fails because their previous submission is final result = students_team[1][0].run("student assignment submit", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_FAIL) # Team 1 cancels their submission # Fails because the previous submission is final result = students_team[1][0].run("student assignment cancel-submit", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_FAIL) for team, student_team in zip(teams, students_team): result = student_team[0].run("student team show", [team]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS)
def test_complete_with_gradescope(self, runner): course_id = u"cmsc40300" course_name = u"Foobarmentals of Foobar II" admin_id = u"admin" instructor_ids = [u"instructor"] grader_ids = [u"grader"] student_ids = [u"student1", u"student2", u"student3", u"student4"] all_users = instructor_ids + grader_ids + student_ids admin, instructors, graders, students = self.create_clients( runner, admin_id, instructor_ids, grader_ids, student_ids, course_id, gradescope_api_key="gradescope-testing", verbose=True) self.create_users(admin, all_users) self.create_course(admin, course_id, course_name) course = Course.get_by_course_id(course_id) self.assertIsNotNone(course) self.assertEqual(course.name, course_name) result = admin.run("admin course set-attribute %s gradescope_id 4242" % (course_id)) self.assertEqual(result.exit_code, 0) self.add_users_to_course(admin, course_id, instructors, graders, students) deadline = get_datetime_now_utc() + timedelta(hours=1) deadline = convert_datetime_to_local(deadline) deadline = deadline.replace(tzinfo=None).isoformat(sep=" ") result = instructors[0].run( "instructor assignment add", ["pa1", "Programming Assignment 1", deadline]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor assignment set-attribute", ["pa1", "max_students", "2"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor assignment set-attribute", ["pa1", "gradescope_id", "3737"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor assignment set-attribute", ["pa1", "expected_files", "foo,b*,qux"]) self.assertEqual(result.exit_code, 0) teams = [u"student1-student2", u"student3-student4"] students_team = [(students[0], students[1]), (students[2], students[3])] self.register_team(students_team[0], teams[0], "pa1", course_id) self.register_team(students_team[1], teams[1], "pa1", course_id) _, _, team_commits = self.create_team_repos(admin, course_id, teams[0:2], students_team[0:2]) # Team 0 and 1 submit result = students_team[0][0].run("student assignment submit", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS) result = students_team[1][0].run("student assignment submit", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS) for team, student_team in zip(teams, students_team): result = student_team[0].run("student team show", [team]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS) # Let the deadline "pass" new_now = get_datetime_now_utc() + timedelta(hours=2) set_testing_now(new_now) print() print("~~~ Time has moved 'forward' by two hours ~~~") print() # Instructor uploads to Gradescope. Both repos should be skipped # because we haven't created the the grading repos yet result = instructors[0].run("instructor grading gradescope-upload", ["--dry-run", "pa1"]) self.assertEqual(result.exit_code, 0) # Instructor creates grading repos result = instructors[0].run("instructor grading create-grading-repos", ["--master", "pa1"]) self.assertEqual(result.exit_code, 0) # Instructor uploads to Gradescope. Both repos should be skipped # because they're missing required file "qux" result = instructors[0].run("instructor grading gradescope-upload", ["--dry-run", "pa1"]) self.assertEqual(result.exit_code, 0) # We change the list of expected files result = instructors[0].run("instructor assignment set-attribute", ["pa1", "expected_files", "foo,b*"]) self.assertEqual(result.exit_code, 0) # Instructor uploads to Gradescope. Both repos should be uploaded # (but we're running in dry-run mode, so we don't actually contact # Gradescope) result = instructors[0].run("instructor grading gradescope-upload", ["--dry-run", "pa1"]) self.assertEqual(result.exit_code, 0)
def test_complete_with_multiple_instructors_multiple_graders(self, runner): course_id = u"cmsc40200" course_name = u"Foobarmentals of Foobar" admin_id = u"admin" instructor_ids = [u"instructor1", u"instructor2"] grader_ids= [u"grader1", u"grader2"] student_ids = [u"student1", u"student2", u"student3", u"student4"] all_users = instructor_ids + grader_ids + student_ids admin, instructors, graders, students = self.create_clients(runner, admin_id, instructor_ids, grader_ids, student_ids, course_id, verbose = True) self.create_users(admin, all_users) self.create_course(admin, course_id, course_name) self.add_users_to_course(admin, course_id, instructors, graders, students) students_team = [[s] for s in students] deadline = get_datetime_now_utc() + timedelta(hours=1) deadline = convert_datetime_to_local(deadline) deadline = deadline.replace(tzinfo=None).isoformat(sep=" ") result = instructors[0].run("instructor assignment add", ["pa1", "Programming Assignment 1", deadline]) self.assertEqual(result.exit_code, 0) pa1_rubric = """Points: - The PA1 Tests: Points Possible: 50 Points Obtained: - The PA1 Design: Points Possible: 50 Points Obtained: Total Points: 0 / 100 """ with open("pa1.rubric.txt", "w") as f: f.write(pa1_rubric) result = instructors[0].run("instructor assignment add-rubric", ["pa1", "pa1.rubric.txt"]) self.assertEqual(result.exit_code, 0) result = admin.run("admin course show", ["--include-users", "--include-assignments", course_id]) self.assertEqual(result.exit_code, 0) for student_id, student in zip(student_ids, students): self.register_team([student], student_id, "pa1", course_id) for student_id, student in zip(student_ids, students): result = student.run("student team list") self.assertEqual(result.exit_code, 0) self.assertIn(student_id, result.output) result = student.run("student team show", [student_id]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor team list") self.assertEqual(result.exit_code, 0) for student_id in student_ids: result = instructors[0].run("instructor team show", [student_id]) self.assertEqual(result.exit_code, 0) student_git_paths, student_git_repos, team_commits = self.create_team_repos(admin, course_id, student_ids, students_team) for student_id, student in zip(student_ids, students): result = student.run("student assignment submit", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS) result = student.run("student team show", [student_id]) self.assertEqual(result.exit_code, 0) # Let the deadline "pass" new_now = get_datetime_now_utc() + timedelta(hours=2) set_testing_now(new_now) print() print("~~~ Time has moved 'forward' by two hours ~~~") print() # The "master instructor" creates the grading repos result = instructors[0].run("instructor grading list-submissions", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading create-grading-repos", ["--master", "pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading assign-grader", ["pa1", "student1", "grader1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading assign-grader", ["pa1", "student2", "grader1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading assign-grader", ["pa1", "student3", "grader2"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading assign-grader", ["pa1", "student4", "grader2"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading list-grader-assignments", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading show-grading-status", ["--by-grader", "pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading push-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) # The non-master instructor downloads the grading repos result = instructors[1].run("instructor grading create-grading-repos", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[1].run("instructor grading show-grading-status", ["--by-grader", "pa1"]) self.assertEqual(result.exit_code, 0) # Grader 1 pulls their grading result = graders[0].run("grader pull-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) student1_grading_repo_path = "chisubmit-test/repositories/%s/%s/%s" % (course_id, "pa1", "student1") student2_grading_repo_path = "chisubmit-test/repositories/%s/%s/%s" % (course_id, "pa1", "student2") student_git_repos[0], student_git_paths[0] = graders[0].get_local_git_repository(student1_grading_repo_path) student_git_repos[1], student_git_paths[1] = graders[0].get_local_git_repository(student2_grading_repo_path) student1_rubric_path = "%s/pa1.rubric.txt" % student_git_paths[0] student2_rubric_path = "%s/pa1.rubric.txt" % student_git_paths[1] # Grader 1 grades student1 and pushes the grading. student1_rubric = """Points: - The PA1 Tests: Points Possible: 50 Points Obtained: 45 - The PA1 Design: Points Possible: 50 Points Obtained: 30 Penalties: Used O(n^156) algorithm: -10 Submitted code in a Word document: -30 Bonuses: Worked alone: 15 Total Points: 50 / 100 Comments: > None""" with open(student1_rubric_path, "w") as f: f.write(student1_rubric) result = graders[0].run("grader validate-rubrics", ["pa1"]) self.assertEqual(result.exit_code, 0) student_git_repos[0].index.add(["pa1.rubric.txt"]) student_git_repos[0].index.commit("Finished grading") result = graders[0].run("grader push-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) # The non-master instructor pulls the repos and generates a report result = instructors[1].run("instructor grading pull-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[1].run("instructor grading show-grading-status", ["--by-grader", "pa1"]) self.assertEqual(result.exit_code, 0) # Grader 1 grades student2 and pushes the grading. student2_rubric = """Points: - The PA1 Tests: Points Possible: 50 Points Obtained: 50 - The PA1 Design: Points Possible: 50 Points Obtained: 45 Total Points: 95 / 100 Comments: > Great job!""" with open(student2_rubric_path, "w") as f: f.write(student2_rubric) result = graders[0].run("grader validate-rubrics", ["pa1"]) self.assertEqual(result.exit_code, 0) student_git_repos[1].index.add(["pa1.rubric.txt"]) student_git_repos[1].index.commit("Finished grading") result = graders[0].run("grader push-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) # The non-master instructor pulls the repos and generates a report result = instructors[1].run("instructor grading pull-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[1].run("instructor grading show-grading-status", ["--by-grader", "pa1"]) self.assertEqual(result.exit_code, 0) # Grader 2 pulls their grading result = graders[1].run("grader pull-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) student3_grading_repo_path = "chisubmit-test/repositories/%s/%s/%s" % (course_id, "pa1", "student3") student4_grading_repo_path = "chisubmit-test/repositories/%s/%s/%s" % (course_id, "pa1", "student4") student_git_repos[2], student_git_paths[2] = graders[1].get_local_git_repository(student3_grading_repo_path) student_git_repos[3], student_git_paths[3] = graders[1].get_local_git_repository(student4_grading_repo_path) student3_rubric_path = "%s/pa1.rubric.txt" % student_git_paths[2] student4_rubric_path = "%s/pa1.rubric.txt" % student_git_paths[3] # Grader 2 adds the empty rubrics (which should be generated by pull-grading) result = graders[1].run("grader validate-rubrics", ["pa1"]) self.assertEqual(result.exit_code, 0) student_git_repos[2].index.add(["pa1.rubric.txt"]) student_git_repos[2].index.commit("Added rubric") student_git_repos[3].index.add(["pa1.rubric.txt"]) student_git_repos[3].index.commit("Added rubric") result = graders[1].run("grader push-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) # The non-master instructor pulls the repos and generates a report result = instructors[1].run("instructor grading pull-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[1].run("instructor grading show-grading-status", ["--by-grader", "pa1"]) self.assertEqual(result.exit_code, 0) # Grader 2 grades student3 but does only a partial grading of student4 student3_rubric = """Points: - The PA1 Tests: Points Possible: 50 Points Obtained: 20 - The PA1 Design: Points Possible: 50 Points Obtained: 15 Total Points: 35 / 100 Comments: > Needs improvement!""" with open(student3_rubric_path, "w") as f: f.write(student3_rubric) student4_rubric = """Points: - The PA1 Tests: Points Possible: 50 Points Obtained: 35 - The PA1 Design: Points Possible: 50 Points Obtained: Total Points: 35 / 100 Comments: > """ with open(student4_rubric_path, "w") as f: f.write(student4_rubric) result = graders[1].run("grader validate-rubrics", ["pa1"]) self.assertEqual(result.exit_code, 0) student_git_repos[2].index.add(["pa1.rubric.txt"]) student_git_repos[2].index.commit("Finished grading") student_git_repos[3].index.add(["pa1.rubric.txt"]) student_git_repos[3].index.commit("Grading in progress") result = graders[1].run("grader push-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) # The non-master instructor pulls the repos and generates a report result = instructors[1].run("instructor grading pull-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[1].run("instructor grading show-grading-status", ["--by-grader", "pa1"]) self.assertEqual(result.exit_code, 0) # Grader 2 finishes grading student4_rubric = """Points: - The PA1 Tests: Points Possible: 50 Points Obtained: 35 - The PA1 Design: Points Possible: 50 Points Obtained: 25 Total Points: 60 / 100 Comments: > """ with open(student4_rubric_path, "w") as f: f.write(student4_rubric) result = graders[1].run("grader validate-rubrics", ["pa1"]) self.assertEqual(result.exit_code, 0) student_git_repos[3].index.add(["pa1.rubric.txt"]) student_git_repos[3].index.commit("Finished grading") result = graders[1].run("grader push-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) # The non-master instructor pulls the repos and generates a report result = instructors[1].run("instructor grading pull-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[1].run("instructor grading show-grading-status", ["--by-grader", "pa1"]) self.assertEqual(result.exit_code, 0) # The master instructor pulls the repos and pushes them to the students result = instructors[0].run("instructor grading pull-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading show-grading-status", ["--by-grader", "pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading collect-rubrics", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading show-grading-status", ["--use-stored-grades", "--by-grader", "pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading list-grades") self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading push-grading", ["--to-students", "--yes", "pa1"]) self.assertEqual(result.exit_code, 0) for student_id, student in zip(student_ids, students): repo, path = student.get_local_git_repository(student_id) repo.remote("origin").pull("pa1-grading:pa1-grading") repo.heads["pa1-grading"].checkout() self.assertTrue(os.path.exists(path + "/pa1.rubric.txt"))
def assignment_submit(course_id, assignment_id): now = get_datetime_now_utc() course = Course.query.filter_by(id=course_id).first() if course is None: abort(404) check_course_access_or_abort(g.user, course, 404, roles=["student"]) assignment = Assignment.query.filter_by(id=assignment_id, course_id=course_id).first() # TODO 12DEC14: check permissions *before* 404 if assignment is None: abort(404) if not g.user.is_student_in(course): error_msg = "You are not a student in course '%s'" % (course_id) return jsonify(errors={"register": error_msg}), 400 if request.method == 'POST': input_data = request.get_json(force=True) if not isinstance(input_data, dict): return jsonify(error='Request data must be a JSON Object'), 400 form = SubmitAssignmentInput.from_json(input_data) if not form.validate(): return jsonify(errors=form.errors), 400 team_id = form.team_id.data commit_sha = form.commit_sha.data extensions_requested = form.extensions.data dry_run = form.dry_run.data team = Team.query.filter_by(id=team_id).first() if team is None: abort(404) check_team_access_or_abort(g.user, team, 404) team_assignment = AssignmentsTeams.from_id(course.id, team.id, assignment.id) if team_assignment is None: msg = "Team '%s' is not registered for assignment '%s'" % ( team.id, assignment.id) return jsonify(errors={"team": msg}), 400 if team_assignment.is_ready_for_grading(): msg = "You cannot re-submit assignment %s." % (assignment.id) msg = " You made a submission before the deadline, and the deadline has passed." return jsonify(errors={"submit": msg}), 400 response = {} response["dry_run"] = dry_run response["prior_submission"] = {} response["prior_submission"][ "submitted_at"] = team_assignment.submitted_at response["prior_submission"]["commit_sha"] = team_assignment.commit_sha response["prior_submission"][ "extensions_used"] = team_assignment.extensions_used response["submission"] = {} response["submission"]["course_id"] = course.id response["submission"]["assignment_id"] = assignment.id response["submission"]["submitted_at"] = now response["submission"]["deadline"] = assignment.deadline extensions_needed = compute_extensions_needed( submission_time=now, deadline=assignment.deadline) extension_policy = course.options.get("extension-policy", None) extensions_available = team.get_extensions_available(extension_policy) if extensions_available < 0: error_msg = "The number of available extensions is negative" return jsonify(errors={"fatal": error_msg}), 500 response["submission"]["extensions_requested"] = extensions_requested response["submission"]["extensions_needed"] = extensions_needed response["team"] = {} response["team"]["id"] = team.id response["team"]["extensions_available_before"] = extensions_available if extensions_available + team_assignment.extensions_used >= extensions_needed and extensions_requested == extensions_needed: response["success"] = True # If the team has already used extensions for a previous submission, # they don't count towards the number of extensions needed # They are 'credited' to the available extensions extensions_available += team_assignment.extensions_used extensions_available -= extensions_needed if not dry_run: team_assignment.extensions_used = extensions_needed team_assignment.commit_sha = commit_sha team_assignment.submitted_at = now db.session.add(team_assignment) db.session.commit() else: response["success"] = False response["team"]["extensions_available"] = extensions_available return jsonify(response)
def student_assignment_cancel_submit(ctx, course, team_id, assignment_id, yes): assignment = course.get_assignment(assignment_id) if assignment is None: print "Assignment %s does not exist" % assignment_id ctx.exit(CHISUBMIT_FAIL) team = course.get_team(team_id) if team is None: print "Team %s does not exist" % team_id ctx.exit(CHISUBMIT_FAIL) ta = team.get_assignment(assignment_id) if ta is None: print "Team %s is not registered for assignment %s" % (team_id, assignment_id) ctx.exit(CHISUBMIT_FAIL) if ta.submitted_at is None: print "Team %s has not made a submission for assignment %s," % ( team_id, assignment_id) print "so there is nothing to cancel." ctx.exit(CHISUBMIT_FAIL) if ta.submitted_at is not None: now = get_datetime_now_utc() deadline = assignment.deadline + timedelta(days=ta.extensions_used) if now > deadline: print "You cannot cancel this submission." print "You made a submission before the deadline, and the deadline has passed." ctx.exit(CHISUBMIT_FAIL) conn = create_connection(course, ctx.obj['config']) if conn is None: print "Could not connect to git server." ctx.exit(CHISUBMIT_FAIL) submission_commit = conn.get_commit(course, team, ta.commit_sha) print print "This is your existing submission for assignment %s:" % assignment.id print if submission_commit is None: print "WARNING: Previously submitted commit '%s' is not in the repository!" % ta.commit_sha else: print_commit(submission_commit) print print "Are you sure you want to cancel this submission? (y/n): ", if not yes: yesno = raw_input() else: yesno = 'y' print 'y' if yesno in ('y', 'Y', 'yes', 'Yes', 'YES'): response = assignment.cancel(team_id) # TODO: Can't do this until GitLab supports updating tags # # message = "Extensions: %i\n" % extensions_requested # if submission_tag is None: # conn.create_submission_tag(course, team, tag_name, message, commit.sha) # else: # conn.update_submission_tag(course, team, tag_name, message, commit.sha) print if response["success"]: print "Your submission has been cancelled." else: print "ERROR: Your submission was not cancelled."
def assignment_submit(course_id, assignment_id): now = get_datetime_now_utc() course = Course.query.filter_by(id=course_id).first() if course is None: abort(404) check_course_access_or_abort(g.user, course, 404, roles=["student"]) assignment = Assignment.query.filter_by(id=assignment_id, course_id=course_id).first() # TODO 12DEC14: check permissions *before* 404 if assignment is None: abort(404) if not g.user.is_student_in(course): error_msg = "You are not a student in course '%s'" % (course_id) return jsonify(errors={"register": error_msg}), 400 if request.method == 'POST': input_data = request.get_json(force=True) if not isinstance(input_data, dict): return jsonify(error='Request data must be a JSON Object'), 400 form = SubmitAssignmentInput.from_json(input_data) if not form.validate(): return jsonify(errors=form.errors), 400 team_id = form.team_id.data commit_sha = form.commit_sha.data extensions_requested = form.extensions.data dry_run = form.dry_run.data team = Team.query.filter_by(id=team_id).first() if team is None: abort(404) check_team_access_or_abort(g.user, team, 404) team_assignment = AssignmentsTeams.from_id(course.id,team.id,assignment.id) if team_assignment is None: msg = "Team '%s' is not registered for assignment '%s'" % (team.id, assignment.id) return jsonify(errors={"team":msg}), 400 if team_assignment.is_ready_for_grading(): msg = "You cannot re-submit assignment %s." % (assignment.id) msg = " You made a submission before the deadline, and the deadline has passed." return jsonify(errors={"submit":msg}), 400 response = {} response["dry_run"] = dry_run response["prior_submission"] = {} response["prior_submission"]["submitted_at"] = team_assignment.submitted_at response["prior_submission"]["commit_sha"] = team_assignment.commit_sha response["prior_submission"]["extensions_used"] = team_assignment.extensions_used response["submission"] = {} response["submission"]["course_id"] = course.id response["submission"]["assignment_id"] = assignment.id response["submission"]["submitted_at"] = now response["submission"]["deadline"] = assignment.deadline extensions_needed = compute_extensions_needed(submission_time = now, deadline = assignment.deadline) extension_policy = course.options.get("extension-policy", None) extensions_available = team.get_extensions_available(extension_policy) if extensions_available < 0: error_msg = "The number of available extensions is negative" return jsonify(errors={"fatal": error_msg}), 500 response["submission"]["extensions_requested"] = extensions_requested response["submission"]["extensions_needed"] = extensions_needed response["team"] = {} response["team"]["id"] = team.id response["team"]["extensions_available_before"] = extensions_available if extensions_available + team_assignment.extensions_used >= extensions_needed and extensions_requested == extensions_needed: response["success"] = True # If the team has already used extensions for a previous submission, # they don't count towards the number of extensions needed # They are 'credited' to the available extensions extensions_available += team_assignment.extensions_used extensions_available -= extensions_needed if not dry_run: team_assignment.extensions_used = extensions_needed team_assignment.commit_sha = commit_sha team_assignment.submitted_at = now db.session.add(team_assignment) db.session.commit() else: response["success"] = False response["team"]["extensions_available"] = extensions_available return jsonify(response)
def test_complete_with_extensions_per_student(self, runner): course_id = u"cmsc40300" course_name = u"Foobarmentals of Foobar II" admin_id = u"admin" instructor_ids = [u"instructor"] grader_ids= [u"grader"] student_ids = [u"student1", u"student2", u"student3", u"student4"] all_users = instructor_ids + grader_ids + student_ids admin, instructors, graders, students = self.create_clients(runner, admin_id, instructor_ids, grader_ids, student_ids, course_id, verbose = True) self.create_users(admin, all_users) self.create_course(admin, course_id, course_name) course = Course.get_by_course_id(course_id) self.assertIsNotNone(course) self.assertEquals(course.name, course_name) result = admin.run("admin course set-attribute %s default_extensions 3" % (course_id)) self.assertEquals(result.exit_code, 0) result = admin.run("admin course set-attribute %s extension_policy per-student" % (course_id)) self.assertEquals(result.exit_code, 0) self.add_users_to_course(admin, course_id, instructors, graders, students) deadline = get_datetime_now_utc() - timedelta(hours=23) deadline = deadline.replace(tzinfo=None).isoformat(sep=" ") result = instructors[0].run("instructor assignment add", ["pa1", "Programming Assignment 1", deadline]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor assignment set-attribute", ["pa1", "max_students", "2"]) self.assertEquals(result.exit_code, 0) deadline = get_datetime_now_utc() - timedelta(hours=47) deadline = deadline.isoformat(sep=" ") result = instructors[0].run("instructor assignment add", ["pa2", "Programming Assignment 2", deadline]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor assignment set-attribute", ["pa2", "max_students", "2"]) self.assertEquals(result.exit_code, 0) deadline = get_datetime_now_utc() - timedelta(hours=47) deadline = deadline.isoformat(sep=" ") result = instructors[0].run("instructor assignment add", ["pa3", "Programming Assignment 3", deadline]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor assignment set-attribute", ["pa3", "max_students", "2"]) self.assertEquals(result.exit_code, 0) deadline = get_datetime_now_utc() - timedelta(hours=23) deadline = deadline.replace(tzinfo=None).isoformat(sep=" ") result = instructors[0].run("instructor assignment add", ["pa4", "Programming Assignment 4", deadline]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor assignment set-attribute", ["pa4", "max_students", "2"]) self.assertEquals(result.exit_code, 0) deadline = get_datetime_now_utc() + timedelta(hours=2) deadline = deadline.replace(tzinfo=None).isoformat(sep=" ") result = instructors[0].run("instructor assignment add", ["pa5", "Programming Assignment 5", deadline]) self.assertEquals(result.exit_code, 0) result = instructors[0].run("instructor assignment set-attribute", ["pa5", "max_students", "2"]) self.assertEquals(result.exit_code, 0) teams = [u"student1-student2", u"student3-student4", u"student1-student3", u"student2-student4"] students_team = [ (students[0], students[1]), (students[2], students[3]), (students[0], students[2]), (students[1], students[3])] self.register_team(students_team[0], teams[0], "pa1", course_id) self.register_team(students_team[1], teams[1], "pa2", course_id) team_git_paths, team_git_repos, team_commits = self.create_team_repos(admin, course_id, teams[0:2], students_team[0:2]) self.register_team(students_team[2], teams[2], "pa3", course_id) self.register_team(students_team[2], teams[2], "pa4", course_id) self.register_team(students_team[2], teams[2], "pa5", course_id) self.register_team(students_team[3], teams[3], "pa3", course_id) self.register_team(students_team[3], teams[3], "pa4", course_id) self.register_team(students_team[3], teams[3], "pa5", course_id) x, y, z = self.create_team_repos(admin, course_id, teams[2:4], students_team[2:4]) team_git_paths += x team_git_repos += y team_commits += z for s in students: result = s.run("student course show-extensions") self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) # Team 0 submits with one extension to pa1 # Student 0 and 1 now have 2 extensions left each result = students_team[0][0].run("student assignment submit", ["pa1", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) s1 = course.get_student(get_user_by_username(students_team[0][0].user_id)) s2 = course.get_student(get_user_by_username(students_team[0][1].user_id)) t = course.get_team(teams[0]) self.assertEqual(t.get_extensions_available(), 2) self.assertEqual(s1.get_extensions_available(), 2) self.assertEqual(s2.get_extensions_available(), 2) for s in students: result = s.run("student course show-extensions") self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) # Team 1 submits with two extensions to pa2 # Student 2 and 3 now have 1 extension left each result = students_team[1][0].run("student assignment submit", ["pa2", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) s1 = course.get_student(get_user_by_username(students_team[1][0].user_id)) s2 = course.get_student(get_user_by_username(students_team[1][1].user_id)) t = course.get_team(teams[1]) self.assertEqual(t.get_extensions_available(), 1) self.assertEqual(s1.get_extensions_available(), 1) self.assertEqual(s2.get_extensions_available(), 1) for s in students: result = s.run("student course show-extensions") self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) result = students_team[0][0].run("student team show", [teams[0]]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) result = students_team[1][0].run("student team show", [teams[1]]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) # Now we have two new teams: # # Team 2 with Student 0 and 2, with 2 and 1 extensions left respectively. # This team can only submit to projects requiring one extension # # Team 3 with Student 1 and 3, with 2 and 1 extensions left respectively. # This team can only submit to projects requiring one extension # Team 2 tries to submit to pa3, but they are denied because they would # need two extensions to submit. result = students_team[2][0].run("student assignment submit", ["pa3", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_FAIL) s1 = course.get_student(get_user_by_username(students_team[2][0].user_id)) s2 = course.get_student(get_user_by_username(students_team[2][1].user_id)) t = course.get_team(teams[2]) self.assertEqual(t.get_extensions_available(), 1) self.assertEqual(s1.get_extensions_available(), 2) self.assertEqual(s2.get_extensions_available(), 1) # Team 2 tries submitting to pa4 and it goes through because it only # requires one extensions result = students_team[2][0].run("student assignment submit", ["pa4", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) s1 = course.get_student(get_user_by_username(students_team[2][0].user_id)) s2 = course.get_student(get_user_by_username(students_team[2][1].user_id)) t = course.get_team(teams[2]) self.assertEqual(t.get_extensions_available(), 0) self.assertEqual(s1.get_extensions_available(), 1) self.assertEqual(s2.get_extensions_available(), 0) for s in students: result = s.run("student course show-extensions") self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) # Team 2 tries submitting to pa5 with zero extensions and is accepted result = students_team[2][0].run("student assignment submit", ["pa5", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) s1 = course.get_student(get_user_by_username(students_team[2][0].user_id)) s2 = course.get_student(get_user_by_username(students_team[2][1].user_id)) t = course.get_team(teams[2]) self.assertEqual(t.get_extensions_available(), 0) self.assertEqual(s1.get_extensions_available(), 1) self.assertEqual(s2.get_extensions_available(), 0) for s in students: result = s.run("student course show-extensions") self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) # Team 3 tries submitting to pa5 and is accepted (doesn't require extensions) result = students_team[3][0].run("student assignment submit", ["pa5", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) s1 = course.get_student(get_user_by_username(students_team[3][0].user_id)) s2 = course.get_student(get_user_by_username(students_team[3][1].user_id)) t = course.get_team(teams[3]) self.assertEqual(t.get_extensions_available(), 1) self.assertEqual(s1.get_extensions_available(), 2) self.assertEqual(s2.get_extensions_available(), 1) for team, student_team in zip(teams, students_team): result = student_team[0].run("student team show", [team]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) for s in students: result = s.run("student course show-extensions") self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS)
def test_complete_with_submission_cancelling(self, runner): course_id = u"cmsc40300" course_name = u"Foobarmentals of Foobar II" admin_id = u"admin" instructor_ids = [u"instructor"] grader_ids= [u"grader"] student_ids = [u"student1", u"student2", u"student3", u"student4"] all_users = instructor_ids + grader_ids + student_ids admin, instructors, graders, students = self.create_clients(runner, course_id, admin_id, instructor_ids, grader_ids, student_ids) self.create_users(admin, all_users) self.create_course(admin, course_id, course_name) result = admin.run("admin course set-option %s default-extensions 3" % (course_id)) self.assertEquals(result.exit_code, 0) result = admin.run("admin course set-option %s extension-policy per_student" % (course_id)) self.assertEquals(result.exit_code, 0) self.add_users_to_course(admin, course_id, instructors, graders, students) deadline = get_datetime_now_utc() - timedelta(hours=23) deadline = deadline.isoformat(sep=" ") result = instructors[0].run("instructor assignment add", ["pa1", "Programming Assignment 1", deadline]) self.assertEquals(result.exit_code, 0) teams = [u"the-flaming-foobars", u"the-magnificent-mallocs"] students_team = [ (students[0], students[1]), (students[2], students[3])] self.register_team(students_team[0], teams[0], "pa1", course_id) self.register_team(students_team[1], teams[1], "pa1", course_id) _, _, team_commits = self.create_team_repos(admin, course_id, teams[0:2], students_team[0:2]) # Team 0 cancels their submission # Fails because there is nothing to cancel result = students_team[0][0].run("student assignment cancel-submit", [teams[0], "pa1", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_FAIL) # Team 0 and 1 submit with one extension to pa1 result = students_team[0][0].run("student assignment submit", [teams[0], "pa1", team_commits[0][0].hexsha, "--extensions", "1", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) result = students_team[1][0].run("student assignment submit", [teams[1], "pa1", team_commits[1][0].hexsha, "--extensions", "1", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) # Team 0 cancels their submission result = students_team[0][0].run("student assignment cancel-submit", [teams[0], "pa1", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) # Team 0 cancels their submission (again) # Fails because there is nothing to cancel result = students_team[0][0].run("student assignment cancel-submit", [teams[0], "pa1", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_FAIL) # Team 1 resubmits and is successful because the deadline hasn't passed yet result = students_team[1][0].run("student assignment submit", [teams[1], "pa1", team_commits[1][1].hexsha, "--extensions", "1", "--force", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) # Let the deadline "pass" new_now = get_datetime_now_utc() + timedelta(hours=2) set_testing_now(new_now) print print "~~~ Time has moved 'forward' by two hours ~~~" print # Team 0 submits and is successful because they cancelled their previous submission result = students_team[0][0].run("student assignment submit", [teams[0], "pa1", team_commits[0][1].hexsha, "--extensions", "2", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) # Team 1 submits and fails because their previous submission is final result = students_team[1][0].run("student assignment submit", [teams[1], "pa1", team_commits[1][0].hexsha, "--extensions", "2", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_FAIL) # Team 1 cancels their submission # Fails because the previous submission is final result = students_team[1][0].run("student assignment cancel-submit", [teams[1], "pa1", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_FAIL) for team, student_team in zip(teams, students_team): result = student_team[0].run("student team show", [team]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS)
def test_complete_with_multiple_instructors_multiple_graders(self, runner): course_id = u"cmsc40200" course_name = u"Foobarmentals of Foobar" admin_id = u"admin" instructor_ids = [u"instructor1", u"instructor2"] grader_ids = [u"grader1", u"grader2"] student_ids = [u"student1", u"student2", u"student3", u"student4"] all_users = instructor_ids + grader_ids + student_ids admin, instructors, graders, students = self.create_clients( runner, admin_id, instructor_ids, grader_ids, student_ids, course_id, verbose=True) self.create_users(admin, all_users) self.create_course(admin, course_id, course_name) self.add_users_to_course(admin, course_id, instructors, graders, students) students_team = [[s] for s in students] deadline = get_datetime_now_utc() + timedelta(hours=1) deadline = convert_datetime_to_local(deadline) deadline = deadline.replace(tzinfo=None).isoformat(sep=" ") result = instructors[0].run( "instructor assignment add", ["pa1", "Programming Assignment 1", deadline]) self.assertEqual(result.exit_code, 0) pa1_rubric = """Points: - The PA1 Tests: Points Possible: 50 Points Obtained: - The PA1 Design: Points Possible: 50 Points Obtained: Total Points: 0 / 100 """ with open("pa1.rubric.txt", "w") as f: f.write(pa1_rubric) result = instructors[0].run("instructor assignment add-rubric", ["pa1", "pa1.rubric.txt"]) self.assertEqual(result.exit_code, 0) result = admin.run( "admin course show", ["--include-users", "--include-assignments", course_id]) self.assertEqual(result.exit_code, 0) for student_id, student in zip(student_ids, students): self.register_team([student], student_id, "pa1", course_id) for student_id, student in zip(student_ids, students): result = student.run("student team list") self.assertEqual(result.exit_code, 0) self.assertIn(student_id, result.output) result = student.run("student team show", [student_id]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor team list") self.assertEqual(result.exit_code, 0) for student_id in student_ids: result = instructors[0].run("instructor team show", [student_id]) self.assertEqual(result.exit_code, 0) student_git_paths, student_git_repos, team_commits = self.create_team_repos( admin, course_id, student_ids, students_team) for student_id, student in zip(student_ids, students): result = student.run("student assignment submit", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS) result = student.run("student team show", [student_id]) self.assertEqual(result.exit_code, 0) # Let the deadline "pass" new_now = get_datetime_now_utc() + timedelta(hours=2) set_testing_now(new_now) print() print("~~~ Time has moved 'forward' by two hours ~~~") print() # The "master instructor" creates the grading repos result = instructors[0].run("instructor grading list-submissions", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading create-grading-repos", ["--master", "pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading assign-grader", ["pa1", "student1", "grader1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading assign-grader", ["pa1", "student2", "grader1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading assign-grader", ["pa1", "student3", "grader2"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading assign-grader", ["pa1", "student4", "grader2"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run( "instructor grading list-grader-assignments", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading show-grading-status", ["--by-grader", "pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading push-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) # The non-master instructor downloads the grading repos result = instructors[1].run("instructor grading create-grading-repos", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[1].run("instructor grading show-grading-status", ["--by-grader", "pa1"]) self.assertEqual(result.exit_code, 0) # Grader 1 pulls their grading result = graders[0].run("grader pull-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) student1_grading_repo_path = "chisubmit-test/repositories/%s/%s/%s" % ( course_id, "pa1", "student1") student2_grading_repo_path = "chisubmit-test/repositories/%s/%s/%s" % ( course_id, "pa1", "student2") student_git_repos[0], student_git_paths[0] = graders[ 0].get_local_git_repository(student1_grading_repo_path) student_git_repos[1], student_git_paths[1] = graders[ 0].get_local_git_repository(student2_grading_repo_path) student1_rubric_path = "%s/pa1.rubric.txt" % student_git_paths[0] student2_rubric_path = "%s/pa1.rubric.txt" % student_git_paths[1] # Grader 1 grades student1 and pushes the grading. student1_rubric = """Points: - The PA1 Tests: Points Possible: 50 Points Obtained: 45 - The PA1 Design: Points Possible: 50 Points Obtained: 30 Penalties: Used O(n^156) algorithm: -10 Submitted code in a Word document: -30 Bonuses: Worked alone: 15 Total Points: 50 / 100 Comments: > None""" with open(student1_rubric_path, "w") as f: f.write(student1_rubric) result = graders[0].run("grader validate-rubrics", ["pa1"]) self.assertEqual(result.exit_code, 0) student_git_repos[0].index.add(["pa1.rubric.txt"]) student_git_repos[0].index.commit("Finished grading") result = graders[0].run("grader push-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) # The non-master instructor pulls the repos and generates a report result = instructors[1].run("instructor grading pull-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[1].run("instructor grading show-grading-status", ["--by-grader", "pa1"]) self.assertEqual(result.exit_code, 0) # Grader 1 grades student2 and pushes the grading. student2_rubric = """Points: - The PA1 Tests: Points Possible: 50 Points Obtained: 50 - The PA1 Design: Points Possible: 50 Points Obtained: 45 Total Points: 95 / 100 Comments: > Great job!""" with open(student2_rubric_path, "w") as f: f.write(student2_rubric) result = graders[0].run("grader validate-rubrics", ["pa1"]) self.assertEqual(result.exit_code, 0) student_git_repos[1].index.add(["pa1.rubric.txt"]) student_git_repos[1].index.commit("Finished grading") result = graders[0].run("grader push-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) # The non-master instructor pulls the repos and generates a report result = instructors[1].run("instructor grading pull-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[1].run("instructor grading show-grading-status", ["--by-grader", "pa1"]) self.assertEqual(result.exit_code, 0) # Grader 2 pulls their grading result = graders[1].run("grader pull-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) student3_grading_repo_path = "chisubmit-test/repositories/%s/%s/%s" % ( course_id, "pa1", "student3") student4_grading_repo_path = "chisubmit-test/repositories/%s/%s/%s" % ( course_id, "pa1", "student4") student_git_repos[2], student_git_paths[2] = graders[ 1].get_local_git_repository(student3_grading_repo_path) student_git_repos[3], student_git_paths[3] = graders[ 1].get_local_git_repository(student4_grading_repo_path) student3_rubric_path = "%s/pa1.rubric.txt" % student_git_paths[2] student4_rubric_path = "%s/pa1.rubric.txt" % student_git_paths[3] # Grader 2 adds the empty rubrics (which should be generated by pull-grading) result = graders[1].run("grader validate-rubrics", ["pa1"]) self.assertEqual(result.exit_code, 0) student_git_repos[2].index.add(["pa1.rubric.txt"]) student_git_repos[2].index.commit("Added rubric") student_git_repos[3].index.add(["pa1.rubric.txt"]) student_git_repos[3].index.commit("Added rubric") result = graders[1].run("grader push-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) # The non-master instructor pulls the repos and generates a report result = instructors[1].run("instructor grading pull-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[1].run("instructor grading show-grading-status", ["--by-grader", "pa1"]) self.assertEqual(result.exit_code, 0) # Grader 2 grades student3 but does only a partial grading of student4 student3_rubric = """Points: - The PA1 Tests: Points Possible: 50 Points Obtained: 20 - The PA1 Design: Points Possible: 50 Points Obtained: 15 Total Points: 35 / 100 Comments: > Needs improvement!""" with open(student3_rubric_path, "w") as f: f.write(student3_rubric) student4_rubric = """Points: - The PA1 Tests: Points Possible: 50 Points Obtained: 35 - The PA1 Design: Points Possible: 50 Points Obtained: Total Points: 35 / 100 Comments: > """ with open(student4_rubric_path, "w") as f: f.write(student4_rubric) result = graders[1].run("grader validate-rubrics", ["pa1"]) self.assertEqual(result.exit_code, 0) student_git_repos[2].index.add(["pa1.rubric.txt"]) student_git_repos[2].index.commit("Finished grading") student_git_repos[3].index.add(["pa1.rubric.txt"]) student_git_repos[3].index.commit("Grading in progress") result = graders[1].run("grader push-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) # The non-master instructor pulls the repos and generates a report result = instructors[1].run("instructor grading pull-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[1].run("instructor grading show-grading-status", ["--by-grader", "pa1"]) self.assertEqual(result.exit_code, 0) # Grader 2 finishes grading student4_rubric = """Points: - The PA1 Tests: Points Possible: 50 Points Obtained: 35 - The PA1 Design: Points Possible: 50 Points Obtained: 25 Total Points: 60 / 100 Comments: > """ with open(student4_rubric_path, "w") as f: f.write(student4_rubric) result = graders[1].run("grader validate-rubrics", ["pa1"]) self.assertEqual(result.exit_code, 0) student_git_repos[3].index.add(["pa1.rubric.txt"]) student_git_repos[3].index.commit("Finished grading") result = graders[1].run("grader push-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) # The non-master instructor pulls the repos and generates a report result = instructors[1].run("instructor grading pull-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[1].run("instructor grading show-grading-status", ["--by-grader", "pa1"]) self.assertEqual(result.exit_code, 0) # The master instructor pulls the repos and pushes them to the students result = instructors[0].run("instructor grading pull-grading", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading show-grading-status", ["--by-grader", "pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading collect-rubrics", ["pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run( "instructor grading show-grading-status", ["--use-stored-grades", "--by-grader", "pa1"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading list-grades") self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor grading push-grading", ["--to-students", "--yes", "pa1"]) self.assertEqual(result.exit_code, 0) for student_id, student in zip(student_ids, students): repo, path = student.get_local_git_repository(student_id) repo.remote("origin").pull("pa1-grading:pa1-grading") repo.heads["pa1-grading"].checkout() self.assertTrue(os.path.exists(path + "/pa1.rubric.txt"))
def test_complete_with_extensions_per_student(self, runner): from chisubmit.backend.webapp.api.teams.models import Team from chisubmit.backend.webapp.api.courses.models import CoursesStudents course_id = u"cmsc40300" course_name = u"Foobarmentals of Foobar II" admin_id = u"admin" instructor_ids = [u"instructor"] grader_ids= [u"grader"] student_ids = [u"student1", u"student2", u"student3", u"student4"] all_users = instructor_ids + grader_ids + student_ids admin, instructors, graders, students = self.create_clients(runner, course_id, admin_id, instructor_ids, grader_ids, student_ids) self.create_users(admin, all_users) self.create_course(admin, course_id, course_name) result = admin.run("admin course set-option %s default-extensions 3" % (course_id)) self.assertEquals(result.exit_code, 0) result = admin.run("admin course set-option %s extension-policy per_student" % (course_id)) self.assertEquals(result.exit_code, 0) self.add_users_to_course(admin, course_id, instructors, graders, students) deadline = get_datetime_now_utc() - timedelta(hours=23) deadline = deadline.replace(tzinfo=None).isoformat(sep=" ") result = instructors[0].run("instructor assignment add", ["pa1", "Programming Assignment 1", deadline]) self.assertEquals(result.exit_code, 0) deadline = get_datetime_now_utc() - timedelta(hours=47) deadline = deadline.isoformat(sep=" ") result = instructors[0].run("instructor assignment add", ["pa2", "Programming Assignment 2", deadline]) self.assertEquals(result.exit_code, 0) deadline = get_datetime_now_utc() - timedelta(hours=47) deadline = deadline.isoformat(sep=" ") result = instructors[0].run("instructor assignment add", ["pa3", "Programming Assignment 3", deadline]) self.assertEquals(result.exit_code, 0) deadline = get_datetime_now_utc() - timedelta(hours=23) deadline = deadline.replace(tzinfo=None).isoformat(sep=" ") result = instructors[0].run("instructor assignment add", ["pa4", "Programming Assignment 4", deadline]) self.assertEquals(result.exit_code, 0) deadline = get_datetime_now_utc() + timedelta(hours=2) deadline = deadline.replace(tzinfo=None).isoformat(sep=" ") result = instructors[0].run("instructor assignment add", ["pa5", "Programming Assignment 5", deadline]) self.assertEquals(result.exit_code, 0) teams = [u"the-flaming-foobars", u"the-magnificent-mallocs", u"the-reticent-reallocs", u"the-panicked-printfs"] students_team = [ (students[0], students[1]), (students[2], students[3]), (students[0], students[2]), (students[1], students[3])] self.register_team(students_team[0], teams[0], "pa1", course_id) self.register_team(students_team[1], teams[1], "pa2", course_id) team_git_paths, team_git_repos, team_commits = self.create_team_repos(admin, course_id, teams[0:2], students_team[0:2]) self.register_team(students_team[2], teams[2], "pa3", course_id) self.register_team(students_team[2], teams[2], "pa4", course_id) self.register_team(students_team[2], teams[2], "pa5", course_id) self.register_team(students_team[3], teams[3], "pa3", course_id) self.register_team(students_team[3], teams[3], "pa4", course_id) self.register_team(students_team[3], teams[3], "pa5", course_id) x, y, z = self.create_team_repos(admin, course_id, teams[2:4], students_team[2:4]) team_git_paths += x team_git_repos += y team_commits += z # Team 0 submits with one extension to pa1 # Student 0 and 1 now have 2 extensions left each result = students_team[0][0].run("student assignment submit", [teams[0], "pa1", team_commits[0][0].hexsha, "--extensions", "1", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) cs1 = CoursesStudents.from_id(course_id, students_team[0][0].user_id) cs2 = CoursesStudents.from_id(course_id, students_team[0][1].user_id) t = Team.from_id(course_id, teams[0]) self.assertEqual(t.get_extensions_available("per_student"), 2) self.assertEqual(cs1.get_extensions_available(), 2) self.assertEqual(cs2.get_extensions_available(), 2) # Team 1 submits with two extensions to pa2 # Student 2 and 3 now have 1 extension left each result = students_team[1][0].run("student assignment submit", [teams[1], "pa2", team_commits[1][0].hexsha, "--extensions", "2", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) cs1 = CoursesStudents.from_id(course_id, students_team[1][0].user_id) cs2 = CoursesStudents.from_id(course_id, students_team[1][1].user_id) t = Team.from_id(course_id, teams[1]) self.assertEqual(t.get_extensions_available("per_student"), 1) self.assertEqual(cs1.get_extensions_available(), 1) self.assertEqual(cs2.get_extensions_available(), 1) result = students_team[0][0].run("student team show", [teams[0]]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) result = students_team[1][0].run("student team show", [teams[1]]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) # Now we have two new teams: # # Team 2 with Student 0 and 2, with 2 and 1 extensions left respectively. # This team can only submit to projects requiring one extension # # Team 3 with Student 1 and 3, with 2 and 1 extensions left respectively. # This team can only submit to projects requiring one extension # Team 2 tries to submit to pa3 with one extension (one less than needed) # and is denied result = students_team[2][0].run("student assignment submit", [teams[2], "pa3", team_commits[2][0].hexsha, "--extensions", "1", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_FAIL) cs1 = CoursesStudents.from_id(course_id, students_team[2][0].user_id) cs2 = CoursesStudents.from_id(course_id, students_team[2][1].user_id) t = Team.from_id(course_id, teams[2]) self.assertEqual(t.get_extensions_available("per_student"), 1) self.assertEqual(cs1.get_extensions_available(), 2) self.assertEqual(cs2.get_extensions_available(), 1) # Team 2 tries to submit to pa3 with two extensions (the right number, # but not enough because one of the students only has one extension left) # and is denied result = students_team[2][0].run("student assignment submit", [teams[2], "pa3", team_commits[2][0].hexsha, "--extensions", "2", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_FAIL) cs1 = CoursesStudents.from_id(course_id, students_team[2][0].user_id) cs2 = CoursesStudents.from_id(course_id, students_team[2][1].user_id) t = Team.from_id(course_id, teams[2]) self.assertEqual(t.get_extensions_available("per_student"), 1) self.assertEqual(cs1.get_extensions_available(), 2) self.assertEqual(cs2.get_extensions_available(), 1) # Team 2 tries submitting to pa4 with zero extensions (one less than needed) # and is denied result = students_team[2][0].run("student assignment submit", [teams[2], "pa4", team_commits[2][1].hexsha, "--extensions", "0", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_FAIL) cs1 = CoursesStudents.from_id(course_id, students_team[2][0].user_id) cs2 = CoursesStudents.from_id(course_id, students_team[2][1].user_id) t = Team.from_id(course_id, teams[2]) self.assertEqual(t.get_extensions_available("per_student"), 1) self.assertEqual(cs1.get_extensions_available(), 2) self.assertEqual(cs2.get_extensions_available(), 1) # Team 2 tries submitting to pa4 with one extension (the correct number) # and it goes through result = students_team[2][0].run("student assignment submit", [teams[2], "pa4", team_commits[2][1].hexsha, "--extensions", "1", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) cs1 = CoursesStudents.from_id(course_id, students_team[2][0].user_id) cs2 = CoursesStudents.from_id(course_id, students_team[2][1].user_id) t = Team.from_id(course_id, teams[2]) self.assertEqual(t.get_extensions_available("per_student"), 0) self.assertEqual(cs1.get_extensions_available(), 1) self.assertEqual(cs2.get_extensions_available(), 0) # Team 2 tries submitting to pa5 with zero extensions and is accepted result = students_team[2][0].run("student assignment submit", [teams[2], "pa5", team_commits[2][1].hexsha, "--extensions", "0", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) cs1 = CoursesStudents.from_id(course_id, students_team[2][0].user_id) cs2 = CoursesStudents.from_id(course_id, students_team[2][1].user_id) t = Team.from_id(course_id, teams[2]) self.assertEqual(t.get_extensions_available("per_student"), 0) self.assertEqual(cs1.get_extensions_available(), 1) self.assertEqual(cs2.get_extensions_available(), 0) # Team 3 tries submitting to pa5 with zero extensions and is accepted result = students_team[3][0].run("student assignment submit", [teams[3], "pa5", team_commits[3][1].hexsha, "--extensions", "0", "--yes"]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS) cs1 = CoursesStudents.from_id(course_id, students_team[3][0].user_id) cs2 = CoursesStudents.from_id(course_id, students_team[3][1].user_id) t = Team.from_id(course_id, teams[3]) self.assertEqual(t.get_extensions_available("per_student"), 1) self.assertEqual(cs1.get_extensions_available(), 2) self.assertEqual(cs2.get_extensions_available(), 1) for team, student_team in zip(teams, students_team): result = student_team[0].run("student team show", [team]) self.assertEquals(result.exit_code, CHISUBMIT_SUCCESS)
def test_complete_with_submission_grace_period(self, runner): course_id = u"cmsc40300" course_name = u"Foobarmentals of Foobar II" admin_id = u"admin" instructor_ids = [u"instructor"] grader_ids = [u"grader"] student_ids = [u"student1", u"student2", u"student3", u"student4"] all_users = instructor_ids + grader_ids + student_ids admin, instructors, graders, students = self.create_clients( runner, admin_id, instructor_ids, grader_ids, student_ids, course_id, verbose=True) self.create_users(admin, all_users) self.create_course(admin, course_id, course_name) course = Course.get_by_course_id(course_id) self.assertIsNotNone(course) self.assertEqual(course.name, course_name) result = admin.run( "admin course set-attribute %s default_extensions 2" % (course_id)) self.assertEqual(result.exit_code, 0) result = admin.run( "admin course set-attribute %s extension_policy per-student" % (course_id)) self.assertEqual(result.exit_code, 0) self.add_users_to_course(admin, course_id, instructors, graders, students) deadline = get_datetime_now_utc() - timedelta(minutes=5) deadline = deadline.isoformat(sep=" ") result = instructors[0].run( "instructor assignment add", ["pa1", "Programming Assignment 1", deadline]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor assignment set-attribute", ["pa1", "max_students", "2"]) self.assertEqual(result.exit_code, 0) result = instructors[0].run("instructor assignment set-attribute", ["pa1", "grace_period", "00:15"]) self.assertEqual(result.exit_code, 0) teams = [u"student1-student2", u"student3-student4"] students_team = [(students[0], students[1]), (students[2], students[3])] self.register_team(students_team[0], teams[0], "pa1", course_id) self.register_team(students_team[1], teams[1], "pa1", course_id) _, _, team_commits = self.create_team_repos(admin, course_id, teams[0:2], students_team[0:2]) # Team 0 submits during the grace period, and doesn't have to use an extension. result = students_team[0][0].run("student assignment submit", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS) t = course.get_team(teams[0]) self.assertEqual(t.get_extensions_available(), 2) # Let the grace period "pass" new_now = get_datetime_now_utc() + timedelta(minutes=11) set_testing_now(new_now) print() print( "~~~ Time has moved 'forward' to one minute after the grace period hours ~~~" ) print() # Team 1 submits and has to use an extensions because the grace period is over result = students_team[1][0].run("student assignment submit", ["pa1", "--yes"]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS) t = course.get_team(teams[1]) self.assertEqual(t.get_extensions_available(), 1) for team, student_team in zip(teams, students_team): result = student_team[0].run("student team show", [team]) self.assertEqual(result.exit_code, CHISUBMIT_SUCCESS)