diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/models/common.py b/SAS/TMSS/backend/src/tmss/tmssapp/models/common.py index 58dcb85838219d685c516f3c1106ce28afefcb46..1c82ced88c993e3e6e9759e9913f6d150a586254 100644 --- a/SAS/TMSS/backend/src/tmss/tmssapp/models/common.py +++ b/SAS/TMSS/backend/src/tmss/tmssapp/models/common.py @@ -282,11 +282,13 @@ class AbstractSchemaTemplate(AbstractTemplate): # this template's schema has a schema of its own (usually the draft-06 meta schema). Validate it. validate_json_against_its_schema(self.schema) - def validate_document(self, json_doc: typing.Union[str, dict]): + def validate_document(self, json_doc: typing.Union[str, dict], raise_on_obsolete=True): '''validate the given json_doc against this template's schema and consistency/sanity rules If no exception is thrown, then the given json_doc validates. + Optionally raise when template is obsolete. This check should only happen when the document is basis for an + action in the system, but not when a (legacy) document is merely read. :raises ValidationException if the json_doc does not validate against this template's schema, or if some rule is violated, or the template is obsolete''' - if self.state.value == TemplateState.Choices.OBSOLETE.value: + if raise_on_obsolete and self.state.value == TemplateState.Choices.OBSOLETE.value: raise ObsoleteValidationException("Cannot validate document against obsolete template id=%s name='%s version='%s'" % (self.id, self.name, self.version)) self.validate_document_against_schema(json_doc) self.validate_document_against_rules(json_doc) diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/models/specification.py b/SAS/TMSS/backend/src/tmss/tmssapp/models/specification.py index 37bf9e1ec603caa899426c7584433cf28f068319..f459e5a59f597f83b4d84384f2bc916867f2023d 100644 --- a/SAS/TMSS/backend/src/tmss/tmssapp/models/specification.py +++ b/SAS/TMSS/backend/src/tmss/tmssapp/models/specification.py @@ -976,7 +976,7 @@ class SchedulingUnitDraft(NamedCommon, TemplateSchemaMixin, ProjectPropertyMixin specifications_doc['parameters'] = self.observation_strategy_template.template.get('parameters', []) # ensure that the generated specifications_doc is valid according to the schema (raises if not valid) - self.specifications_template.validate_document(specifications_doc) + self.specifications_template.validate_document(specifications_doc, raise_on_obsolete=False) return specifications_doc diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/tasks.py b/SAS/TMSS/backend/src/tmss/tmssapp/tasks.py index db34b0b84622506e6031eb36071390ab1fe37eb6..815ce11b7786cf04b25825a0c952a1861b1d0bea 100644 --- a/SAS/TMSS/backend/src/tmss/tmssapp/tasks.py +++ b/SAS/TMSS/backend/src/tmss/tmssapp/tasks.py @@ -83,8 +83,7 @@ def create_scheduling_unit_blueprint_from_scheduling_unit_draft(scheduling_unit_ """ try: # make sure the draft's speficifications_docs validate before we blueprint it - # just calling the specifications_doc property constructs a valid document, or raises - scheduling_unit_draft.specifications_doc + scheduling_unit_draft.specifications_template.validate_document(scheduling_unit_draft.specifications_doc, raise_on_obsolete=True) except ValidationException as e: logger.error("cannot create blueprint for scheduling_unit_draft id=%s name='%s': %s", scheduling_unit_draft.pk, scheduling_unit_draft.name, e) raise diff --git a/SAS/TMSS/backend/test/t_scheduling_units.py b/SAS/TMSS/backend/test/t_scheduling_units.py index 9de3fa4be9a183c92c716d1faa2c7a8cc2e16d23..dcc9389c715a58bc46797149fe6108461583cf4d 100644 --- a/SAS/TMSS/backend/test/t_scheduling_units.py +++ b/SAS/TMSS/backend/test/t_scheduling_units.py @@ -54,7 +54,7 @@ from lofar.sas.tmss.test.tmss_test_data_django_models import * rest_data_creator = tmss_test_env.create_test_data_creator() from lofar.sas.tmss.tmss.tmssapp import models -from lofar.sas.tmss.tmss.exceptions import SchemaValidationException, ObsoleteTemplateException, ValidationException +from lofar.sas.tmss.tmss.exceptions import SchemaValidationException, ObsoleteTemplateException, ValidationException, ObsoleteValidationException import requests @@ -462,6 +462,25 @@ class SchedulingUnitBlueprintStateTest(unittest.TestCase): self.assertEqual(sublueprint.on_sky_stop_time, on_sky_stop_time_before_cancel) + def test_can_access_specs_of_scheduling_unit_draft_with_obsolete_template_but_not_create_blueprint(self): # bugfix TMSS-1960 + # create draft and template + strategy_template = models.SchedulingUnitObservingStrategyTemplate.objects.create(name="test template", + state=models.TemplateState.objects.get(value=models.TemplateState.Choices.ACTIVE.value), + scheduling_unit_template=models.SchedulingUnitTemplate.get_latest("scheduling unit"), + template={}) + draft = create_scheduling_unit_draft_from_observing_strategy_template(strategy_template, scheduling_set=models.SchedulingSet.objects.create(**SchedulingSet_test_data())) + + # mark template obsolete + draft.specifications_template.state = models.TemplateState.objects.get(value=models.TemplateState.Choices.OBSOLETE.value) + draft.save() + + # access specs, which should not raise + self.assertIn("$schema", draft.specifications_doc) + + # make sure that we do get an exception when we try to create a blueprint from it + with self.assertRaises(ObsoleteValidationException) as context: + create_scheduling_unit_blueprint_from_scheduling_unit_draft(draft) + class TestFlatStations(unittest.TestCase): """ Test the property of 'flat_stations', retrieve a list of all station as a flat list