diff --git a/SAS/TMSS/src/tmss/tmssapp/migrations/0001_initial.py b/SAS/TMSS/src/tmss/tmssapp/migrations/0001_initial.py index 48c2c95468c4997e165fa571384ac559cae5309d..7a630f07320fc7a2fda98f04615255a7ed98dd3b 100644 --- a/SAS/TMSS/src/tmss/tmssapp/migrations/0001_initial.py +++ b/SAS/TMSS/src/tmss/tmssapp/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 3.0.9 on 2020-10-14 16:37 +# Generated by Django 3.0.9 on 2020-10-14 18:48 from django.conf import settings import django.contrib.postgres.fields @@ -1267,6 +1267,11 @@ class Migration(migrations.Migration): name='dataproduct', field=models.ForeignKey(help_text='A dataproduct residing in the archive.', on_delete=django.db.models.deletion.PROTECT, to='tmssapp.Dataproduct'), ), + migrations.AddField( + model_name='dataproduct', + name='SAP', + field=models.ForeignKey(help_text='SAP this dataproduct was generated out of (NULLable).', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='SAP_dataproducts', to='tmssapp.SAP'), + ), migrations.AddField( model_name='dataproduct', name='dataformat', diff --git a/SAS/TMSS/src/tmss/tmssapp/models/scheduling.py b/SAS/TMSS/src/tmss/tmssapp/models/scheduling.py index 8a65ffcce93882908ce82990ebeb8a56bb3a5ff2..0d9532f288902cfcd1fcc4345f6634f02e16f968 100644 --- a/SAS/TMSS/src/tmss/tmssapp/models/scheduling.py +++ b/SAS/TMSS/src/tmss/tmssapp/models/scheduling.py @@ -257,11 +257,13 @@ class SubtaskInput(BasicCommon): class SubtaskOutput(BasicCommon): subtask = ForeignKey('Subtask', null=False, on_delete=CASCADE, related_name='outputs', help_text='Subtask to which this output specification refers.') + class SAP(BasicCommon): - name = CharField(max_length=128, unique=True) # todo: we also have NamedCommon, which would make this PK. Confluence is a little ambiguous whether id or name... - specifications_doc = JSONField(help_text='SAP properties.') + name = CharField(max_length=128, unique=True) # todo: we also have NamedCommon, which would make this PK. Confluence is a little ambiguous whether id or name... + specifications_doc = JSONField(help_text='SAP properties.') specifications_template = ForeignKey('SAPTemplate', null=False, on_delete=CASCADE, help_text='Schema used for specifications_doc.') + class Dataproduct(BasicCommon): """ A data product represents an atomic dataset, produced and consumed by subtasks. The consumed dataproducts are those @@ -283,6 +285,7 @@ class Dataproduct(BasicCommon): size = BigIntegerField(null=True, help_text='Dataproduct size, in bytes. Used for accounting purposes. NULL if size is (yet) unknown (NULLable).') feedback_doc = JSONField(help_text='Dataproduct properties, as reported by the producing process.') feedback_template = ForeignKey('DataproductFeedbackTemplate', on_delete=PROTECT, help_text='Schema used for feedback_doc.') + SAP = ForeignKey('SAP', on_delete=PROTECT, null=True, related_name="SAP_dataproducts", help_text='SAP this dataproduct was generated out of (NULLable).') # todo: I find it odd to have this uppercase def save(self, force_insert=False, force_update=False, using=None, update_fields=None): annotate_validate_add_defaults_to_doc_using_template(self, 'specifications_doc', 'specifications_template') diff --git a/SAS/TMSS/test/t_tmssapp_scheduling_django_API.py b/SAS/TMSS/test/t_tmssapp_scheduling_django_API.py index ec2a1bb407b065247fa6a087618968ac0606bdfc..f5207337417bb58a4b825451ff3fe63437f9a9ea 100755 --- a/SAS/TMSS/test/t_tmssapp_scheduling_django_API.py +++ b/SAS/TMSS/test/t_tmssapp_scheduling_django_API.py @@ -472,6 +472,69 @@ class DataproductHashTest(unittest.TestCase): self.assertGreater(after, entry.updated_at) +class SAPTemplateTest(unittest.TestCase): + def test_SAPTemplate_gets_created_with_correct_creation_timestamp(self): + + # setup + before = datetime.utcnow() + entry = models.SAPTemplate.objects.create(**SAPTemplate_test_data()) + + after = datetime.utcnow() + + # assert + self.assertLess(before, entry.created_at) + self.assertGreater(after, entry.created_at) + + def test_SAPTemplate_update_timestamp_gets_changed_correctly(self): + + # setup + entry = models.SAPTemplate.objects.create(**SAPTemplate_test_data()) + before = datetime.utcnow() + entry.save() + after = datetime.utcnow() + + # assert + self.assertLess(before, entry.updated_at) + self.assertGreater(after, entry.updated_at) + + +class SAPTest(unittest.TestCase): + def test_SAP_gets_created_with_correct_creation_timestamp(self): + + # setup + before = datetime.utcnow() + entry = models.SAP.objects.create(**SAP_test_data()) + + after = datetime.utcnow() + + # assert + self.assertLess(before, entry.created_at) + self.assertGreater(after, entry.created_at) + + def test_SAP_update_timestamp_gets_changed_correctly(self): + + # setup + entry = models.SAP.objects.create(**SAP_test_data()) + before = datetime.utcnow() + entry.save() + after = datetime.utcnow() + + # assert + self.assertLess(before, entry.updated_at) + self.assertGreater(after, entry.updated_at) + + + def test_SAP_prevents_missing_specifications_template(self): + + # setup + test_data = dict(SAP_test_data()) + test_data['specifications_template'] = None + + # assert + with self.assertRaises(IntegrityError): + models.SAP.objects.create(**test_data) + + if __name__ == "__main__": os.environ['TZ'] = 'UTC' unittest.main() diff --git a/SAS/TMSS/test/tmss_test_data_django_models.py b/SAS/TMSS/test/tmss_test_data_django_models.py index 13fc9c26cb698e3bbb65b2f4152d276c20cb3b55..e171076c313a8d7171a5b5f847157022e9838f3e 100644 --- a/SAS/TMSS/test/tmss_test_data_django_models.py +++ b/SAS/TMSS/test/tmss_test_data_django_models.py @@ -466,3 +466,25 @@ def DataproductHash_test_data() -> dict: "algorithm": models.Algorithm.objects.get(value='md5'), "hash": "myhash_1", "tags": ['tmss', 'testing']} + + +def SAP_test_data(specifications_template=None, specifications_doc=None) -> dict: + + if specifications_template is None: + specifications_template = models.SAPTemplate.objects.create(**SAPTemplate_test_data()) + + if specifications_doc is None: + specifications_doc = get_default_json_object_for_schema(specifications_template.schema) + + return {"name": "my_sap" + str(uuid.uuid4()), + "specifications_doc": specifications_doc, + "specifications_template": specifications_template, + "tags": ['tmss', 'testing']} + + +def SAPTemplate_test_data() -> dict: + return {"name": "my_sap_template" + str(uuid.uuid4()), + "description": 'My SAP test template', + "schema": minimal_json_schema(), + "tags": ["TMSS", "TESTING"]} + diff --git a/SAS/TMSS/test/tmss_test_data_rest.py b/SAS/TMSS/test/tmss_test_data_rest.py index 76f23608e242dd7efed4380290729249c999c476..9b8c4c4c30fb082c6872d4e56863768322987878 100644 --- a/SAS/TMSS/test/tmss_test_data_rest.py +++ b/SAS/TMSS/test/tmss_test_data_rest.py @@ -534,7 +534,9 @@ class TMSSRESTTestDataCreator(): specifications_doc=None, specifications_template_url=None, subtask_output_url=None, dataproduct_feedback_doc=None, dataproduct_feedback_template_url=None, - dataformat="MeasurementSet", datatype="visibilities"): + dataformat="MeasurementSet", datatype="visibilities", + sap_url=None): + if specifications_template_url is None: specifications_template_url = self.post_data_and_get_url(self.SubtaskTemplate(), '/dataproduct_specifications_template/') @@ -550,6 +552,9 @@ class TMSSRESTTestDataCreator(): if dataproduct_feedback_doc is None: dataproduct_feedback_doc = self.get_response_as_json_object(dataproduct_feedback_template_url+'/default') + if sap_url is None: + sap_url = self.post_data_and_get_url(self.SAP(), '/sap/') + return {"filename": filename, "directory": directory, "dataformat": "%s/dataformat/%s" % (self.django_api_url, dataformat), @@ -564,7 +569,8 @@ class TMSSRESTTestDataCreator(): "expected_size": 1234, "size": 123, "feedback_doc": dataproduct_feedback_doc, - "feedback_template": dataproduct_feedback_template_url + "feedback_template": dataproduct_feedback_template_url, + "SAP": sap_url } def AntennaSet(self, name="antennaset1"): @@ -648,4 +654,22 @@ class TMSSRESTTestDataCreator(): "cluster": cluster_url, "directory": '/', "tags": ['tmss', 'testing']} - + + def SAPTemplate(self): + return {"name": "my_sap_template" + str(uuid.uuid4()), + "description": 'My SAP test template', + "schema": minimal_json_schema(), + "tags": ["TMSS", "TESTING"]} + + def SAP(self, specifications_template_url=None, specifications_doc=None): + + if specifications_template_url is None: + specifications_template_url = self.post_data_and_get_url(self.SAPTemplate(), '/sap_template/') + + if specifications_doc is None: + specifications_doc = self.get_response_as_json_object(specifications_template_url + '/default') + + return {"name": "my_sap" + str(uuid.uuid4()), + "specifications_doc": specifications_doc, + "specifications_template": specifications_template_url, + "tags": ['tmss', 'testing']} \ No newline at end of file