Loading running_exercise/lib/exercise_updater.py +11 −0 Original line number Diff line number Diff line Loading @@ -371,6 +371,17 @@ class ExerciseStateUpdater: # not accounted for in the old exercise loop start = time.time() team_ids = [team_updater.team.id for team_updater in self.team_updaters] team_finish_times = dict( Team.objects.filter(id__in=team_ids).values_list( "id", "finish_time" ) ) for team_updater in self.team_updaters: team_updater.team.finish_time = team_finish_times.get( team_updater.team.id ) should_stop = True logs = [] for team_updater in self.team_updaters: Loading running_exercise/lib/milestone_handler.py +3 −0 Original line number Diff line number Diff line Loading @@ -67,6 +67,9 @@ class MilestoneHandler: } def final_milestone_reached(self) -> bool: if self.team.finish_time is not None: return True for name in self.final_milestone_names: if self.milestones[name].reached: return True Loading running_exercise/schema/query.py +6 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ from common_lib.utils import has_role, ensure_exists, ensure_all_exist from exercise.models import ( Team, Exercise, ExerciseState, MilestoneState, EmailParticipant, TeamLearningObjective, Loading Loading @@ -420,6 +421,11 @@ class Query(graphene.ObjectType): ).filter(id=int(team_id)) ) if team.exercise_state.status == ExerciseState.Status.FINISHED: return 0 if team.exercise.on_demand and team.finish_time is not None: return 0 # should be checking the SHOW_EXERCISE_TIME feature exercise_duration_s = team.exercise.config.exercise_duration * 60 return max(0, exercise_duration_s - int(team.exercise_state.elapsed_s)) Loading running_exercise/tests/exercise_updater_tests.py +39 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ from running_exercise.lib.exercise_updater import ( ExerciseStateUpdater, ) from running_exercise.models import LogType, ActionLog, TeamFileAccess from running_exercise.lib.milestone_handler import MilestoneHandler TEST_DATA_STORAGE = "exercise_updater_test_data" Loading Loading @@ -742,6 +743,44 @@ class ExerciseUpdaterTestCase(TestCase): self.assertTrue(should_finish2) self.assertTrue(should_finish3) def test_reaching_final_milestone_on_demand_persists(self): team: Team = self.on_demand_base_exercise.teams.first() updater = ExerciseStateUpdater(team.exercise_state) _, should_finish = updater.update(0) self.assertFalse(should_finish) external_team = Team.objects.get(id=team.id) handler = MilestoneHandler(external_team) handler.update(Control(activate_milestone=["evaluation_great"])) self.assertIsNotNone(Team.objects.get(id=team.id).finish_time) handler.update(Control(deactivate_milestone=["evaluation_great"])) milestone = self.on_demand_base_exercise.definition.milestones.get( name="evaluation_great" ) self.assertFalse( is_milestone_reached(Team.objects.get(id=team.id), milestone), msg=f"Milestone `{milestone.name}` should not be reached", ) self.assertIsNotNone(Team.objects.get(id=team.id).finish_time) _, should_finish = updater.update(1) self.assertTrue(should_finish) def test_finish_time_set_outside_loop_is_respected(self): team: Team = self.on_demand_base_exercise.teams.first() self.assertIsNotNone(team) updater = ExerciseStateUpdater(team.exercise_state) Team.objects.filter(id=team.id).update(finish_time=timezone.now()) _, should_stop = updater.update(1) self.assertTrue(should_stop) def test_show_exercise_overview_enabled_on_finish(self): exercise_state = self.base_exercise.single_state() updater = ExerciseStateUpdater(exercise_state) Loading Loading
running_exercise/lib/exercise_updater.py +11 −0 Original line number Diff line number Diff line Loading @@ -371,6 +371,17 @@ class ExerciseStateUpdater: # not accounted for in the old exercise loop start = time.time() team_ids = [team_updater.team.id for team_updater in self.team_updaters] team_finish_times = dict( Team.objects.filter(id__in=team_ids).values_list( "id", "finish_time" ) ) for team_updater in self.team_updaters: team_updater.team.finish_time = team_finish_times.get( team_updater.team.id ) should_stop = True logs = [] for team_updater in self.team_updaters: Loading
running_exercise/lib/milestone_handler.py +3 −0 Original line number Diff line number Diff line Loading @@ -67,6 +67,9 @@ class MilestoneHandler: } def final_milestone_reached(self) -> bool: if self.team.finish_time is not None: return True for name in self.final_milestone_names: if self.milestones[name].reached: return True Loading
running_exercise/schema/query.py +6 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ from common_lib.utils import has_role, ensure_exists, ensure_all_exist from exercise.models import ( Team, Exercise, ExerciseState, MilestoneState, EmailParticipant, TeamLearningObjective, Loading Loading @@ -420,6 +421,11 @@ class Query(graphene.ObjectType): ).filter(id=int(team_id)) ) if team.exercise_state.status == ExerciseState.Status.FINISHED: return 0 if team.exercise.on_demand and team.finish_time is not None: return 0 # should be checking the SHOW_EXERCISE_TIME feature exercise_duration_s = team.exercise.config.exercise_duration * 60 return max(0, exercise_duration_s - int(team.exercise_state.elapsed_s)) Loading
running_exercise/tests/exercise_updater_tests.py +39 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ from running_exercise.lib.exercise_updater import ( ExerciseStateUpdater, ) from running_exercise.models import LogType, ActionLog, TeamFileAccess from running_exercise.lib.milestone_handler import MilestoneHandler TEST_DATA_STORAGE = "exercise_updater_test_data" Loading Loading @@ -742,6 +743,44 @@ class ExerciseUpdaterTestCase(TestCase): self.assertTrue(should_finish2) self.assertTrue(should_finish3) def test_reaching_final_milestone_on_demand_persists(self): team: Team = self.on_demand_base_exercise.teams.first() updater = ExerciseStateUpdater(team.exercise_state) _, should_finish = updater.update(0) self.assertFalse(should_finish) external_team = Team.objects.get(id=team.id) handler = MilestoneHandler(external_team) handler.update(Control(activate_milestone=["evaluation_great"])) self.assertIsNotNone(Team.objects.get(id=team.id).finish_time) handler.update(Control(deactivate_milestone=["evaluation_great"])) milestone = self.on_demand_base_exercise.definition.milestones.get( name="evaluation_great" ) self.assertFalse( is_milestone_reached(Team.objects.get(id=team.id), milestone), msg=f"Milestone `{milestone.name}` should not be reached", ) self.assertIsNotNone(Team.objects.get(id=team.id).finish_time) _, should_finish = updater.update(1) self.assertTrue(should_finish) def test_finish_time_set_outside_loop_is_respected(self): team: Team = self.on_demand_base_exercise.teams.first() self.assertIsNotNone(team) updater = ExerciseStateUpdater(team.exercise_state) Team.objects.filter(id=team.id).update(finish_time=timezone.now()) _, should_stop = updater.update(1) self.assertTrue(should_stop) def test_show_exercise_overview_enabled_on_finish(self): exercise_state = self.base_exercise.single_state() updater = ExerciseStateUpdater(exercise_state) Loading