diff --git a/SAS/TMSS/backend/services/scheduling/test/t_dynamic_scheduling.py b/SAS/TMSS/backend/services/scheduling/test/t_dynamic_scheduling.py index 6c0dadc0f596759d7bb832be1205c96e5affa9f3..179d5c3bbacb2b60a3824f61ce32cc66ac3823af 100755 --- a/SAS/TMSS/backend/services/scheduling/test/t_dynamic_scheduling.py +++ b/SAS/TMSS/backend/services/scheduling/test/t_dynamic_scheduling.py @@ -117,7 +117,7 @@ class BaseDynamicSchedulingTestCase(unittest.TestCase): priority_queue = models.PriorityQueueType.objects.get(value=models.PriorityQueueType.Choices.A.value) if scheduling_set is None: - scheduling_set = TestDynamicScheduling.scheduling_set_medium + scheduling_set = models.SchedulingSet.objects.create(**SchedulingSet_test_data()) # ensure the (reused) project is active scheduling_set.project.project_state = models.ProjectState.objects.get(value=models.ProjectState.Choices.ACTIVE.value) @@ -169,7 +169,7 @@ class TestFixedTimeScheduling(BaseDynamicSchedulingTestCase): '''Test the behaviour of the dynamic scheduler for scheduling_units with a 'fixed_time' 'at' constraint''' def setUp(self) -> None: # wipe all scheduling_unit_drafts in between tests, so the tests don't influence each other - tmss_test_env.delete_scheduling_sets_cascade() + tmss_test_env.delete_scheduling_unit_drafts_cascade() models.Reservation.objects.all().delete() @staticmethod @@ -188,8 +188,8 @@ class TestFixedTimeScheduling(BaseDynamicSchedulingTestCase): if isinstance(obs_duration, timedelta): obs_duration = obs_duration.total_seconds() - scheduling_unit_draft = TestDynamicScheduling.create_simple_observation_scheduling_unit(name, scheduling_set=scheduling_set, obs_duration=obs_duration) - TestDynamicScheduling._clear_constraints(scheduling_unit_draft) + scheduling_unit_draft = BaseDynamicSchedulingTestCase.create_simple_observation_scheduling_unit(name, scheduling_set=scheduling_set, obs_duration=obs_duration) + BaseDynamicSchedulingTestCase._clear_constraints(scheduling_unit_draft) scheduling_unit_draft.scheduling_constraints_doc['scheduler'] = 'fixed_time' scheduling_unit_draft.scheduling_constraints_doc['time']['at'] = at.isoformat() scheduling_unit_draft.save() @@ -2380,30 +2380,34 @@ class TestReservedStationsTimeWindows(BaseDynamicSchedulingTestCase): self.assertTrue(can_run_within_station_reservations(self.scheduling_unit_blueprint)) -class TestTriggers(unittest.TestCase): +class TestTriggers(BaseDynamicSchedulingTestCase): """ Tests for scheduling behavior of triggered observations """ - def setUp(self): - tmss_test_env.delete_scheduling_sets_cascade() - models.Reservation.objects.all().delete() + @classmethod + def setUpClass(cls) -> None: + super().setUpClass() # create a scheduling set in a project that allows triggers - self.scheduling_set = models.SchedulingSet.objects.create(**SchedulingSet_test_data()) - self.scheduling_set.project.can_trigger = True - self.scheduling_set.project.save() + cls.scheduling_set = models.SchedulingSet.objects.create(**SchedulingSet_test_data()) + cls.scheduling_set.project.can_trigger = True + cls.scheduling_set.project.trigger_priority = 1 + cls.scheduling_set.project.save() # create a second scheduling set in a project that allows triggers and has higher trigger_priority - self.scheduling_set_high_trigger_priority = models.SchedulingSet.objects.create(**SchedulingSet_test_data()) - self.scheduling_set_high_trigger_priority.project.can_trigger = True - self.scheduling_set_high_trigger_priority.project.trigger_priority = self.scheduling_set_high_trigger_priority.project.trigger_priority + 1 - self.scheduling_set_high_trigger_priority.project.save() + cls.scheduling_set_high_trigger_priority = models.SchedulingSet.objects.create(**SchedulingSet_test_data()) + cls.scheduling_set_high_trigger_priority.project.can_trigger = True + cls.scheduling_set_high_trigger_priority.project.trigger_priority = cls.scheduling_set.project.trigger_priority + 1 + cls.scheduling_set_high_trigger_priority.project.save() - self.scheduler = Scheduler() + def setUp(self) -> None: + # wipe all scheduling_unit_drafts in between tests, so the tests don't influence each other + tmss_test_env.delete_scheduling_unit_drafts_cascade() + models.Reservation.objects.all().delete() def test_simple_triggered_scheduling_unit_gets_scheduled(self): - scheduling_unit_draft = TestDynamicScheduling.create_simple_observation_scheduling_unit( + scheduling_unit_draft = self.create_simple_observation_scheduling_unit( "triggered scheduling unit for %s" % self._testMethodName, scheduling_set=self.scheduling_set, interrupts_telescope=True) @@ -2418,7 +2422,7 @@ class TestTriggers(unittest.TestCase): def test_triggered_scheduling_unit_with_at_constraint_gets_scheduled_at_correct_time(self): - scheduling_unit_draft = TestDynamicScheduling.create_simple_observation_scheduling_unit( + scheduling_unit_draft = self.create_simple_observation_scheduling_unit( 'scheduling_unit for at %s' % self._testMethodName, scheduling_set=self.scheduling_set) # Clear constraints @@ -2444,13 +2448,13 @@ class TestTriggers(unittest.TestCase): def test_triggered_scheduling_unit_has_priority_over_regular_observation(self): - scheduling_unit_draft = TestDynamicScheduling.create_simple_observation_scheduling_unit( + scheduling_unit_draft = self.create_simple_observation_scheduling_unit( "scheduling unit for %s" % self._testMethodName, scheduling_set=self.scheduling_set, interrupts_telescope=False) regular_scheduling_unit_blueprint = create_scheduling_unit_blueprint_and_tasks_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft) - scheduling_unit_draft = TestDynamicScheduling.create_simple_observation_scheduling_unit( + scheduling_unit_draft = self.create_simple_observation_scheduling_unit( "triggered scheduling unit for %s" % self._testMethodName, scheduling_set=self.scheduling_set, interrupts_telescope=True) @@ -2470,7 +2474,7 @@ class TestTriggers(unittest.TestCase): def test_triggered_scheduling_unit_unschedules_regular_observation(self): # create a regular scheduling_unit - scheduling_unit_draft = TestDynamicScheduling.create_simple_observation_scheduling_unit( + scheduling_unit_draft = self.create_simple_observation_scheduling_unit( "scheduling unit for %s" % self._testMethodName, scheduling_set=self.scheduling_set, interrupts_telescope=False) @@ -2488,7 +2492,7 @@ class TestTriggers(unittest.TestCase): self.assertEqual(regular_scheduling_unit_blueprint.status.value, 'scheduled') # add a triggered scheduling_unit - scheduling_unit_draft = TestDynamicScheduling.create_simple_observation_scheduling_unit( + scheduling_unit_draft = self.create_simple_observation_scheduling_unit( "triggered scheduling unit for %s" % self._testMethodName, scheduling_set=self.scheduling_set, interrupts_telescope=True) @@ -2511,7 +2515,7 @@ class TestTriggers(unittest.TestCase): def test_triggered_scheduling_unit_cancels_regular_observation(self, kill_observation_subtask_mock): # create a regular scheduling_unit - scheduling_unit_draft = TestDynamicScheduling.create_simple_observation_scheduling_unit( + scheduling_unit_draft = self.create_simple_observation_scheduling_unit( "scheduling unit for %s" % self._testMethodName, scheduling_set=self.scheduling_set, interrupts_telescope=False) @@ -2544,7 +2548,7 @@ class TestTriggers(unittest.TestCase): self.assertNotIn(subtask, running_subtasks) # add a triggered scheduling_unit with higher priority - scheduling_unit_draft = TestDynamicScheduling.create_simple_observation_scheduling_unit( + scheduling_unit_draft = self.create_simple_observation_scheduling_unit( "triggered scheduling unit for %s" % self._testMethodName, scheduling_set=self.scheduling_set_high_trigger_priority, interrupts_telescope=True) @@ -2574,7 +2578,7 @@ class TestTriggers(unittest.TestCase): def test_triggered_scheduling_unit_does_not_cancel_regular_observation_with_same_trigger_priority(self, cancel_mock): # create a regular scheduling_unit - scheduling_unit_draft = TestDynamicScheduling.create_simple_observation_scheduling_unit( + scheduling_unit_draft = self.create_simple_observation_scheduling_unit( "scheduling unit for %s" % self._testMethodName, scheduling_set=self.scheduling_set, interrupts_telescope=False) @@ -2605,7 +2609,7 @@ class TestTriggers(unittest.TestCase): self.assertNotIn(subtask, running_subtasks) # add a triggered scheduling_unit with same trigger priority - scheduling_unit_draft = TestDynamicScheduling.create_simple_observation_scheduling_unit( + scheduling_unit_draft = self.create_simple_observation_scheduling_unit( "triggered scheduling unit for %s" % self._testMethodName, scheduling_set=self.scheduling_set, interrupts_telescope=True) @@ -2629,7 +2633,7 @@ class TestTriggers(unittest.TestCase): def test_triggered_scheduling_unit_does_not_cancel_regular_observation_if_it_cannot_run_anyway(self, cancel_mock): # create a regular scheduling_unit - scheduling_unit_draft = TestDynamicScheduling.create_simple_observation_scheduling_unit( + scheduling_unit_draft = self.create_simple_observation_scheduling_unit( "scheduling unit for %s" % self._testMethodName, scheduling_set=self.scheduling_set, interrupts_telescope=False) @@ -2660,7 +2664,7 @@ class TestTriggers(unittest.TestCase): self.assertNotIn(subtask, running_subtasks) # add a triggered scheduling_unit with higher priority, but a between constraint that can never be met - scheduling_unit_draft = TestDynamicScheduling.create_simple_observation_scheduling_unit( + scheduling_unit_draft = self.create_simple_observation_scheduling_unit( "triggered scheduling unit for %s" % self._testMethodName, scheduling_set=self.scheduling_set_high_trigger_priority, interrupts_telescope=True) @@ -2685,7 +2689,7 @@ class TestTriggers(unittest.TestCase): def test_triggered_scheduling_unit_gets_scheduled_in_correct_trigger_priority_order(self, cancel_mock): # create three regular scheduling_units, two with high trigger priority, one with lower - scheduling_unit_draft_high1 = TestDynamicScheduling.create_simple_observation_scheduling_unit( + scheduling_unit_draft_high1 = self.create_simple_observation_scheduling_unit( "scheduling unit for %s" % self._testMethodName, scheduling_set=self.scheduling_set_high_trigger_priority, interrupts_telescope=False) @@ -2693,7 +2697,7 @@ class TestTriggers(unittest.TestCase): regular_scheduling_unit_blueprint_high1.scheduling_constraints_doc = {} regular_scheduling_unit_blueprint_high1.save() - scheduling_unit_draft_high2 = TestDynamicScheduling.create_simple_observation_scheduling_unit( + scheduling_unit_draft_high2 = self.create_simple_observation_scheduling_unit( "scheduling unit for %s" % self._testMethodName, scheduling_set=self.scheduling_set_high_trigger_priority, interrupts_telescope=False) @@ -2701,7 +2705,7 @@ class TestTriggers(unittest.TestCase): regular_scheduling_unit_blueprint_high2.scheduling_constraints_doc = {} regular_scheduling_unit_blueprint_high2.save() - scheduling_unit_draft_low = TestDynamicScheduling.create_simple_observation_scheduling_unit( + scheduling_unit_draft_low = self.create_simple_observation_scheduling_unit( "scheduling unit for %s" % self._testMethodName, scheduling_set=self.scheduling_set, interrupts_telescope=False) @@ -2725,7 +2729,7 @@ class TestTriggers(unittest.TestCase): subtask.save() # add a triggered scheduling_unit with same priority - scheduling_unit_draft_trigger = TestDynamicScheduling.create_simple_observation_scheduling_unit( + scheduling_unit_draft_trigger = self.create_simple_observation_scheduling_unit( "triggered scheduling unit for %s" % self._testMethodName, scheduling_set=self.scheduling_set_high_trigger_priority, interrupts_telescope=True) @@ -2755,7 +2759,7 @@ class TestTriggers(unittest.TestCase): def test_triggered_scheduling_unit_goes_to_unschedulable_if_it_cannot_cancel_and_does_not_fit(self, cancel_mock): # create three regular scheduling_units, two with high trigger priority, one with lower - scheduling_unit_draft_high1 = TestDynamicScheduling.create_simple_observation_scheduling_unit( + scheduling_unit_draft_high1 = self.create_simple_observation_scheduling_unit( "scheduling unit for %s" % self._testMethodName, scheduling_set=self.scheduling_set_high_trigger_priority, interrupts_telescope=False) @@ -2763,7 +2767,7 @@ class TestTriggers(unittest.TestCase): regular_scheduling_unit_blueprint_high1.scheduling_constraints_doc = {} regular_scheduling_unit_blueprint_high1.save() - scheduling_unit_draft_high2 = TestDynamicScheduling.create_simple_observation_scheduling_unit( + scheduling_unit_draft_high2 = self.create_simple_observation_scheduling_unit( "scheduling unit for %s" % self._testMethodName, scheduling_set=self.scheduling_set_high_trigger_priority, interrupts_telescope=False) @@ -2771,7 +2775,7 @@ class TestTriggers(unittest.TestCase): regular_scheduling_unit_blueprint_high2.scheduling_constraints_doc = {} regular_scheduling_unit_blueprint_high2.save() - scheduling_unit_draft_low = TestDynamicScheduling.create_simple_observation_scheduling_unit( + scheduling_unit_draft_low = self.create_simple_observation_scheduling_unit( "scheduling unit for %s" % self._testMethodName, scheduling_set=self.scheduling_set, interrupts_telescope=False) @@ -2793,7 +2797,7 @@ class TestTriggers(unittest.TestCase): # add a triggered scheduling_unit with same trigger priority, and a between constraint that can only be met # when the regular obs would be cancelled (which is not allowed because it requires higher trigger priority). - scheduling_unit_draft_trigger = TestDynamicScheduling.create_simple_observation_scheduling_unit( + scheduling_unit_draft_trigger = self.create_simple_observation_scheduling_unit( "triggered scheduling unit for %s" % self._testMethodName, scheduling_set=self.scheduling_set_high_trigger_priority, interrupts_telescope=True) diff --git a/SAS/TMSS/backend/test/t_observation_strategies_specification_and_scheduling_test.py b/SAS/TMSS/backend/test/t_observation_strategies_specification_and_scheduling_test.py index 0d0ff3fb17b8b00185df1ab2e7f0d1197d277c44..71bdb5acedb17b4db29a23d77c7c3601727c6cfc 100755 --- a/SAS/TMSS/backend/test/t_observation_strategies_specification_and_scheduling_test.py +++ b/SAS/TMSS/backend/test/t_observation_strategies_specification_and_scheduling_test.py @@ -59,7 +59,7 @@ class TestObservationStrategiesSpecificationAndScheduling(unittest.TestCase): shutil.rmtree(cls.TEST_DIR, ignore_errors=True) def setUp(self) -> None: - self.tmss_test_env.delete_scheduling_sets_cascade() + self.tmss_test_env.delete_scheduling_unit_drafts_cascade() # prepare a new clean project and parent scheduling_set for each tested observation strategy template test_data_creator = self.tmss_test_env.create_test_data_creator() diff --git a/SAS/TMSS/backend/test/t_scheduling.py b/SAS/TMSS/backend/test/t_scheduling.py index 2150df7e8c63ea6342f86cf1c9acfbe838c49335..02fb92df927ebc65cf23c5e9000240a00aad3425 100755 --- a/SAS/TMSS/backend/test/t_scheduling.py +++ b/SAS/TMSS/backend/test/t_scheduling.py @@ -126,7 +126,7 @@ def duplicates(l: list) -> list: class SchedulingTest(unittest.TestCase): def setUp(self): - tmss_test_env.delete_scheduling_sets_cascade() + tmss_test_env.delete_scheduling_unit_drafts_cascade() models.Reservation.objects.all().delete() test_data_creator.wipe_cache() @@ -894,7 +894,7 @@ class TestWithUC1Specifications(unittest.TestCase): Note that this test requires Resource Assigner testenvironment being alive """ def setUp(self) -> None: - tmss_test_env.delete_scheduling_sets_cascade() + tmss_test_env.delete_scheduling_unit_drafts_cascade() models.Reservation.objects.all().delete() test_data_creator.wipe_cache() diff --git a/SAS/TMSS/backend/test/test_environment.py b/SAS/TMSS/backend/test/test_environment.py index 4dcbcc7beaea33f2fe554d2fd9937baa2de66e4c..0d97edb2d4ee43fb58aa2d8659c8444171145a2d 100644 --- a/SAS/TMSS/backend/test/test_environment.py +++ b/SAS/TMSS/backend/test/test_environment.py @@ -471,9 +471,9 @@ class TMSSTestEnvironment: from lofar.sas.tmss.test.tmss_test_data_rest import TMSSRESTTestDataCreator return TMSSRESTTestDataCreator(self.django_server.url, (self.django_server.ldap_dbcreds.user, self.django_server.ldap_dbcreds.password)) - def delete_scheduling_sets_cascade(self, mute_delete_event_messages: bool=True): - '''convenience method for TESTING to wipe ALL scheduling_sets, scheduling_unit_draft/blueprint, task_draft/blueprint, subtask, subtask_input/output, dataproducts in a cascading manner.''' - from lofar.sas.tmss.tmss.tmssapp.models import SchedulingSet, SubtaskState + def delete_scheduling_unit_drafts_cascade(self, mute_delete_event_messages: bool=True): + '''convenience method for TESTING to wipe ALL scheduling_unit_drafts, scheduling_unit_blueprints, task_draft/blueprint, subtask, subtask_input/output, dataproducts in a cascading manner.''' + from lofar.sas.tmss.tmss.tmssapp.models import SchedulingUnitDraft, SubtaskState from lofar.sas.tmss.tmss.tmssapp.subtasks import unschedule_subtask if self.postgres_listener is not None and mute_delete_event_messages: @@ -481,36 +481,35 @@ class TMSSTestEnvironment: self.postgres_listener.stop() # loop over all instances in the tree and delete them, as we modelled many of these models to PROTECT on delete instead of CASCADE (for good reason) - for scheduling_set in SchedulingSet.objects.all(): - for scheduling_unit_draft in scheduling_set.scheduling_unit_drafts.all(): - for scheduling_unit_blueprint in scheduling_unit_draft.scheduling_unit_blueprints.all(): - for task_blueprint in scheduling_unit_blueprint.task_blueprints.all(): - for subtask in task_blueprint.subtasks.all(): - try: - if subtask.state.value == SubtaskState.Choices.SCHEDULED.value: - unschedule_subtask(subtask) - except Exception as e: - logger.exception(e) - for output in subtask.outputs.all(): - for dataproduct in output.dataproducts.all(): - for transform in dataproduct.consumer_transforms.all(): - transform.delete() - for transform in dataproduct.producer_transforms.all(): - transform.delete() - dataproduct.delete() - for consumer in output.consumers.all(): - consumer.delete() - output.delete() - for input in subtask.inputs.all(): - input.delete() - subtask.delete() - task_blueprint.delete() - scheduling_unit_blueprint.delete() - - for task_draft in scheduling_unit_draft.task_drafts.all(): - task_draft.delete() - - scheduling_unit_draft.delete() + for scheduling_unit_draft in SchedulingUnitDraft.objects.all(): + for scheduling_unit_blueprint in scheduling_unit_draft.scheduling_unit_blueprints.all(): + for task_blueprint in scheduling_unit_blueprint.task_blueprints.all(): + for subtask in task_blueprint.subtasks.all(): + try: + if subtask.state.value == SubtaskState.Choices.SCHEDULED.value: + unschedule_subtask(subtask) + except Exception as e: + logger.exception(e) + for output in subtask.outputs.all(): + for dataproduct in output.dataproducts.all(): + for transform in dataproduct.consumer_transforms.all(): + transform.delete() + for transform in dataproduct.producer_transforms.all(): + transform.delete() + dataproduct.delete() + for consumer in output.consumers.all(): + consumer.delete() + output.delete() + for input in subtask.inputs.all(): + input.delete() + subtask.delete() + task_blueprint.delete() + scheduling_unit_blueprint.delete() + + for task_draft in scheduling_unit_draft.task_drafts.all(): + task_draft.delete() + + scheduling_unit_draft.delete() if self.postgres_listener is not None and mute_delete_event_messages: # restart the previously stopped postgres_listener