diff --git a/chord_metadata_service/authz/tests/helpers.py b/chord_metadata_service/authz/tests/helpers.py index ccb70d861..9ec625723 100644 --- a/chord_metadata_service/authz/tests/helpers.py +++ b/chord_metadata_service/authz/tests/helpers.py @@ -76,6 +76,17 @@ def one_no_authz_put(self, url: str, *args, **kwargs): """ return self._one_authz_put(False, url, *args, **kwargs) + def _one_authz_patch(self, authz_res: bool, url: str, *args, **kwargs): + with aioresponses() as m: + mock_authz_eval_one_result(m, authz_res) + return self.client.patch(url, *args, content_type="application/json", **kwargs) + + def one_authz_patch(self, url: str, *args, **kwargs): + """ + Mocks a single True response from the authorization service and executes a JSON PATCH request. + """ + return self._one_authz_patch(True, url, *args, **kwargs) + def _one_authz_delete(self, authz_res: bool, url: str, *args, **kwargs): with aioresponses() as m: mock_authz_eval_one_result(m, authz_res) diff --git a/chord_metadata_service/chord/api_views.py b/chord_metadata_service/chord/api_views.py index 16c3495dd..8038dce89 100644 --- a/chord_metadata_service/chord/api_views.py +++ b/chord_metadata_service/chord/api_views.py @@ -251,7 +251,7 @@ async def update(self, request, *args, **kwargs): return forbidden(request) # side effect: sets authz done flag # Do not allow datasets to change project - if request.data["project"] != dataset_project_id: + if "project" in request.data and request.data["project"] != dataset_project_id: return bad_request(request, "Dataset project ID cannot change") authz.mark_authz_done(request) diff --git a/chord_metadata_service/chord/tests/test_api.py b/chord_metadata_service/chord/tests/test_api.py index d5be94229..d50391001 100644 --- a/chord_metadata_service/chord/tests/test_api.py +++ b/chord_metadata_service/chord/tests/test_api.py @@ -236,9 +236,17 @@ def setUp(self): def test_update_dataset(self): r = self.one_authz_put(f"/api/datasets/{self.dataset.identifier}", data=json.dumps(self.valid_update)) - assert r.status_code == status.HTTP_200_OK + self.assertEqual(r.status_code, status.HTTP_200_OK) + self.dataset.refresh_from_db() + self.assertEqual(self.dataset.title, self.valid_update["title"]) + + def test_update_dataset_partial(self): + r = self.one_authz_patch( + f"/api/datasets/{self.dataset.identifier}", data=json.dumps({"title": self.valid_update["title"]}) + ) + self.assertEqual(r.status_code, status.HTTP_200_OK) self.dataset.refresh_from_db() - assert self.dataset.title == self.valid_update["title"] + self.assertEqual(self.dataset.title, self.valid_update["title"]) def test_update_dataset_changed_project(self): r = self.one_authz_put( @@ -248,50 +256,53 @@ def test_update_dataset_changed_project(self): "project": str(self.project_2.identifier), }) ) - assert r.status_code == status.HTTP_400_BAD_REQUEST + self.assertEqual(r.status_code, status.HTTP_400_BAD_REQUEST) res = r.json() - assert res["message"] == "Bad Request" - assert res["errors"][0]["message"] == "Dataset project ID cannot change" + self.assertEqual(res["message"], "Bad Request") + self.assertEqual(res["errors"][0]["message"], "Dataset project ID cannot change") def test_update_dataset_bad_dats_json(self): r = self.one_authz_put( f"/api/datasets/{self.dataset.identifier}", data=json.dumps({**self.valid_update, "dats_file": "asdf"}), # asdf is not JSON ) - assert r.status_code == status.HTTP_400_BAD_REQUEST + self.assertEqual(r.status_code, status.HTTP_400_BAD_REQUEST) res = r.json() - assert res["message"] == "Bad Request" - assert res["errors"][0]["message"] == ( - "Submitted dataset.dats_file data is not a valid JSON string. Make sure the string value is JSON " - "compatible, or submit dats_file as a JSON object." + self.assertEqual(res["message"], "Bad Request") + self.assertEqual( + res["errors"][0]["message"], + ( + "Submitted dataset.dats_file data is not a valid JSON string. Make sure the string value is JSON " + "compatible, or submit dats_file as a JSON object." + ) ) def test_update_dataset_forbidden(self): r = self.one_no_authz_put(f"/api/datasets/{self.dataset.identifier}", data=json.dumps(self.valid_update)) - assert r.status_code == status.HTTP_403_FORBIDDEN + self.assertEqual(r.status_code, status.HTTP_403_FORBIDDEN) def test_update_dataset_not_found(self): r = self.one_authz_put(f"/api/datasets/{uuid.uuid4()}", data=json.dumps(self.valid_update)) - assert r.status_code == status.HTTP_404_NOT_FOUND + self.assertEqual(r.status_code, status.HTTP_404_NOT_FOUND) class DeleteDatasetTest(AuthzAPITestCase, ProjectTestCase): def test_delete_dataset(self): r = self.one_authz_delete(f"/api/datasets/{self.dataset.identifier}") - assert r.status_code == status.HTTP_204_NO_CONTENT + self.assertEqual(r.status_code, status.HTTP_204_NO_CONTENT) with self.assertRaises(Dataset.DoesNotExist): # must not exist in DB anymore self.dataset.refresh_from_db() def test_delete_dataset_forbidden(self): r = self.one_no_authz_delete(f"/api/datasets/{self.dataset.identifier}") - assert r.status_code == status.HTTP_403_FORBIDDEN + self.assertEqual(r.status_code, status.HTTP_403_FORBIDDEN) self.dataset.refresh_from_db() # must not raise DoesNotExist def test_delete_dataset_not_found(self): r = self.client.delete(f"/api/datasets/{uuid.uuid4()}") - assert r.status_code == status.HTTP_404_NOT_FOUND + self.assertEqual(r.status_code, status.HTTP_404_NOT_FOUND) class CreateProjectJsonSchema(AuthzAPITestCaseWithProjectJSON):