diff --git a/SAS/ResourceAssignment/ResourceAssigner/lib/resource_assigner.py b/SAS/ResourceAssignment/ResourceAssigner/lib/resource_assigner.py index 640321d12068ea0c915b6bcfbfd6a790422e44fa..3f0b14b65145b3239a4e40ae04256145cc5b0719 100755 --- a/SAS/ResourceAssignment/ResourceAssigner/lib/resource_assigner.py +++ b/SAS/ResourceAssignment/ResourceAssigner/lib/resource_assigner.py @@ -221,8 +221,8 @@ class ResourceAssigner(object): task_id, task = self._insert_main_task(specification_tree, start_time, end_time, cluster_name) - self._link_predecessors_to_task(task) - self._link_successors_to_task(task) + self._link_predecessors_to_task_in_radb(task) + self._link_successors_to_task_in_radb(task) logger.info('Successfully inserted main task and its predecessors and successors into RADB: task=%s', task) @@ -445,7 +445,6 @@ class ResourceAssigner(object): return parset_start_time, parset_end_time - # TODO: add unit tests for this functionality def _get_duration_from_parset(_parset): """ Preferably use the duration specified by the parset. If that's not available, calculate the duration from @@ -687,7 +686,7 @@ class ResourceAssigner(object): # in line with failure as warning just above: allow going to scheduled state here too logger.error(str(e)) - def _link_predecessors_to_task(self, task): + def _link_predecessors_to_task_in_radb(self, task): """ Links a task to its predecessors in RADB @@ -721,7 +720,7 @@ class ResourceAssigner(object): logger.warning('could not find predecessor task with mom_id=%s in radb for task otdb_id=%s', predecessor_mom_id, task['otdb_id']) - def _link_successors_to_task(self, task): + def _link_successors_to_task_in_radb(self, task): """ Links a task to its successors in RADB diff --git a/SAS/ResourceAssignment/ResourceAssigner/test/t_resourceassigner.py b/SAS/ResourceAssignment/ResourceAssigner/test/t_resourceassigner.py index 3b19819b59c13d6e826948bd17a6028e44982a38..44f93c2fa7f70d66533484c2411bc23fe4bd7e12 100755 --- a/SAS/ResourceAssignment/ResourceAssigner/test/t_resourceassigner.py +++ b/SAS/ResourceAssignment/ResourceAssigner/test/t_resourceassigner.py @@ -26,6 +26,7 @@ import sys from lofar.sas.resourceassignment.resourceassigner.resource_assigner import ResourceAssigner from lofar.sas.resourceassignment.resourceassigner.resource_availability_checker import ResourceAvailabilityChecker from lofar.parameterset import parameterset +from lofar.common.datetimeutils import parseDatetime ra_notification_prefix = "ra_notification_prefix" @@ -1657,6 +1658,15 @@ class ResourceAssignerTest(unittest.TestCase): self.resource_assigner.do_assignment(self.non_approved_or_prescheduled_specification_tree['otdb_id'], self.non_approved_or_prescheduled_specification_tree) + def test_do_assignment_approved_task_should_not_be_rescheduled(self): + otdb_id = self.specification_tree['otdb_id'] + self.specification_tree['state'] = 'approved' + + self.resource_assigner.do_assignment(otdb_id, self.specification_tree) + + self.logger_mock.info.assert_any_call('Task otdb_id=%s is already approved, no resource assignment needed' % + otdb_id) + def test_do_assignment_inserts_specification_and_task_in_radb(self): self.resource_assigner.do_assignment(self.specification_tree['otdb_id'], self.specification_tree) @@ -1831,7 +1841,7 @@ class ResourceAssignerTest(unittest.TestCase): return datetime.datetime.strptime(now.strftime('%Y-%m-%d %H:%M:%S'), '%Y-%m-%d %H:%M:%S') @mock.patch('lofar.sas.resourceassignment.resourceassigner.resource_assigner.datetime') - def test_do_assignment_should_reset_observation_period_when_in_past(self, datetime_mock): + def test_do_assignment_pushes_back_observation_start_and_end_times_when_in_past(self, datetime_mock): now = datetime.datetime.utcnow() + datetime.timedelta(days=1) datetime_mock.utcnow.return_value = now @@ -1856,6 +1866,56 @@ class ResourceAssignerTest(unittest.TestCase): 'LOFAR.ObsSW.Observation.stopTime': new_endtime.strftime('%Y-%m-%d %H:%M:%S') }) + def test_get_main_task_start_and_end_times_with_unspecified_start_and_end_times(self): + """ + Verify that get_main_task_start_and_end_times() returns start/end times in the future with the default duration + """ + + self.specification_tree['specification']['Observation.startTime'] = None + self.specification_tree['specification']['Observation.stopTime'] = None + expected_duration = datetime.timedelta(hours=1) + + start_time, end_time = self.resource_assigner._get_main_task_start_and_end_times(self.specification_tree) + + duration = end_time - start_time + self.assertEqual(expected_duration, duration) + self.assertGreater(start_time, datetime.datetime.utcnow()) + + def test_get_main_task_start_and_end_times_with_unspecified_start_and_end_times_and_specified_duration(self): + """ + Verify that get_main_task_start_and_end_times() returns start/end times in the future with the specified + duration + """ + + self.specification_tree['specification']['Observation.startTime'] = None + self.specification_tree['specification']['Observation.stopTime'] = None + self.specification_tree['specification']['Observation.Scheduler.taskDuration'] = 300 # seconds + expected_duration = datetime.timedelta(seconds=300) + + start_time, end_time = self.resource_assigner._get_main_task_start_and_end_times(self.specification_tree) + + duration = end_time - start_time + self.assertEqual(expected_duration, duration) + self.assertGreater(start_time, datetime.datetime.utcnow()) + + def test_get_main_task_start_and_end_times_with_start_and_end_times_in_the_past(self): + """ + Verify that get_main_task_start_and_end_times() returns start/end times in the future but retains the original + duration. + """ + + specified_duration = datetime.timedelta(hours=5) + _start_time = datetime.datetime.utcnow() - datetime.timedelta(hours=7) + _end_time = _start_time + specified_duration + self.specification_tree['specification']['Observation.startTime'] = _start_time.strftime('%Y-%m-%d %H:%M:%S') + self.specification_tree['specification']['Observation.stopTime'] = _end_time.strftime('%Y-%m-%d %H:%M:%S') + + start_time, end_time = self.resource_assigner._get_main_task_start_and_end_times(self.specification_tree) + + duration = end_time - start_time + self.assertEqual(specified_duration, duration) + self.assertGreater(start_time, datetime.datetime.utcnow()) + def test_do_assignment_should_log_insertion_of_specification_and_task(self): self.resource_assigner.do_assignment(self.specification_tree['otdb_id'], self.specification_tree)