Skip to content
Snippets Groups Projects
Commit 67d7543c authored by Roy de Goei's avatar Roy de Goei
Browse files

Merge branch 'TMSS-337' into 'master'

Resolve TMSS-337

Closes TMSS-337

See merge request !264
parents d0ab7097 0842b27f
No related branches found
No related tags found
2 merge requests!264Resolve TMSS-337,!260syncing cob-master with master again
......@@ -660,6 +660,21 @@ class SchedulingUnitBlueprint(NamedCommon):
else:
return None
@property
def observed_end_time(self) -> datetime or None:
"""
return the latest stop time of all (observation) tasks of this scheduling unit with the status observed/finished
"""
observed_tasks = []
for task in self.task_blueprints.all():
if task.specifications_template.type.value == TaskType.Choices.OBSERVATION.value and\
(task.status == "observed" or task.status == "finished") and task.stop_time is not None:
observed_tasks.append(task)
if observed_tasks:
return max(observed_tasks, key=lambda x: x.stop_time).stop_time
else:
return None
@property
def status(self):
"""
......@@ -800,14 +815,19 @@ class TaskDraft(NamedCommon):
'''
scheduling_relations = list(self.first_to_connect.all()) + list(self.second_to_connect.all())
for scheduling_relation in scheduling_relations:
if scheduling_relation.first.id == self._id and scheduling_relation.placement_id == "after":
# sometimes self._id does not exist so use self.id instead to avoid Exception
if hasattr(self, '_id'):
id = self._id
else:
id = self.id
if scheduling_relation.first.id == id and scheduling_relation.placement_id == "after":
previous_related_task_draft = TaskDraft.objects.get(id=scheduling_relation.second.id)
time_offset = scheduling_relation.time_offset
# todo: max of several relations
if previous_related_task_draft.relative_stop_time:
return previous_related_task_draft.relative_stop_time + datetime.timedelta(seconds=time_offset)
if scheduling_relation.second.id == self._id and scheduling_relation.placement_id == "before":
if scheduling_relation.second.id == id and scheduling_relation.placement_id == "before":
previous_related_task_draft = TaskDraft.objects.get(id=scheduling_relation.first.id)
time_offset = scheduling_relation.time_offset
# todo: max of several relations
......@@ -872,6 +892,7 @@ class TaskDraft(NamedCommon):
class TaskBlueprint(NamedCommon):
specifications_doc = JSONField(help_text='Schedulings for this task (IMMUTABLE).')
do_cancel = BooleanField(help_text='Cancel this task.')
specifications_template = ForeignKey('TaskTemplate', on_delete=CASCADE, help_text='Schema used for specifications_doc (IMMUTABLE).')
......@@ -917,20 +938,25 @@ class TaskBlueprint(NamedCommon):
'''
scheduling_relations = list(self.first_to_connect.all()) + list(self.second_to_connect.all())
for scheduling_relation in scheduling_relations:
if scheduling_relation.first.id == self._id and scheduling_relation.placement_id == "after": # self.id and placement.value will hit the db, this does not
# sometimes self._id does not exist so use self.id instead to avoid Exception
if hasattr(self, '_id'):
id = self._id
else:
id = self.id
if scheduling_relation.first.id == id and scheduling_relation.placement_id == "after": # self.id and placement.value will hit the db, this does not
previous_related_task_blueprint = TaskBlueprint.objects.get(id=scheduling_relation.second.id)
time_offset = scheduling_relation.time_offset
# todo: max of several relations
if previous_related_task_blueprint.relative_stop_time:
return previous_related_task_blueprint.relative_stop_time + datetime.timedelta(seconds=time_offset)
if scheduling_relation.second.id == self._id and scheduling_relation.placement_id == "before": # self.id and placement.value will hit the db, this does not
if scheduling_relation.second.id == id and scheduling_relation.placement_id == "before": # self.id and placement.value will hit the db, this does not
previous_related_task_blueprint = TaskBlueprint.objects.get(id=scheduling_relation.first.id)
time_offset = scheduling_relation.time_offset
# todo: max of several relations
if previous_related_task_blueprint.relative_stop_time:
return previous_related_task_blueprint.relative_stop_time + datetime.timedelta(seconds=time_offset)
return datetime.timedelta(seconds=666660)
return datetime.timedelta(seconds=0)
@cached_property
def relative_stop_time(self) -> datetime.timedelta:
......
......@@ -314,7 +314,7 @@ class SchedulingUnitBlueprintSerializer(RelationalHyperlinkedModelSerializer):
class Meta:
model = models.SchedulingUnitBlueprint
fields = '__all__'
extra_fields = ['task_blueprints', 'duration', 'start_time', 'stop_time', 'status']
extra_fields = ['task_blueprints', 'duration', 'start_time', 'stop_time', 'status', 'observed_end_time']
class SchedulingUnitBlueprintCopyToSchedulingUnitDraftSerializer(SchedulingUnitBlueprintSerializer):
class Meta(SchedulingUnitDraftSerializer.Meta):
......
......@@ -400,27 +400,37 @@ class SAPTest(unittest.TestCase):
self.assertEqual(dp2_in.sap, dp2_out.sap)
class CreationFromSchedulingUnitDraft(unittest.TestCase):
class TestWithUC1Specifications(unittest.TestCase):
"""
From scheduling_unit_draft test:
create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft: models.SchedulingUnitDraft) -> models.SchedulingUnitBlueprint:
This requires Resource Assigner testenvironment being alive
The Setup will create Scheduling Unit Draft with UC1 strategy template
It will use the function 'create_task_blueprints_and_subtasks_from_scheduling_unit_draft' which is then
implicit tested.
Create Task Blueprints and Subtasks:
Observation Task 'Calibration 1'
SubTask Observation Control
SubTask QA File
SubTask QA Plots
Pipeline Task 'Pipeline 1'
SubTask Pipeline Control
Observation Task 'Target Observation'
SubTask Observation Control
SubTask QA File
SubTask QA Plots
Pipeline Task 'Pipeline target1'
SubTask Pipeline Control
Pipeline Task 'Pipeline target2'
SubTask Pipeline Control
Observation Task 'Calibration 2'
SubTask Observation Control
SubTask QA File
SubTask QA Plots
Pipeline Task 'Pipeline 2'
SubTask Pipeline Control
Note that this test requires Resource Assigner testenvironment being alive
"""
def test_create_task_blueprints_and_subtasks_from_scheduling_unit_draft_with_UC1_requirements(self):
"""
Create Scheduling Unit Draft with requirements_doc (read from file)
Create Task Blueprints and Subtasks
Check if tasks (7) are created:
Calibration 1 : 1 Observation and 1 Pipeline task
Target Observation: 1 Observation and 2 Pipeline tasks
Calibration 2 : 1 Observation and 1 Pipeline task
Check if subtasks (13) are created:
Every Observation Task: 3 subtasks (1 control, 2 QA)
Every Pipeline Task: 1 subtasks (1 control)
makes 3x3 + 4x1 = 13
"""
@classmethod
def setUpClass(cls) -> None:
strategy_template = models.SchedulingUnitObservingStrategyTemplate.objects.get(name="UC1 CTC+pipelines")
scheduling_unit_draft = models.SchedulingUnitDraft.objects.create(
......@@ -436,20 +446,81 @@ class CreationFromSchedulingUnitDraft(unittest.TestCase):
create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft)
scheduling_unit_draft.refresh_from_db()
task_drafts = scheduling_unit_draft.task_drafts.all()
self.assertEqual(7, len(task_drafts))
scheduling_unit_blueprints = scheduling_unit_draft.scheduling_unit_blueprints.all()
self.assertEqual(1, len(scheduling_unit_blueprints))
cls.task_drafts = scheduling_unit_draft.task_drafts.all()
cls.scheduling_unit_blueprints = scheduling_unit_draft.scheduling_unit_blueprints.all()
cls.scheduling_unit_blueprint = cls.scheduling_unit_blueprints[0]
cls.task_blueprints = cls.scheduling_unit_blueprint.task_blueprints.all()
scheduling_unit_blueprint = scheduling_unit_blueprints[0]
task_blueprints = scheduling_unit_blueprint.task_blueprints.all()
self.assertEqual(7, len(task_blueprints))
def test_create_task_blueprints_and_subtasks_from_scheduling_unit_draft(self):
"""
Create Task Blueprints and Subtasks (class setup)
Check if tasks (7) are created:
Calibration 1 : 1 Observation and 1 Pipeline task
Target Observation: 1 Observation and 2 Pipeline tasks
Calibration 2 : 1 Observation and 1 Pipeline task
Check if subtasks (13) are created:
Every Observation Task: 3 subtasks (1 control, 2 QA)
Every Pipeline Task: 1 subtasks (1 control)
makes 3x3 + 4x1 = 13
"""
self.assertEqual(7, len(self.task_drafts))
self.assertEqual(1, len(self.scheduling_unit_blueprints))
self.assertEqual(7, len(self.task_blueprints))
total_subtasks = 0
for task_blueprint in task_blueprints:
for task_blueprint in self.task_blueprints:
total_subtasks += task_blueprint.subtasks.count()
self.assertEqual(13, total_subtasks)
def test_relative_times(self):
"""
Create Task Blueprints and Subtasks (class setup)
Set start and stop times of taskBlueprint
Set the subtask start/stop time equal to its taskBlueprint
Set all subtask states to 'finished'
Check the observed_end_time of the SchedulingUnitBlueprint
Check the relative_start/stop_time of the SchedulingUnitBlueprint
start = 0
stop = calculates like 8hours (Target) + 2x10min (calibrators) + 2*1min (offset between observations) = 8h22min
"""
DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S"
test_timeschedule = {
# name of taskBlueprint start_time stop_time
"Calibrator Observation 1": ["2020-11-01 08:00:00", "2020-11-01 08:10:00"],
"Pipeline 1": ["2020-11-01 08:20:00", "2020-11-01 08:22:00"],
"Target Observation": ["2020-11-01 08:30:00", "2020-11-01 18:00:00"],
"Pipeline target1": ["2020-11-01 18:30:00", "2020-11-01 18:35:00"],
"Pipeline target2": ["2020-11-01 18:40:00", "2020-11-01 18:45:00"],
"Calibrator Observation 2": ["2020-11-01 19:00:00", "2020-11-01 19:20:00"],
"Pipeline 2": ["2020-11-01 19:30:00", "2020-11-01 19:40:00"]
}
# Set time_schedule,
for name, times in test_timeschedule.items():
task_blueprint = list(filter(lambda x: x.name == name, self.task_blueprints))[0]
for subtask in task_blueprint.subtasks.all():
subtask.state = models.SubtaskState.objects.get(value="finished")
subtask.stop_time = datetime.strptime(times[1], DATETIME_FORMAT)
subtask.start_time = datetime.strptime(times[0], DATETIME_FORMAT)
subtask.save()
# Check times
self.assertEqual("2020-11-01 19:20:00", self.scheduling_unit_blueprint.observed_end_time.strftime("%Y-%m-%d %H:%M:%S"))
self.assertEqual(timedelta(0), self.scheduling_unit_blueprint.relative_start_time)
self.assertEqual(timedelta(hours=8, minutes=22), self.scheduling_unit_blueprint.relative_stop_time)
for task_blueprint in self.task_blueprints:
if task_blueprint.name == "Calibrator Observation 1":
self.assertEqual(timedelta(0), task_blueprint.relative_start_time)
self.assertEqual(timedelta(minutes=10), task_blueprint.relative_stop_time)
elif task_blueprint.name == "Target Observation":
self.assertEqual(timedelta(minutes=11), task_blueprint.relative_start_time)
self.assertEqual(timedelta(hours=8, minutes=11), task_blueprint.relative_stop_time)
elif task_blueprint.name == "Calibrator Observation 2":
self.assertEqual(timedelta(hours=8, minutes=12), task_blueprint.relative_start_time)
self.assertEqual(timedelta(hours=8, minutes=22), task_blueprint.relative_stop_time)
else:
self.assertEqual(timedelta(0), task_blueprint.relative_start_time)
self.assertEqual(timedelta(0), task_blueprint.relative_stop_time)
if __name__ == "__main__":
os.environ['TZ'] = 'UTC'
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment