diff --git a/SAS/TMSS/src/remakemigrations.py b/SAS/TMSS/src/remakemigrations.py index a54c96c70a98b82362904b530e19b49285a7bad1..503432045e7905079d295a0faba956a987eaa66c 100755 --- a/SAS/TMSS/src/remakemigrations.py +++ b/SAS/TMSS/src/remakemigrations.py @@ -80,6 +80,7 @@ class Migration(migrations.Migration): migrations.RunPython(populate_misc), migrations.RunPython(populate_lofar_json_schemas), migrations.RunPython(populate_cycles), + migrations.RunPython(populate_resources), migrations.RunPython(populate_projects), migrations.RunPython(populate_test_scheduling_set) ] """ diff --git a/SAS/TMSS/src/tmss/tmssapp/migrations/0002_populate.py b/SAS/TMSS/src/tmss/tmssapp/migrations/0002_populate.py index 5f71d8b3e7997447b18548b528557232bc454362..b24c0bccf0ded89c957fa2c6c53c62dea7428c71 100644 --- a/SAS/TMSS/src/tmss/tmssapp/migrations/0002_populate.py +++ b/SAS/TMSS/src/tmss/tmssapp/migrations/0002_populate.py @@ -21,5 +21,6 @@ class Migration(migrations.Migration): migrations.RunPython(populate_misc), migrations.RunPython(populate_lofar_json_schemas), migrations.RunPython(populate_cycles), + migrations.RunPython(populate_resources), migrations.RunPython(populate_projects), migrations.RunPython(populate_test_scheduling_set) ] diff --git a/SAS/TMSS/src/tmss/tmssapp/models/specification.py b/SAS/TMSS/src/tmss/tmssapp/models/specification.py index ec60e4693dbec31d3049706b5490128b40840cff..854d5392c6fdf8915dd69f04ab20ffe3ef65f84a 100644 --- a/SAS/TMSS/src/tmss/tmssapp/models/specification.py +++ b/SAS/TMSS/src/tmss/tmssapp/models/specification.py @@ -286,6 +286,21 @@ class Project(NamedCommonPK): project_category = ForeignKey('ProjectCategory', null=True, on_delete=PROTECT, help_text='Project category.') period_category = ForeignKey('PeriodCategory', null=True, on_delete=PROTECT, help_text='Period category.') + # also create default project quotas when projects are created + def save(self, force_insert=False, force_update=False, using=None, update_fields=None): + creating = self._state.adding # True on create, False on update + super().save(force_insert, force_update, using, update_fields) + if creating: + # todo: review these defaults for being sensible + ProjectQuota.objects.create(resource_type=ResourceType.objects.get(name="lta_storage"), value=1024^4, project=self) + ProjectQuota.objects.create(resource_type=ResourceType.objects.get(name="cep_storage"), value=1024^4, project=self) + ProjectQuota.objects.create(resource_type=ResourceType.objects.get(name="cep_processing_time"), value=60*60*24, project=self) + ProjectQuota.objects.create(resource_type=ResourceType.objects.get(name="lofar_observing_time"), value=60*60*24, project=self) + ProjectQuota.objects.create(resource_type=ResourceType.objects.get(name="lofar_observing_time_prio_a"), value=60*60*12, project=self) + ProjectQuota.objects.create(resource_type=ResourceType.objects.get(name="lofar_observing_time_prio_b"), value=60*60*12, project=self) + ProjectQuota.objects.create(resource_type=ResourceType.objects.get(name="support_time"), value=60*60*6, project=self) + ProjectQuota.objects.create(resource_type=ResourceType.objects.get(name="number_of_triggers"), value=42, project=self) + class ProjectQuota(Model): project = ForeignKey('Project', related_name="project_quota", on_delete=PROTECT, help_text='Project to wich this quota belongs.') # protected to avoid accidents diff --git a/SAS/TMSS/src/tmss/tmssapp/populate.py b/SAS/TMSS/src/tmss/tmssapp/populate.py index 05ce47208c77dcb0c51d29046abc9d300c7dcc95..c8ea9780f7d44872d2ab7d3859bfa6e8568cb4f6 100644 --- a/SAS/TMSS/src/tmss/tmssapp/populate.py +++ b/SAS/TMSS/src/tmss/tmssapp/populate.py @@ -209,7 +209,12 @@ def populate_projects(apps, schema_editor): def populate_resources(apps, schema_editor): ResourceType.objects.create(name="lta_storage", description="Amount of storage in the LTA (in bytes)") ResourceType.objects.create(name="cep_storage", description="Amount of storage on the CEP processing cluster (in bytes)") - ResourceType.objects.create(name="cep_processing_hours", description="Processing time on the CEP processing cluster (in seconds)") + ResourceType.objects.create(name="cep_processing_time", description="Processing time on the CEP processing cluster (in seconds)") + ResourceType.objects.create(name="lofar_observing_time", description="Observing time (in seconds)") + ResourceType.objects.create(name="lofar_observing_time_prio_a", description="Observing time with priority A (in seconds)") + ResourceType.objects.create(name="lofar_observing_time_prio_b", description="Observing time with priority B (in seconds)") + ResourceType.objects.create(name="support_time", description="Support time by human (in seconds)") + ResourceType.objects.create(name="number_of_triggers", description="Number of trigger events (as integer)") def populate_misc(apps, schema_editor): diff --git a/SAS/TMSS/test/t_tmssapp_specification_REST_API.py b/SAS/TMSS/test/t_tmssapp_specification_REST_API.py index b55b2d4669438ae85fcca09021075d3d0c2e1dcf..d192f6486088fdf8d2860a7d90731150715b3b05 100755 --- a/SAS/TMSS/test/t_tmssapp_specification_REST_API.py +++ b/SAS/TMSS/test/t_tmssapp_specification_REST_API.py @@ -720,9 +720,11 @@ class ProjectTestCase(unittest.TestCase): project_test_data = test_data_creator.Project() # POST and GET a new item and assert correctness - r_dict = POST_and_assert_expected_response(self, BASE_URL + '/project/', project_test_data, 201, project_test_data) + expected = project_test_data.copy() + expected.pop('project_quota') # exclude project_quota from comparison, because these get auto-generated + r_dict = POST_and_assert_expected_response(self, BASE_URL + '/project/', project_test_data, 201, expected) url = r_dict['url'] - GET_OK_and_assert_equal_expected_response(self, url, project_test_data) + GET_OK_and_assert_equal_expected_response(self, url, expected) def test_project_PUT_invalid_raises_error(self): PUT_and_assert_expected_response(self, BASE_URL + '/project/9876789876/', test_data_creator.Project(), 404, {}) @@ -731,40 +733,52 @@ class ProjectTestCase(unittest.TestCase): project_test_data = test_data_creator.Project() # POST new item, verify - r_dict = POST_and_assert_expected_response(self, BASE_URL + '/project/', project_test_data, 201, project_test_data) + expected = project_test_data.copy() + expected.pop('project_quota') # exclude project_quota from comparison, because these get auto-generated + r_dict = POST_and_assert_expected_response(self, BASE_URL + '/project/', project_test_data, 201, expected) url = r_dict['url'] - GET_OK_and_assert_equal_expected_response(self, url, project_test_data) + GET_OK_and_assert_equal_expected_response(self, url, expected) # PUT new values, verify test_data = dict(test_data_creator.Project("other description")) test_data['name'] = project_test_data['name'] # since name is PK, need to keep that unchanged - PUT_and_assert_expected_response(self, url, test_data, 200, test_data) - GET_OK_and_assert_equal_expected_response(self, url, test_data) + expected = test_data.copy() + expected.pop('project_quota') # exclude project_quota from comparison, because these get auto-generated + PUT_and_assert_expected_response(self, url, test_data, 200, expected) + GET_OK_and_assert_equal_expected_response(self, url, expected) def test_project_PATCH(self): project_test_data = test_data_creator.Project() # POST new item, verify - r_dict = POST_and_assert_expected_response(self, BASE_URL + '/project/', project_test_data, 201, project_test_data) + expected = project_test_data.copy() + expected.pop('project_quota') # exclude project_quota from comparison, because these get auto-generated + r_dict = POST_and_assert_expected_response(self, BASE_URL + '/project/', project_test_data, 201, expected) url = r_dict['url'] - GET_OK_and_assert_equal_expected_response(self, url, project_test_data) + GET_OK_and_assert_equal_expected_response(self, url, expected) test_patch = {"priority_rank": 1.0, "tags": ["SUPERIMPORTANT"]} # PATCH item and verify PATCH_and_assert_expected_response(self, url, test_patch, 200, test_patch) - expected_data = dict(project_test_data) - expected_data.update(test_patch) - GET_OK_and_assert_equal_expected_response(self, url, expected_data) + expected.update(test_patch) + GET_OK_and_assert_equal_expected_response(self, url, expected) def test_project_DELETE(self): project_test_data = test_data_creator.Project() # POST new item, verify - r_dict = POST_and_assert_expected_response(self, BASE_URL + '/project/', project_test_data, 201, project_test_data) + expected = project_test_data.copy() + expected.pop('project_quota') # exclude project_quota from comparison, because these get auto-generated + r_dict = POST_and_assert_expected_response(self, BASE_URL + '/project/', project_test_data, 201, expected) url = r_dict['url'] - GET_OK_and_assert_equal_expected_response(self, url, project_test_data) + GET_OK_and_assert_equal_expected_response(self, url, expected) + + # DELETE related auto-generated project_quota first + project_quotas = r_dict['project_quota'] + for project_quota in project_quotas: + DELETE_and_assert_gone(self, project_quota) # DELETE and check it's gone DELETE_and_assert_gone(self, url) @@ -776,13 +790,15 @@ class ProjectTestCase(unittest.TestCase): cycle_url = POST_and_assert_expected_response(self, BASE_URL + '/cycle/', cycle_test_data, 201, cycle_test_data)['url'] test_data = dict(test_data_creator.Project()) test_data['cycles'] = [cycle_url] - url = POST_and_assert_expected_response(self, BASE_URL + '/project/', test_data, 201, test_data)['url'] + expected = test_data.copy() + expected.pop('project_quota') # exclude project_quota from comparison, because these get auto-generated + url = POST_and_assert_expected_response(self, BASE_URL + '/project/', test_data, 201, expected)['url'] # verify - GET_OK_and_assert_equal_expected_response(self, url, test_data) + GET_OK_and_assert_equal_expected_response(self, url, expected) # add project reference to cycle test data (we make Django add that to the cycle in serializer) - cycle_test_data['projects'] = [url] # add the + cycle_test_data['projects'] = [url] # Try to DELETE dependency, verify that was not successful # Unfortunately we don't get a nice error in json, but a Django debug page on error 500... @@ -907,7 +923,9 @@ class ProjectQuotaTestCase(unittest.TestCase): # POST new item with dependencies project_test_data = test_data_creator.Project() - project_url = POST_and_assert_expected_response(self, BASE_URL + '/project/', project_test_data, 201, project_test_data)['url'] + expected = project_test_data.copy() + expected.pop('project_quota') # exclude project_quota from comparison, because these get auto-generated + project_url = POST_and_assert_expected_response(self, BASE_URL + '/project/', project_test_data, 201, expected)['url'] project_quota_test_data = dict(test_data_creator.ProjectQuota(project_url=project_url)) project_quota_url = POST_and_assert_expected_response(self, BASE_URL + '/project_quota/', project_quota_test_data, 201, project_quota_test_data)['url'] @@ -1595,7 +1613,7 @@ class TaskRelationDraftTestCase(unittest.TestCase): # assert the returned list contains related items, A list of length 1 is retrieved GET_and_assert_in_expected_response_result_list(self, BASE_URL + '/task_draft/%s/task_relation_draft/' % task_draft_1.id, test_data_1, 1) # assert an existing related producer is returned - + class SchedulingUnitBlueprintTestCase(unittest.TestCase): @classmethod @@ -2335,7 +2353,7 @@ class TaskSchedulingRelationBlueprintTestCase(unittest.TestCase): # verify GET_OK_and_assert_equal_expected_response(self, url, tsrb_test_data) - #Get the URL of first task blueprint + #Get the URL of first task blueprint test_data = dict(tsrb_test_data) task_blueprint_url=test_data['first']