From 12c2ee5b72a6e378afb77cbdef0002d4573a409f Mon Sep 17 00:00:00 2001
From: Jorrit Schaap <schaap@astron.nl>
Date: Thu, 21 Sep 2023 13:30:11 +0200
Subject: [PATCH] TMSS-2733: added bug-reproducing test, which fails on
 expected behaviour and thus confirms the bug

---
 .../scheduling/test/t_dynamic_scheduling.py   | 58 +++++++++++++++++++
 1 file changed, 58 insertions(+)

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 80c2c5c0da3..4d31cd715c8 100755
--- a/SAS/TMSS/backend/services/scheduling/test/t_dynamic_scheduling.py
+++ b/SAS/TMSS/backend/services/scheduling/test/t_dynamic_scheduling.py
@@ -5163,6 +5163,64 @@ class TestTriggers(BaseDynamicSchedulingTestCase):
         self.assertEqual(regular_scheduling_unit_blueprint_low.status.value, 'schedulable')
 
 
+    @mock.patch("lofar.sas.tmss.tmss.tmssapp.subtasks.kill_observation_subtask")
+    def test_TMSS_2733_bugfix_do_cancel_calibrators_in_regular_unit(self, kill_observation_subtask_mock):
+        scheduling_set = models.SchedulingSet.objects.create(**SchedulingSet_test_data())
+        scheduling_set.project.trigger_priority = 0
+        scheduling_set.project.project_state = models.ProjectState.objects.get(value=models.ProjectState.Choices.ACTIVE.value)
+        scheduling_set.project.cycles.add(models.Cycle.objects.create(**Cycle_test_data(start=datetime.utcnow()-timedelta(days=1),
+                                                                                        stop=datetime.utcnow()+timedelta(days=1))))
+
+        strategy_template = models.SchedulingUnitObservingStrategyTemplate.get_latest(name="IM HBA - 1 Beam")
+        regular_su_draft = create_scheduling_unit_draft_from_observing_strategy_template(strategy_template, scheduling_set=scheduling_set)
+        regular_su_draft.scheduling_constraints_doc['scheduler'] = 'fixed_time'
+        regular_su_draft.scheduling_constraints_doc['time']['at'] = round_to_second_precision(datetime.utcnow() + timedelta(minutes=3)).isoformat()
+        regular_su_draft.scheduling_constraints_doc['sky']['transit_offset'] = {'from': -12 * 60 * 60, 'to': 12 * 60 * 60}
+        regular_su_draft.scheduling_constraints_doc['sky']['min_elevation'] = {'target': 0, 'calibrator': 0}
+        regular_su_draft.scheduling_constraints_doc['sky']['min_distance'] = {'sun': 0, 'moon': 0, 'jupiter': 0}
+        regular_su_draft.save()
+        regular_su_blueprint = create_scheduling_unit_blueprint_and_tasks_and_subtasks_from_scheduling_unit_draft(regular_su_draft)
+
+        scheduled_scheduling_units = self.scheduler.schedule_fixed_time_scheduling_units()
+        self.assertEqual(1, len(scheduled_scheduling_units))
+        self.assertEqual(regular_su_blueprint.id, scheduled_scheduling_units[0].id)
+
+        # put first obs to started state
+        first_obs_subtask = regular_su_blueprint.observation_tasks.order_by('scheduled_start_time').first().subtasks.first()
+        set_subtask_state_following_allowed_transitions(first_obs_subtask, 'started')
+
+        # create a triggered observation, overlapping with the first regular observation
+        scheduling_set = models.SchedulingSet.objects.create(**SchedulingSet_test_data())
+        scheduling_set.project.can_trigger = True
+        scheduling_set.project.trigger_priority = 10000
+        scheduling_set.project.project_state = models.ProjectState.objects.get(value=models.ProjectState.Choices.ACTIVE.value)
+        models.ProjectQuota.objects.create(project=scheduling_set.project.project, value=1000, resource_type=models.ResourceType.objects.get(quantity__value=models.Quantity.Choices.NUMBER.value, name__icontains='trigger'))
+        scheduling_set.project.cycles.add(models.Cycle.objects.create(**Cycle_test_data(start=datetime.utcnow()-timedelta(days=1),
+                                                                                        stop=datetime.utcnow()+timedelta(days=1))))
+        scheduling_unit_draft_trigger = self.create_simple_observation_scheduling_unit("triggered scheduling unit for %s" % self._testMethodName,
+                                                                                       obs_duration=60,
+                                                                                       scheduling_set=scheduling_set,
+                                                                                       interrupts_telescope=True)
+        triggered_scheduling_unit_blueprint = create_scheduling_unit_blueprint_and_tasks_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft_trigger)
+        triggered_scheduling_unit_blueprint.scheduling_constraints_doc = {'scheduler': 'dynamic', 'time': {'between': [{"from": first_obs_subtask.scheduled_start_time.isoformat(), "to": first_obs_subtask.scheduled_stop_time.isoformat()},]}}
+        triggered_scheduling_unit_blueprint.save()
+
+        # schedule the triggered observations
+        scheduled_scheduling_units = self.scheduler.do_dynamic_schedule()
+        self.assertEqual(1, len(scheduled_scheduling_units))
+        self.assertEqual(triggered_scheduling_unit_blueprint.id, scheduled_scheduling_units[0].id)
+
+        # the regular observations should have been cancelled.
+        kill_observation_subtask_mock.assert_called()
+        first_obs_subtask.refresh_from_db()
+        self.assertEqual(models.SubtaskState.Choices.CANCELLED.value, first_obs_subtask.state.value)
+
+        # and the rest of the tasks (observations & pipelines & etc) in the regular unit should be cancelled as well
+        for task in regular_su_blueprint.tasks.all():
+            task.refresh_from_db()
+            self.assertEqual(models.TaskStatus.Choices.CANCELLED.value, task.status.value)
+
+
 logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', level=logging.INFO)
 
 # # uncomment to show debug messages for scheduling modules
-- 
GitLab