From ccbfc7a0187258c2295101a47537a4756f0138c5 Mon Sep 17 00:00:00 2001 From: Joel Davies Date: Tue, 6 Aug 2024 14:16:09 +0000 Subject: [PATCH] Refactor some update tests #342 --- test/e2e/test_catalogue_category.py | 102 +- test/e2e/test_catalogue_item.py | 1373 +++++++++------------ test/e2e/test_manufacturer.py | 69 +- test/e2e/test_system.py | 78 +- test/unit/services/test_catalogue_item.py | 54 +- 5 files changed, 719 insertions(+), 957 deletions(-) diff --git a/test/e2e/test_catalogue_category.py b/test/e2e/test_catalogue_category.py index c81839ef..09c95212 100644 --- a/test/e2e/test_catalogue_category.py +++ b/test/e2e/test_catalogue_category.py @@ -42,7 +42,7 @@ class CreateDSL: test_client: TestClient - _post_response: Response + _post_response_catalogue_category: Response unit_value_id_dict: dict[str, str] @@ -89,9 +89,15 @@ def post_catalogue_category(self, catalogue_category_data: dict) -> Optional[str catalogue_category_data, self.unit_value_id_dict ) - self._post_response = self.test_client.post("/v1/catalogue-categories", json=catalogue_category_data) + self._post_response_catalogue_category = self.test_client.post( + "/v1/catalogue-categories", json=catalogue_category_data + ) - return self._post_response.json()["id"] if self._post_response.status_code == 201 else None + return ( + self._post_response_catalogue_category.json()["id"] + if self._post_response_catalogue_category.status_code == 201 + else None + ) def post_leaf_catalogue_category_with_allowed_values( self, property_type: str, allowed_values_post_data: dict @@ -128,8 +134,8 @@ def check_post_catalogue_category_success(self, expected_catalogue_category_get_ as would be required for a `CatalogueCategorySchema`. """ - assert self._post_response.status_code == 201 - assert self._post_response.json() == expected_catalogue_category_get_data + assert self._post_response_catalogue_category.status_code == 201 + assert self._post_response_catalogue_category.json() == expected_catalogue_category_get_data def check_post_catalogue_category_failed_with_detail(self, status_code: int, detail: str) -> None: """ @@ -140,8 +146,8 @@ def check_post_catalogue_category_failed_with_detail(self, status_code: int, det :param detail: Expected detail given in the response. """ - assert self._post_response.status_code == status_code - assert self._post_response.json()["detail"] == detail + assert self._post_response_catalogue_category.status_code == status_code + assert self._post_response_catalogue_category.json()["detail"] == detail def check_post_catalogue_category_failed_with_validation_message(self, status_code: int, message: str) -> None: """ @@ -152,8 +158,8 @@ def check_post_catalogue_category_failed_with_validation_message(self, status_co :param message: Expected validation error message given in the response. """ - assert self._post_response.status_code == status_code - assert self._post_response.json()["detail"][0]["msg"] == message + assert self._post_response_catalogue_category.status_code == status_code + assert self._post_response_catalogue_category.json()["detail"][0]["msg"] == message class TestCreate(CreateDSL): @@ -379,7 +385,7 @@ def test_create_leaf_with_boolean_property_with_allowed_values_list(self): class GetDSL(CreateDSL): """Base class for get tests.""" - _get_response: Response + _get_response_catalogue_category: Response def get_catalogue_category(self, catalogue_category_id: str) -> None: """ @@ -388,7 +394,9 @@ def get_catalogue_category(self, catalogue_category_id: str) -> None: :param catalogue_category_id: ID of the catalogue category to be obtained. """ - self._get_response = self.test_client.get(f"/v1/catalogue-categories/{catalogue_category_id}") + self._get_response_catalogue_category = self.test_client.get( + f"/v1/catalogue-categories/{catalogue_category_id}" + ) def check_get_catalogue_category_success(self, expected_catalogue_category_get_data: dict) -> None: """ @@ -398,8 +406,8 @@ def check_get_catalogue_category_success(self, expected_catalogue_category_get_d be required for a `CatalogueCategorySchema`. """ - assert self._get_response.status_code == 200 - assert self._get_response.json() == expected_catalogue_category_get_data + assert self._get_response_catalogue_category.status_code == 200 + assert self._get_response_catalogue_category.json() == expected_catalogue_category_get_data def check_get_catalogue_category_failed_with_detail(self, status_code: int, detail: str) -> None: """ @@ -410,8 +418,8 @@ def check_get_catalogue_category_failed_with_detail(self, status_code: int, deta :param detail: Expected detail given in the response. """ - assert self._get_response.status_code == status_code - assert self._get_response.json()["detail"] == detail + assert self._get_response_catalogue_category.status_code == status_code + assert self._get_response_catalogue_category.json()["detail"] == detail class TestGet(GetDSL): @@ -441,7 +449,7 @@ def test_get_with_invalid_id(self): class GetBreadcrumbsDSL(GetDSL): """Base class for breadcrumbs tests.""" - _get_response: Response + _get_response_catalogue_category: Response _posted_catalogue_categories_get_data: list[dict] @@ -468,7 +476,7 @@ def post_nested_catalogue_categories(self, number: int) -> list[Optional[str]]: "parent_id": parent_id, } ) - self._posted_catalogue_categories_get_data.append(self._post_response.json()) + self._posted_catalogue_categories_get_data.append(self._post_response_catalogue_category.json()) parent_id = catalogue_category_id return [catalogue_category["id"] for catalogue_category in self._posted_catalogue_categories_get_data] @@ -480,12 +488,14 @@ def get_catalogue_category_breadcrumbs(self, catalogue_category_id: str) -> None :param catalogue_category_id: ID of the catalogue category to obtain the breadcrumbs of. """ - self._get_response = self.test_client.get(f"/v1/catalogue-categories/{catalogue_category_id}/breadcrumbs") + self._get_response_catalogue_category = self.test_client.get( + f"/v1/catalogue-categories/{catalogue_category_id}/breadcrumbs" + ) def get_last_catalogue_category_breadcrumbs(self) -> None: """Gets the last catalogue category posted's breadcrumbs.""" - self.get_catalogue_category_breadcrumbs(self._post_response.json()["id"]) + self.get_catalogue_category_breadcrumbs(self._post_response_catalogue_category.json()["id"]) def check_get_catalogue_categories_breadcrumbs_success( self, expected_trail_length: int, expected_full_trail: bool @@ -498,8 +508,8 @@ def check_get_catalogue_categories_breadcrumbs_success( :param expected_full_trail: Whether the expected trail is a full trail or not. """ - assert self._get_response.status_code == 200 - assert self._get_response.json() == { + assert self._get_response_catalogue_category.status_code == 200 + assert self._get_response_catalogue_category.json() == { "trail": [ [catalogue_category["id"], catalogue_category["name"]] # When the expected trail length is < the number of systems posted, only use the last @@ -518,8 +528,8 @@ def check_get_catalogue_categories_breadcrumbs_failed_with_detail(self, status_c :param detail: Expected detail given in the response. """ - assert self._get_response.status_code == status_code - assert self._get_response.json()["detail"] == detail + assert self._get_response_catalogue_category.status_code == status_code + assert self._get_response_catalogue_category.json()["detail"] == detail class TestGetBreadcrumbs(GetBreadcrumbsDSL): @@ -584,7 +594,7 @@ def get_catalogue_categories(self, filters: dict) -> None: :param filters: Filters to use in the request. """ - self._get_response = self.test_client.get("/v1/catalogue-categories", params=filters) + self._get_response_catalogue_category = self.test_client.get("/v1/catalogue-categories", params=filters) def post_test_catalogue_category_with_child(self) -> list[dict]: """ @@ -614,8 +624,8 @@ def check_get_catalogue_categories_success(self, expected_catalogue_categories_g returned as would be required for `CatalogueCategorySchema`'s. """ - assert self._get_response.status_code == 200 - assert self._get_response.json() == expected_catalogue_categories_get_data + assert self._get_response_catalogue_category.status_code == 200 + assert self._get_response_catalogue_category.json() == expected_catalogue_categories_get_data class TestList(ListDSL): @@ -674,7 +684,7 @@ def test_list_with_invalid_parent_id_filter(self): class UpdateDSL(ListDSL): """Base class for update tests.""" - _patch_response: Response + _patch_response_catalogue_category: Response def patch_catalogue_category(self, catalogue_category_id: str, catalogue_category_update_data: dict) -> None: """ @@ -691,7 +701,7 @@ def patch_catalogue_category(self, catalogue_category_id: str, catalogue_categor catalogue_category_update_data, self.unit_value_id_dict ) - self._patch_response = self.test_client.patch( + self._patch_response_catalogue_category = self.test_client.patch( f"/v1/catalogue-categories/{catalogue_category_id}", json=catalogue_category_update_data ) @@ -701,13 +711,13 @@ def post_child_catalogue_category(self) -> None: # pylint:disable=fixme # TODO: Could change post_catalogue_category logic and use post_catalogue_category - right now a test like # test_partial_update_non_leaf_all_valid_values_when_has_child_catalogue_category wont work with that as it - # will assert the created times based on the last _post_response which will be the child so have to bypass here + # will assert the created times based on the last _post_response_catalogue_category which will be the child so have to bypass here # currently - may not be necessary if have custom test client instead & should be clearer after items self.test_client.post( "/v1/catalogue-categories", json={ **CATALOGUE_CATEGORY_POST_DATA_NON_LEAF_NO_PARENT_NO_PROPERTIES_B, - "parent_id": self._post_response.json()["id"], + "parent_id": self._post_response_catalogue_category.json()["id"], }, ) @@ -723,7 +733,7 @@ def post_child_catalogue_item(self) -> None: catalogue_item_post = { **CATALOGUE_ITEM_DATA_REQUIRED_VALUES_ONLY, - "catalogue_category_id": self._post_response.json()["id"], + "catalogue_category_id": self._post_response_catalogue_category.json()["id"], "manufacturer_id": manufacturer_id, } self.test_client.post("/v1/catalogue-items", json=catalogue_item_post) @@ -741,7 +751,7 @@ def patch_properties_with_property_with_allowed_values( """ self.patch_catalogue_category( - self._post_response.json()["id"], + self._post_response_catalogue_category.json()["id"], { "properties": [ { @@ -763,10 +773,12 @@ def check_patch_catalogue_category_response_success(self, expected_catalogue_cat be required for a `CatalogueCategorySchema`. """ - assert self._patch_response.status_code == 200 - assert self._patch_response.json() == expected_catalogue_category_get_data + assert self._patch_response_catalogue_category.status_code == 200 + assert self._patch_response_catalogue_category.json() == expected_catalogue_category_get_data - E2ETestHelpers.check_created_and_modified_times_updated_correctly(self._post_response, self._patch_response) + E2ETestHelpers.check_created_and_modified_times_updated_correctly( + self._post_response_catalogue_category, self._patch_response_catalogue_category + ) def check_patch_catalogue_category_failed_with_detail(self, status_code: int, detail: str) -> None: """ @@ -777,8 +789,8 @@ def check_patch_catalogue_category_failed_with_detail(self, status_code: int, de :param detail: Expected detail given in the response. """ - assert self._patch_response.status_code == status_code - assert self._patch_response.json()["detail"] == detail + assert self._patch_response_catalogue_category.status_code == status_code + assert self._patch_response_catalogue_category.json()["detail"] == detail def check_patch_catalogue_category_failed_with_validation_message(self, status_code: int, message: str) -> None: """ @@ -789,8 +801,8 @@ def check_patch_catalogue_category_failed_with_validation_message(self, status_c :param message: Expected validation error message given in the response. """ - assert self._patch_response.status_code == status_code - assert self._patch_response.json()["detail"][0]["msg"] == message + assert self._patch_response_catalogue_category.status_code == status_code + assert self._patch_response_catalogue_category.json()["detail"][0]["msg"] == message class TestUpdate(UpdateDSL): @@ -1245,7 +1257,7 @@ def test_partial_update_invalid_id(self): class DeleteDSL(UpdateDSL): """Base class for delete tests.""" - _delete_response: Response + _delete_response_catalogue_category: Response def delete_catalogue_category(self, catalogue_category_id: str) -> None: """ @@ -1254,13 +1266,15 @@ def delete_catalogue_category(self, catalogue_category_id: str) -> None: :param catalogue_category_id: ID of the catalogue category to be deleted. """ - self._delete_response = self.test_client.delete(f"/v1/catalogue-categories/{catalogue_category_id}") + self._delete_response_catalogue_category = self.test_client.delete( + f"/v1/catalogue-categories/{catalogue_category_id}" + ) def check_delete_catalogue_category_success(self) -> None: """Checks that a prior call to `delete_catalogue_category` gave a successful response with the expected data returned.""" - assert self._delete_response.status_code == 204 + assert self._delete_response_catalogue_category.status_code == 204 def check_delete_catalogue_category_failed_with_detail(self, status_code: int, detail: str) -> None: """ @@ -1271,8 +1285,8 @@ def check_delete_catalogue_category_failed_with_detail(self, status_code: int, d :param detail: Expected detail given in the response. """ - assert self._delete_response.status_code == status_code - assert self._delete_response.json()["detail"] == detail + assert self._delete_response_catalogue_category.status_code == status_code + assert self._delete_response_catalogue_category.json()["detail"] == detail class TestDelete(DeleteDSL): diff --git a/test/e2e/test_catalogue_item.py b/test/e2e/test_catalogue_item.py index c2010a02..58951cf9 100644 --- a/test/e2e/test_catalogue_item.py +++ b/test/e2e/test_catalogue_item.py @@ -25,6 +25,7 @@ from test.mock_data import ( BASE_CATALOGUE_CATEGORY_WITH_PROPERTIES, CATALOGUE_CATEGORY_POST_DATA_LEAF_NO_PARENT_NO_PROPERTIES, + CATALOGUE_CATEGORY_POST_DATA_LEAF_REQUIRED_VALUES_ONLY, CATALOGUE_CATEGORY_POST_DATA_NON_LEAF_REQUIRED_VALUES_ONLY, CATALOGUE_CATEGORY_PROPERTY_DATA_BOOLEAN_MANDATORY, CATALOGUE_CATEGORY_PROPERTY_DATA_NUMBER_NON_MANDATORY_WITH_MM_UNIT, @@ -39,10 +40,13 @@ CATALOGUE_ITEM_GET_DATA_REQUIRED_VALUES_ONLY, CATALOGUE_ITEM_GET_DATA_WITH_ALL_PROPERTIES, CATALOGUE_ITEM_GET_DATA_WITH_MANDATORY_PROPERTIES_ONLY, + MANUFACTURER_POST_DATA_ALL_VALUES, MANUFACTURER_POST_DATA_REQUIRED_VALUES_ONLY, PROPERTY_DATA_BOOLEAN_MANDATORY_TRUE, + PROPERTY_DATA_NUMBER_NON_MANDATORY_42, PROPERTY_DATA_NUMBER_NON_MANDATORY_NONE, PROPERTY_DATA_STRING_NON_MANDATORY_WITH_ALLOWED_VALUES_LIST_NONE, + PROPERTY_GET_DATA_NUMBER_NON_MANDATORY_42, UNIT_POST_DATA_MM, ) from typing import Any, Optional @@ -61,6 +65,8 @@ class CreateDSL(CatalogueCategoryCreateDSL, ManufacturerCreateDSL): manufacturer_id: Optional[str] property_name_id_dict: dict[str, str] + _post_response_catalogue_item: Response + # Key of property name, and value a dictionary containing the `unit` and `unit_id` as would # be expected inside a property response _unit_data_lookup_dict: dict[str, dict] @@ -70,6 +76,7 @@ def setup_catalogue_item_create_dsl(self): """Setup fixtures""" self.property_name_id_dict = {} + # TODO: Look up from response instead of storing/overriding? self.catalogue_category_id = None self.manufacturer_id = None @@ -90,7 +97,7 @@ def add_ids_to_expected_catalogue_item_get_data(self, expected_catalogue_item_ge properties = [] for prop in expected_catalogue_item_get_data["properties"]: properties.append({**prop, **self._unit_data_lookup_dict[prop["id"]]}) - expected_catalogue_item_get_data["properties"] = properties + expected_catalogue_item_get_data = {**expected_catalogue_item_get_data, "properties": properties} return { **expected_catalogue_item_get_data, @@ -113,7 +120,7 @@ def post_catalogue_category(self, catalogue_category_data: dict) -> Optional[str # Assign the property name id dict for any properties if self.catalogue_category_id: self.property_name_id_dict = {} - catalogue_category_data = self._post_response.json() + catalogue_category_data = self._post_response_catalogue_category.json() for prop in catalogue_category_data["properties"]: self.property_name_id_dict[prop["name"]] = prop["id"] self._unit_data_lookup_dict[prop["id"]] = {"unit_id": prop["unit_id"], "unit": prop["unit"]} @@ -144,22 +151,27 @@ def post_catalogue_item(self, catalogue_item_data: dict) -> Optional[str]: """ # Replace any unit values with unit IDs - catalogue_item_data = E2ETestHelpers.replace_unit_values_with_ids_in_properties( - catalogue_item_data, self.unit_value_id_dict + full_catalogue_item_data = catalogue_item_data.copy() + full_catalogue_item_data = E2ETestHelpers.replace_unit_values_with_ids_in_properties( + full_catalogue_item_data, self.unit_value_id_dict ) - catalogue_item_data = E2ETestHelpers.replace_property_names_with_ids_in_properties( - catalogue_item_data, self.property_name_id_dict + full_catalogue_item_data = E2ETestHelpers.replace_property_names_with_ids_in_properties( + full_catalogue_item_data, self.property_name_id_dict ) # Insert mandatory IDs if they have been created if self.catalogue_category_id: - catalogue_item_data["catalogue_category_id"] = self.catalogue_category_id + full_catalogue_item_data["catalogue_category_id"] = self.catalogue_category_id if self.manufacturer_id: - catalogue_item_data["manufacturer_id"] = self.manufacturer_id + full_catalogue_item_data["manufacturer_id"] = self.manufacturer_id - self._post_response = self.test_client.post("/v1/catalogue-items", json=catalogue_item_data) + self._post_response_catalogue_item = self.test_client.post("/v1/catalogue-items", json=full_catalogue_item_data) - return self._post_response.json()["id"] if self._post_response.status_code == 201 else None + return ( + self._post_response_catalogue_item.json()["id"] + if self._post_response_catalogue_item.status_code == 201 + else None + ) def post_catalogue_item_and_prerequisites_with_allowed_values( self, property_type: str, allowed_values_post_data: dict, property_value: Any @@ -207,8 +219,8 @@ def check_post_catalogue_item_success(self, expected_catalogue_item_get_data: di expected. """ - assert self._post_response.status_code == 201 - assert self._post_response.json() == self.add_ids_to_expected_catalogue_item_get_data( + assert self._post_response_catalogue_item.status_code == 201 + assert self._post_response_catalogue_item.json() == self.add_ids_to_expected_catalogue_item_get_data( expected_catalogue_item_get_data ) @@ -221,8 +233,8 @@ def check_post_catalogue_item_failed_with_detail(self, status_code: int, detail: :param detail: Expected detail given in the response. """ - assert self._post_response.status_code == status_code - assert self._post_response.json()["detail"] == detail + assert self._post_response_catalogue_item.status_code == status_code + assert self._post_response_catalogue_item.json()["detail"] == detail def check_post_catalogue_item_failed_with_validation_message(self, status_code: int, message: str) -> None: """ @@ -233,8 +245,8 @@ def check_post_catalogue_item_failed_with_validation_message(self, status_code: :param message: Expected validation error message given in the response. """ - assert self._post_response.status_code == status_code - assert self._post_response.json()["detail"][0]["msg"] == message + assert self._post_response_catalogue_item.status_code == status_code + assert self._post_response_catalogue_item.json()["detail"][0]["msg"] == message class TestCreate(CreateDSL): @@ -372,7 +384,7 @@ def test_create_with_non_mandatory_properties_given_none(self): # TODO: Have a post for base catalogue category with properties/manufacturer or something to reduce lines # repeated self.post_unit(UNIT_POST_DATA_MM) - # TODO: Should BASE_CATALOGUE_CATEGORY_WITH_PROPERTIES have _MM? + # TODO: Should BASE_CATALOGUE_CATEGORY_WITH_PROPERTIES have _MM? at least _DATA? self.post_catalogue_category(BASE_CATALOGUE_CATEGORY_WITH_PROPERTIES) self.post_manufacturer(MANUFACTURER_POST_DATA_REQUIRED_VALUES_ONLY) self.post_catalogue_item( @@ -726,15 +738,30 @@ def test_list_with_invalid_catalogue_category_id_filter(self): # TODO: Update tests +class UpdateDSL(ListDSL): + """Base class for update tests.""" + _patch_response_catalogue_item: Response -# TODO: Inherit from UpdateDSL -class DeleteDSL(ListDSL): - """Base class for delete tests.""" + def patch_catalogue_item(self, catalogue_item_id: str, catalogue_item_update_data: dict) -> None: + """ + Updates a catalogue item with the given ID. + + :param catalogue_item_id: ID of the catalogue category to patch. + :param catalogue_item_update_data: Dictionary containing the basic patch data as would be required for a + `CatalogueItemPatchSchema` but with any `id`'s replaced by the `name` value + in its properties as the IDs will be added automatically. + """ + + # Replace any unit values with unit ids + catalogue_item_update_data = E2ETestHelpers.replace_property_names_with_ids_in_properties( + catalogue_item_update_data, self.property_name_id_dict + ) - _delete_response: Response + self._patch_response_catalogue_item = self.test_client.patch( + f"/v1/catalogue-items/{catalogue_item_id}", json=catalogue_item_update_data + ) - # TODO: Move into UpdateDSL? (like post_child_item in catalogue category tests - depends if needed there or not) def post_child_item(self) -> None: """Utility method that posts a child item for the last catalogue item posted.""" @@ -753,731 +780,655 @@ def post_child_item(self) -> None: "serial_number": "xyz123", "delivered_date": "2012-12-05T12:00:00Z", "notes": "Test notes", - "catalogue_item_id": self._post_response.json()["id"], + "catalogue_item_id": self._post_response_catalogue_item.json()["id"], "system_id": system_id, "usage_status_id": usage_status_id, "properties": [], } self.test_client.post("/v1/items", json=item_post) - def delete_catalogue_item(self, catalogue_item_id: str) -> None: + def check_patch_catalogue_item_response_success(self, expected_catalogue_item_get_data: dict) -> None: """ - Deletes a catalogue item with the given ID. + Checks that a prior call to `patch_catalogue_item` gave a successful response with the expected data + returned. - :param catalogue_item_id: ID of the catalogue item to be deleted. + :param expected_catalogue_item_get_data: Dictionary containing the expected system data returned as would + be required for a `CatalogueItemSchema`. Does not need mandatory IDs + (e.g. manufacturer_id) as they will be added automatically to check + they are as expected. """ - self._delete_response = self.test_client.delete(f"/v1/catalogue-items/{catalogue_item_id}") - - def check_delete_catalogue_item_success(self) -> None: - """Checks that a prior call to `delete_catalogue_item` gave a successful response with the expected data - returned.""" + assert self._patch_response_catalogue_item.status_code == 200 + assert self._patch_response_catalogue_item.json() == self.add_ids_to_expected_catalogue_item_get_data( + expected_catalogue_item_get_data + ) - assert self._delete_response.status_code == 204 + E2ETestHelpers.check_created_and_modified_times_updated_correctly( + self._post_response_catalogue_item, self._patch_response_catalogue_item + ) - def check_delete_catalogue_item_failed_with_detail(self, status_code: int, detail: str) -> None: + def check_patch_catalogue_item_failed_with_detail(self, status_code: int, detail: str) -> None: """ - Checks that a prior call to `delete_catalogue_item` gave a failed response with the expected code and + Checks that a prior call to `patch_catalogue_item` gave a failed response with the expected code and error message. :param status_code: Expected status code of the response. :param detail: Expected detail given in the response. """ - assert self._delete_response.status_code == status_code - assert self._delete_response.json()["detail"] == detail + assert self._patch_response_catalogue_item.status_code == status_code + assert self._patch_response_catalogue_item.json()["detail"] == detail + + def check_patch_catalogue_item_failed_with_validation_message(self, status_code: int, message: str) -> None: + """ + Checks that a prior call to `patch_catalogue_item` gave a failed response with the expected code and + pydantic validation error message. + :param status_code: Expected status code of the response. + :param message: Expected validation error message given in the response. + """ -class TestDelete(DeleteDSL): - """Tests for deleting a catalogue item.""" + assert self._patch_response_catalogue_item.status_code == status_code + assert self._patch_response_catalogue_item.json()["detail"][0]["msg"] == message - def test_delete(self): - """Test deleting a catalogue item.""" + +class TestUpdate(UpdateDSL): + """Tests for updating a catalogue item.""" + + def test_partial_update_all_fields_except_ids_or_properties_with_no_children(self): + """Test updating all fields of a catalogue item except its any of its `_id` fields or properties when it has + no children.""" self.post_catalogue_category(CATALOGUE_CATEGORY_POST_DATA_LEAF_NO_PARENT_NO_PROPERTIES) self.post_manufacturer(MANUFACTURER_POST_DATA_REQUIRED_VALUES_ONLY) catalogue_item_id = self.post_catalogue_item(CATALOGUE_ITEM_DATA_REQUIRED_VALUES_ONLY) - self.delete_catalogue_item(catalogue_item_id) - self.check_delete_catalogue_item_success() - - self.get_catalogue_item(catalogue_item_id) - self.check_get_catalogue_item_failed_with_detail(404, "Catalogue item not found") + self.patch_catalogue_item(catalogue_item_id, CATALOGUE_ITEM_DATA_NOT_OBSOLETE_NO_PROPERTIES) + self.check_patch_catalogue_item_response_success(CATALOGUE_ITEM_GET_DATA_NOT_OBSOLETE_NO_PROPERTIES) - def test_delete_with_child_item(self): - """Test deleting a catalogue category with a child catalogue item.""" + def test_partial_update_all_fields_except_ids_or_properties_with_children(self): + """Test updating all fields of a catalogue item except its any of its `_id` fields or properties when it has + children.""" self.post_catalogue_category(CATALOGUE_CATEGORY_POST_DATA_LEAF_NO_PARENT_NO_PROPERTIES) self.post_manufacturer(MANUFACTURER_POST_DATA_REQUIRED_VALUES_ONLY) catalogue_item_id = self.post_catalogue_item(CATALOGUE_ITEM_DATA_REQUIRED_VALUES_ONLY) self.post_child_item() - self.delete_catalogue_item(catalogue_item_id) - self.check_delete_catalogue_item_failed_with_detail( - 409, "Catalogue item has child elements and cannot be deleted" - ) + self.patch_catalogue_item(catalogue_item_id, CATALOGUE_ITEM_DATA_NOT_OBSOLETE_NO_PROPERTIES) + self.check_patch_catalogue_item_response_success(CATALOGUE_ITEM_GET_DATA_NOT_OBSOLETE_NO_PROPERTIES) - def test_delete_with_non_existent_id(self): - """Test deleting a non-existent catalogue item.""" + # TODO: More update tests - self.delete_catalogue_item(str(ObjectId())) - self.check_delete_catalogue_item_failed_with_detail(404, "Catalogue item not found") + def test_partial_update_catalogue_category_id_no_properties(self): + """Test updating the `catalogue_category_id` of a catalogue item when no properties are involved.""" - def test_delete_with_invalid_id(self): - """Test deleting a catalogue item with an invalid ID.""" + self.post_catalogue_category(CATALOGUE_CATEGORY_POST_DATA_LEAF_NO_PARENT_NO_PROPERTIES) + self.post_manufacturer(MANUFACTURER_POST_DATA_REQUIRED_VALUES_ONLY) + catalogue_item_id = self.post_catalogue_item(CATALOGUE_ITEM_DATA_REQUIRED_VALUES_ONLY) + new_catalogue_category_id = self.post_catalogue_category(CATALOGUE_CATEGORY_POST_DATA_LEAF_REQUIRED_VALUES_ONLY) - self.delete_catalogue_item("invalid_id") - self.check_delete_catalogue_item_failed_with_detail(404, "Catalogue item not found") + self.patch_catalogue_item(catalogue_item_id, {"catalogue_category_id": new_catalogue_category_id}) + self.check_patch_catalogue_item_response_success(CATALOGUE_ITEM_GET_DATA_REQUIRED_VALUES_ONLY) + def test_partial_update_catalogue_category_id_with_same_defined_properties(self): + """Test updating the `catalogue_category_id` of a catalogue item when both the old and new catalogue category + has identical properties.""" -# # pylint: disable=duplicate-code -# CATALOGUE_CATEGORY_POST_A = { -# "name": "Category A", -# "is_leaf": True, -# "properties": [ -# {"name": "Property A", "type": "number", "unit": "mm", "mandatory": False}, -# {"name": "Property B", "type": "boolean", "mandatory": True}, -# {"name": "Property C", "type": "string", "unit": "cm", "mandatory": True}, -# ], -# } -# # pylint: enable=duplicate-code + self.post_unit(UNIT_POST_DATA_MM) + self.post_catalogue_category(BASE_CATALOGUE_CATEGORY_WITH_PROPERTIES) + self.post_manufacturer(MANUFACTURER_POST_DATA_REQUIRED_VALUES_ONLY) + catalogue_item_id = self.post_catalogue_item(CATALOGUE_ITEM_DATA_WITH_ALL_PROPERTIES) + new_catalogue_category_id = self.post_catalogue_category( + {**BASE_CATALOGUE_CATEGORY_WITH_PROPERTIES, "name": "Another category"} + ) -# CATALOGUE_CATEGORY_POST_B = { -# "name": "Category B", -# "is_leaf": True, -# "properties": [ -# {"name": "Property A", "type": "boolean", "mandatory": True}, -# ], -# } + self.patch_catalogue_item(catalogue_item_id, {"catalogue_category_id": new_catalogue_category_id}) + self.check_patch_catalogue_item_response_success(CATALOGUE_ITEM_GET_DATA_WITH_ALL_PROPERTIES) -# # pylint: disable=duplicate-code -# MANUFACTURER = { -# "name": "Manufacturer D", -# "url": "http://example.com/", -# "address": { -# "address_line": "1 Example Street", -# "town": "Oxford", -# "county": "Oxfordshire", -# "country": "United Kingdom", -# "postcode": "OX1 2AB", -# }, -# "telephone": "0932348348", -# } + def test_partial_update_catalogue_category_id_and_properties_with_same_defined_properties(self): + """Test updating the `catalogue_category_id` and `properties` of a catalogue item when both the old and new + catalogue category has identical properties.""" -# CATALOGUE_ITEM_POST_A = { -# "name": "Catalogue Item A", -# "description": "This is Catalogue Item A", -# "cost_gbp": 129.99, -# "days_to_replace": 2.0, -# "drawing_link": "https://drawing-link.com/", -# "item_model_number": "abc123", -# "is_obsolete": False, -# "properties": [ -# {"name": "Property A", "value": 20}, -# {"name": "Property B", "value": False}, -# {"name": "Property C", "value": "20x15x10"}, -# ], -# } + self.post_unit(UNIT_POST_DATA_MM) + self.post_catalogue_category(BASE_CATALOGUE_CATEGORY_WITH_PROPERTIES) + self.post_manufacturer(MANUFACTURER_POST_DATA_REQUIRED_VALUES_ONLY) + catalogue_item_id = self.post_catalogue_item(CATALOGUE_ITEM_DATA_WITH_ALL_PROPERTIES) + new_catalogue_category_id = self.post_catalogue_category( + {**BASE_CATALOGUE_CATEGORY_WITH_PROPERTIES, "name": "Another category"} + ) -# CATALOGUE_ITEM_POST_A_EXPECTED = { -# **CATALOGUE_ITEM_POST_A, -# **CREATED_MODIFIED_VALUES_EXPECTED, -# "id": ANY, -# "cost_to_rework_gbp": None, -# "days_to_rework": None, -# "drawing_number": None, -# "obsolete_reason": None, -# "obsolete_replacement_catalogue_item_id": None, -# "notes": None, -# "properties": [ -# {"name": "Property A", "value": 20, "unit": "mm"}, -# {"name": "Property B", "value": False, "unit": None}, -# {"name": "Property C", "value": "20x15x10", "unit": "cm"}, -# ], -# } + self.patch_catalogue_item( + catalogue_item_id, + { + "catalogue_category_id": new_catalogue_category_id, + "properties": CATALOGUE_ITEM_DATA_WITH_MANDATORY_PROPERTIES_ONLY["properties"], + }, + ) + self.check_patch_catalogue_item_response_success( + { + **CATALOGUE_ITEM_GET_DATA_WITH_ALL_PROPERTIES, + "properties": CATALOGUE_ITEM_GET_DATA_WITH_MANDATORY_PROPERTIES_ONLY["properties"], + } + ) -# CATALOGUE_ITEM_POST_B = { -# "name": "Catalogue Item B", -# "description": "This is Catalogue Item B", -# "cost_gbp": 300.00, -# "cost_to_rework_gbp": 120.99, -# "days_to_replace": 1.5, -# "days_to_rework": 3.0, -# "drawing_number": "789xyz", -# "is_obsolete": False, -# "notes": "Some extra information", -# "properties": [{"name": "Property A", "value": True}], -# } -# # pylint: enable=duplicate-code + def test_partial_update_catalogue_category_id_with_same_defined_properties_different_order(self): + """Test updating the `catalogue_category_id` of a catalogue item when both the old and new catalogue category + has identical properties but in a different order.""" -# CATALOGUE_ITEM_POST_B_EXPECTED = { -# **CATALOGUE_ITEM_POST_B, -# **CREATED_MODIFIED_VALUES_EXPECTED, -# "id": ANY, -# "drawing_link": None, -# "item_model_number": None, -# "obsolete_reason": None, -# "obsolete_replacement_catalogue_item_id": None, -# "properties": [{"name": "Property A", "value": True, "unit": None}], -# } + self.post_unit(UNIT_POST_DATA_MM) + self.post_catalogue_category(BASE_CATALOGUE_CATEGORY_WITH_PROPERTIES) + self.post_manufacturer(MANUFACTURER_POST_DATA_REQUIRED_VALUES_ONLY) + catalogue_item_id = self.post_catalogue_item(CATALOGUE_ITEM_DATA_WITH_ALL_PROPERTIES) + new_catalogue_category_id = self.post_catalogue_category( + { + **BASE_CATALOGUE_CATEGORY_WITH_PROPERTIES, + "name": "Another category", + "properties": BASE_CATALOGUE_CATEGORY_WITH_PROPERTIES["properties"][::-1], + } + ) -# def test_partial_update_catalogue_item_when_no_child_items(test_client): -# """ -# Test changing the name and description of a catalogue item when it doesn't have any child -# items -# """ -# catalogue_category = _post_catalogue_category_with_units(test_client, CATALOGUE_CATEGORY_POST_A) + self.patch_catalogue_item(catalogue_item_id, {"catalogue_category_id": new_catalogue_category_id}) + self.check_patch_catalogue_item_failed_with_detail( + 422, + "Cannot move catalogue item to a category with different properties without specifying the new properties", + ) -# # pylint: disable=duplicate-code -# response = test_client.post("/v1/manufacturers", json=MANUFACTURER) -# manufacturer_id = response.json()["id"] + def test_partial_update_catalogue_category_id_and_properties_with_same_defined_properties_different_order(self): + """Test updating the `catalogue_category_id` and `properties` of a catalogue item when both the old and new + catalogue category has identical properties but in a different order.""" -# catalogue_item_post = { -# **CATALOGUE_ITEM_POST_A, -# "catalogue_category_id": catalogue_category["id"], -# "manufacturer_id": manufacturer_id, -# "properties": add_ids_to_properties(catalogue_category["properties"], CATALOGUE_ITEM_POST_A["properties"]), -# } -# response = test_client.post("/v1/catalogue-items", json=catalogue_item_post) -# # pylint: enable=duplicate-code + self.post_unit(UNIT_POST_DATA_MM) + self.post_catalogue_category(BASE_CATALOGUE_CATEGORY_WITH_PROPERTIES) + self.post_manufacturer(MANUFACTURER_POST_DATA_REQUIRED_VALUES_ONLY) + catalogue_item_id = self.post_catalogue_item(CATALOGUE_ITEM_DATA_WITH_ALL_PROPERTIES) + new_catalogue_category_id = self.post_catalogue_category( + { + **BASE_CATALOGUE_CATEGORY_WITH_PROPERTIES, + "name": "Another category", + "properties": BASE_CATALOGUE_CATEGORY_WITH_PROPERTIES["properties"][::-1], + } + ) -# catalogue_item_patch = {"name": "Catalogue Item B", "description": "This is Catalogue Item B"} -# response = test_client.patch(f"/v1/catalogue-items/{response.json()['id']}", json=catalogue_item_patch) + self.patch_catalogue_item( + catalogue_item_id, + { + "catalogue_category_id": new_catalogue_category_id, + "properties": CATALOGUE_ITEM_DATA_WITH_ALL_PROPERTIES["properties"][::-1], + }, + ) + self.check_patch_catalogue_item_response_success( + { + **CATALOGUE_ITEM_GET_DATA_WITH_ALL_PROPERTIES, + "properties": CATALOGUE_ITEM_GET_DATA_WITH_ALL_PROPERTIES["properties"][::-1], + } + ) -# assert response.status_code == 200 + def test_partial_update_catalogue_category_id_with_different_defined_properties(self): + """Test updating the `catalogue_category_id` of a catalogue item when the old and new catalogue category + have different properties.""" -# catalogue_item = response.json() + self.post_unit(UNIT_POST_DATA_MM) + self.post_catalogue_category(BASE_CATALOGUE_CATEGORY_WITH_PROPERTIES) + self.post_manufacturer(MANUFACTURER_POST_DATA_REQUIRED_VALUES_ONLY) + catalogue_item_id = self.post_catalogue_item(CATALOGUE_ITEM_DATA_WITH_ALL_PROPERTIES) + new_catalogue_category_id = self.post_catalogue_category( + { + **BASE_CATALOGUE_CATEGORY_WITH_PROPERTIES, + "name": "Another category", + "properties": [CATALOGUE_CATEGORY_PROPERTY_DATA_NUMBER_NON_MANDATORY_WITH_MM_UNIT], + } + ) -# assert catalogue_item == { -# **CATALOGUE_ITEM_POST_A_EXPECTED, -# **catalogue_item_patch, -# "catalogue_category_id": catalogue_category["id"], -# "manufacturer_id": manufacturer_id, -# "properties": add_ids_to_properties( -# catalogue_category["properties"], CATALOGUE_ITEM_POST_A_EXPECTED["properties"] -# ), -# } + self.patch_catalogue_item(catalogue_item_id, {"catalogue_category_id": new_catalogue_category_id}) + self.check_patch_catalogue_item_failed_with_detail( + 422, + "Cannot move catalogue item to a category with different properties without specifying the new properties", + ) + def test_partial_update_catalogue_category_id_and_properties_with_different_defined_properties(self): + """Test updating the `catalogue_category_id` and `properties` of a catalogue item when the old and new catalogue + category have different properties.""" -# def test_partial_update_catalogue_item_when_has_child_items(test_client): -# """ -# Test updating a catalogue item which has child items. -# """ -# # pylint: disable=duplicate-code -# catalogue_category = _post_catalogue_category_with_units(test_client, CATALOGUE_CATEGORY_POST_A) + self.post_unit(UNIT_POST_DATA_MM) + self.post_catalogue_category(BASE_CATALOGUE_CATEGORY_WITH_PROPERTIES) + self.post_manufacturer(MANUFACTURER_POST_DATA_REQUIRED_VALUES_ONLY) + catalogue_item_id = self.post_catalogue_item(CATALOGUE_ITEM_DATA_WITH_ALL_PROPERTIES) + new_catalogue_category_id = self.post_catalogue_category( + { + **BASE_CATALOGUE_CATEGORY_WITH_PROPERTIES, + "name": "Another category", + "properties": [CATALOGUE_CATEGORY_PROPERTY_DATA_NUMBER_NON_MANDATORY_WITH_MM_UNIT], + } + ) -# # pylint: disable=duplicate-code -# response = test_client.post("/v1/manufacturers", json=MANUFACTURER) -# manufacturer_id = response.json()["id"] + self.patch_catalogue_item( + catalogue_item_id, + {"catalogue_category_id": new_catalogue_category_id, "properties": [PROPERTY_DATA_NUMBER_NON_MANDATORY_42]}, + ) + self.check_patch_catalogue_item_response_success( + { + **CATALOGUE_ITEM_GET_DATA_WITH_ALL_PROPERTIES, + "properties": [PROPERTY_GET_DATA_NUMBER_NON_MANDATORY_42], + } + ) -# catalogue_item_post = { -# **CATALOGUE_ITEM_POST_A, -# "catalogue_category_id": catalogue_category["id"], -# "manufacturer_id": manufacturer_id, -# "properties": add_ids_to_properties(catalogue_category["properties"], CATALOGUE_ITEM_POST_A["properties"]), -# } -# response = test_client.post("/v1/catalogue-items", json=catalogue_item_post) -# # pylint: enable=duplicate-code + def test_partial_update_catalogue_category_id_while_removing_all_defined_properties(self): + """Test updating the `catalogue_category_id` of a catalogue item when the old catalogue category and item has + properties but the new one does not.""" -# catalogue_item_patch = {"name": "Catalogue Item B", "description": "This is Catalogue Item B"} -# response = test_client.patch(f"/v1/catalogue-items/{response.json()['id']}", json=catalogue_item_patch) + self.post_unit(UNIT_POST_DATA_MM) + self.post_catalogue_category(BASE_CATALOGUE_CATEGORY_WITH_PROPERTIES) + self.post_manufacturer(MANUFACTURER_POST_DATA_REQUIRED_VALUES_ONLY) + catalogue_item_id = self.post_catalogue_item(CATALOGUE_ITEM_DATA_WITH_ALL_PROPERTIES) + new_catalogue_category_id = self.post_catalogue_category( + { + **BASE_CATALOGUE_CATEGORY_WITH_PROPERTIES, + "name": "Another category", + "properties": [], + } + ) -# assert response.status_code == 200 + self.patch_catalogue_item(catalogue_item_id, {"catalogue_category_id": new_catalogue_category_id}) + self.check_patch_catalogue_item_failed_with_detail( + 422, + "Cannot move catalogue item to a category with different properties without specifying the new properties", + ) -# catalogue_item = response.json() + def test_partial_update_catalogue_category_id_and_properties_while_removing_all_defined_properties(self): + """Test updating the `catalogue_category_id` and `properties` of a catalogue item when the old catalogue + category and item has properties but the new one does not.""" -# assert catalogue_item == { -# **CATALOGUE_ITEM_POST_A_EXPECTED, -# **catalogue_item_patch, -# "catalogue_category_id": catalogue_category["id"], -# "manufacturer_id": manufacturer_id, -# "properties": add_ids_to_properties( -# catalogue_category["properties"], CATALOGUE_ITEM_POST_A_EXPECTED["properties"] -# ), -# } - - -# def test_partial_update_catalogue_item_invalid_id(test_client): -# """ -# Test updating a catalogue item with an invalid ID. -# """ -# catalogue_item_patch = {"name": "Catalogue Item B", "description": "This is Catalogue Item B"} - -# response = test_client.patch("/v1/catalogue-items/invalid", json=catalogue_item_patch) - -# assert response.status_code == 404 -# assert response.json()["detail"] == "Catalogue item not found" - - -# def test_partial_update_catalogue_item_non_existent_id(test_client): -# """ -# Test updating a catalogue item with a non-existent ID. -# """ -# catalogue_item_patch = {"name": "Catalogue Item B", "description": "This is Catalogue Item B"} - -# response = test_client.patch(f"/v1/catalogue-items/{str(ObjectId())}", json=catalogue_item_patch) - -# assert response.status_code == 404 -# assert response.json()["detail"] == "Catalogue item not found" - - -# def test_partial_update_catalogue_item_change_catalogue_category_id(test_client): -# """ -# Test moving a catalogue item to another catalogue category with the same properties without -# specifying any new properties. -# """ -# # pylint: disable=duplicate-code -# catalogue_category_a = _post_catalogue_category_with_units(test_client, CATALOGUE_CATEGORY_POST_A) -# catalogue_category_b = _post_catalogue_category_with_units( -# test_client, -# { -# **CATALOGUE_CATEGORY_POST_B, -# "properties": CATALOGUE_CATEGORY_POST_A["properties"], -# }, -# ) -# # pylint: enable=duplicate-code -# response = test_client.post("/v1/manufacturers", json=MANUFACTURER) -# manufacturer_id = response.json()["id"] - -# catalogue_item_post = { -# **CATALOGUE_ITEM_POST_A, -# "catalogue_category_id": catalogue_category_a["id"], -# "manufacturer_id": manufacturer_id, -# "properties": add_ids_to_properties(catalogue_category_a["properties"], CATALOGUE_ITEM_POST_A["properties"]), -# } -# response = test_client.post("/v1/catalogue-items", json=catalogue_item_post) - -# catalogue_item_patch = { -# "catalogue_category_id": catalogue_category_b["id"], -# } -# response = test_client.patch(f"/v1/catalogue-items/{response.json()['id']}", json=catalogue_item_patch) - -# assert response.status_code == 200 - -# catalogue_item = response.json() - -# assert catalogue_item == { -# **CATALOGUE_ITEM_POST_A_EXPECTED, -# "catalogue_category_id": catalogue_category_b["id"], -# "manufacturer_id": manufacturer_id, -# "properties": add_ids_to_properties( -# catalogue_category_b["properties"], CATALOGUE_ITEM_POST_A_EXPECTED["properties"] -# ), -# } - - -# def test_partial_update_catalogue_item_change_catalogue_category_id_without_properties(test_client): -# """ -# Test moving a catalogue item to another catalogue category without supplying any properties. -# """ -# catalogue_category_a = _post_catalogue_category_with_units(test_client, CATALOGUE_CATEGORY_POST_A) -# response = test_client.post("/v1/catalogue-categories", json=CATALOGUE_CATEGORY_POST_B) -# catalogue_category_b_id = response.json()["id"] - -# response = test_client.post("/v1/manufacturers", json=MANUFACTURER) -# manufacturer_id = response.json()["id"] + self.post_unit(UNIT_POST_DATA_MM) + self.post_catalogue_category(BASE_CATALOGUE_CATEGORY_WITH_PROPERTIES) + self.post_manufacturer(MANUFACTURER_POST_DATA_REQUIRED_VALUES_ONLY) + catalogue_item_id = self.post_catalogue_item(CATALOGUE_ITEM_DATA_WITH_ALL_PROPERTIES) + new_catalogue_category_id = self.post_catalogue_category( + { + **BASE_CATALOGUE_CATEGORY_WITH_PROPERTIES, + "name": "Another category", + "properties": [], + } + ) -# catalogue_item_post = { -# **CATALOGUE_ITEM_POST_A, -# "catalogue_category_id": catalogue_category_a["id"], -# "manufacturer_id": manufacturer_id, -# "properties": add_ids_to_properties(catalogue_category_a["properties"], CATALOGUE_ITEM_POST_A["properties"]), -# } -# response = test_client.post("/v1/catalogue-items", json=catalogue_item_post) + self.patch_catalogue_item( + catalogue_item_id, + {"catalogue_category_id": new_catalogue_category_id, "properties": []}, + ) + self.check_patch_catalogue_item_response_success( + { + **CATALOGUE_ITEM_GET_DATA_WITH_ALL_PROPERTIES, + "properties": [], + } + ) -# catalogue_item_patch = {"catalogue_category_id": catalogue_category_b_id} -# response = test_client.patch(f"/v1/catalogue-items/{response.json()['id']}", json=catalogue_item_patch) + def test_partial_update_catalogue_category_id_and_properties_with_missing_non_mandatory_properties(self): + """Test updating the `catalogue_category_id` of a catalogue item when the item has missing non mandatory + properties in the new catalogue category.""" -# assert response.status_code == 422 -# assert ( -# response.json()["detail"] -# == "Cannot move catalogue item to a category with different properties without specifying the " -# "new properties" -# ) + self.post_unit(UNIT_POST_DATA_MM) + self.post_catalogue_category(CATALOGUE_CATEGORY_POST_DATA_LEAF_REQUIRED_VALUES_ONLY) + self.post_manufacturer(MANUFACTURER_POST_DATA_REQUIRED_VALUES_ONLY) + catalogue_item_id = self.post_catalogue_item(CATALOGUE_ITEM_DATA_REQUIRED_VALUES_ONLY) + new_catalogue_category_id = self.post_catalogue_category(BASE_CATALOGUE_CATEGORY_WITH_PROPERTIES) + self.patch_catalogue_item( + catalogue_item_id, + { + "catalogue_category_id": new_catalogue_category_id, + "properties": CATALOGUE_ITEM_DATA_WITH_MANDATORY_PROPERTIES_ONLY["properties"], + }, + ) + self.check_patch_catalogue_item_response_success( + { + **CATALOGUE_ITEM_GET_DATA_REQUIRED_VALUES_ONLY, + "properties": CATALOGUE_ITEM_GET_DATA_WITH_MANDATORY_PROPERTIES_ONLY["properties"], + } + ) -# def test_partial_update_catalogue_item_change_catalogue_category_id_with_properties(test_client): -# """ -# Test moving a catalogue item to another catalogue category while supplying any new properties. -# """ -# catalogue_category_a = _post_catalogue_category_with_units(test_client, CATALOGUE_CATEGORY_POST_A) -# response = test_client.post("/v1/catalogue-categories", json=CATALOGUE_CATEGORY_POST_B) -# catalogue_category_b = response.json() + def test_partial_update_catalogue_category_id_and_properties_with_missing_mandatory_properties(self): + """Test updating the `catalogue_category_id` of a catalogue item when the item has missing mandatory properties + in the new catalogue category.""" -# response = test_client.post("/v1/manufacturers", json=MANUFACTURER) -# manufacturer_id = response.json()["id"] + self.post_unit(UNIT_POST_DATA_MM) + self.post_catalogue_category(CATALOGUE_CATEGORY_POST_DATA_LEAF_REQUIRED_VALUES_ONLY) + self.post_manufacturer(MANUFACTURER_POST_DATA_REQUIRED_VALUES_ONLY) + catalogue_item_id = self.post_catalogue_item(CATALOGUE_ITEM_DATA_REQUIRED_VALUES_ONLY) + new_catalogue_category_id = self.post_catalogue_category(BASE_CATALOGUE_CATEGORY_WITH_PROPERTIES) -# catalogue_item_post = { -# **CATALOGUE_ITEM_POST_A, -# "catalogue_category_id": catalogue_category_a["id"], -# "manufacturer_id": manufacturer_id, -# "properties": add_ids_to_properties(catalogue_category_a["properties"], CATALOGUE_ITEM_POST_A["properties"]), -# } -# response = test_client.post("/v1/catalogue-items", json=catalogue_item_post) + self.patch_catalogue_item( + catalogue_item_id, {"catalogue_category_id": new_catalogue_category_id, "properties": []} + ) + self.check_patch_catalogue_item_failed_with_detail( + 422, + "Missing mandatory property with ID: " + f"'{self.property_name_id_dict[CATALOGUE_CATEGORY_PROPERTY_DATA_BOOLEAN_MANDATORY['name']]}'", + ) -# catalogue_item_patch = { -# "catalogue_category_id": catalogue_category_b["id"], -# "properties": add_ids_to_properties(catalogue_category_b["properties"], CATALOGUE_ITEM_POST_B["properties"]), -# } -# response = test_client.patch(f"/v1/catalogue-items/{response.json()['id']}", json=catalogue_item_patch) + def test_partial_update_catalogue_category_id_with_non_leaf_id(self): + """Test updating the `catalogue_category_id` of a catalogue item to a non-leaf catalogue category.""" -# assert response.status_code == 200 + self.post_catalogue_category(CATALOGUE_CATEGORY_POST_DATA_LEAF_NO_PARENT_NO_PROPERTIES) + self.post_manufacturer(MANUFACTURER_POST_DATA_REQUIRED_VALUES_ONLY) + catalogue_item_id = self.post_catalogue_item(CATALOGUE_ITEM_DATA_REQUIRED_VALUES_ONLY) + new_catalogue_category_id = self.post_catalogue_category( + CATALOGUE_CATEGORY_POST_DATA_NON_LEAF_REQUIRED_VALUES_ONLY + ) -# catalogue_item = response.json() + self.patch_catalogue_item(catalogue_item_id, {"catalogue_category_id": new_catalogue_category_id}) + self.check_patch_catalogue_item_failed_with_detail( + 409, "Adding a catalogue item to a non-leaf catalogue category is not allowed" + ) -# assert catalogue_item == { -# **CATALOGUE_ITEM_POST_A_EXPECTED, -# "catalogue_category_id": catalogue_category_b["id"], -# "manufacturer_id": manufacturer_id, -# "properties": add_ids_to_properties( -# catalogue_category_b["properties"], CATALOGUE_ITEM_POST_B_EXPECTED["properties"] -# ), -# } + def test_partial_update_catalogue_category_id_with_non_existent_id(self): + """Test updating the `catalogue_category_id` of a catalogue item to a non-existent catalogue category.""" + self.post_catalogue_category(CATALOGUE_CATEGORY_POST_DATA_LEAF_NO_PARENT_NO_PROPERTIES) + self.post_manufacturer(MANUFACTURER_POST_DATA_REQUIRED_VALUES_ONLY) + catalogue_item_id = self.post_catalogue_item(CATALOGUE_ITEM_DATA_REQUIRED_VALUES_ONLY) -# def test_partial_update_catalogue_item_change_catalogue_category_id_with_different_properties_order(test_client): -# """ -# Test moving a catalogue item to another catalogue category with the same properties but in a different order -# without supplying the new properties. -# """ -# catalogue_category_a = _post_catalogue_category_with_units(test_client, CATALOGUE_CATEGORY_POST_A) + self.patch_catalogue_item(catalogue_item_id, {"catalogue_category_id": str(ObjectId())}) + self.check_patch_catalogue_item_failed_with_detail(422, "The specified catalogue category does not exist") -# catalogue_category_b = _post_catalogue_category_with_units( -# test_client, -# { -# **CATALOGUE_CATEGORY_POST_B, -# "properties": CATALOGUE_CATEGORY_POST_A["properties"][::-1], -# }, -# ) + def test_partial_update_catalogue_category_id_with_invalid_id(self): + """Test updating the `catalogue_category_id` of a catalogue item to an invalid ID.""" -# catalogue_category_b_id = catalogue_category_b["id"] + self.post_catalogue_category(CATALOGUE_CATEGORY_POST_DATA_LEAF_NO_PARENT_NO_PROPERTIES) + self.post_manufacturer(MANUFACTURER_POST_DATA_REQUIRED_VALUES_ONLY) + catalogue_item_id = self.post_catalogue_item(CATALOGUE_ITEM_DATA_REQUIRED_VALUES_ONLY) -# response = test_client.post("/v1/manufacturers", json=MANUFACTURER) -# manufacturer_id = response.json()["id"] + self.patch_catalogue_item(catalogue_item_id, {"catalogue_category_id": "invalid-id"}) + self.check_patch_catalogue_item_failed_with_detail(422, "The specified catalogue category does not exist") -# catalogue_item_post = { -# **CATALOGUE_ITEM_POST_A, -# "catalogue_category_id": catalogue_category_a["id"], -# "manufacturer_id": manufacturer_id, -# "properties": add_ids_to_properties(catalogue_category_a["properties"], CATALOGUE_ITEM_POST_A["properties"]), -# } -# response = test_client.post("/v1/catalogue-items", json=catalogue_item_post) + def test_partial_update_manufacturer_id_with_no_children(self): + """Test updating the `manufacturer_id` of a catalogue item when it has no children.""" -# catalogue_item_patch = {"catalogue_category_id": catalogue_category_b_id} -# response = test_client.patch(f"/v1/catalogue-items/{response.json()['id']}", json=catalogue_item_patch) + self.post_catalogue_category(CATALOGUE_CATEGORY_POST_DATA_LEAF_NO_PARENT_NO_PROPERTIES) + self.post_manufacturer(MANUFACTURER_POST_DATA_REQUIRED_VALUES_ONLY) + catalogue_item_id = self.post_catalogue_item(CATALOGUE_ITEM_DATA_REQUIRED_VALUES_ONLY) + new_manufacturer_id = self.post_manufacturer(MANUFACTURER_POST_DATA_ALL_VALUES) -# assert response.status_code == 422 -# assert ( -# response.json()["detail"] -# == "Cannot move catalogue item to a category with different properties without specifying the " -# "new properties" -# ) + self.patch_catalogue_item(catalogue_item_id, {"manufacturer_id": new_manufacturer_id}) + self.check_patch_catalogue_item_response_success(CATALOGUE_ITEM_GET_DATA_REQUIRED_VALUES_ONLY) + def test_partial_update_manufacturer_id_with_children(self): + """Test updating the `manufacturer_id` of a catalogue item when it has children.""" -# def test_partial_update_catalogue_item_change_catalogue_category_id_missing_mandatory_properties(test_client): -# """ -# Test moving a catalogue item to another catalogue category with missing mandatory properties. -# """ -# catalogue_category_a = _post_catalogue_category_with_units(test_client, CATALOGUE_CATEGORY_POST_A) -# response = test_client.post("/v1/catalogue-categories", json=CATALOGUE_CATEGORY_POST_B) -# catalogue_category_b = response.json() + self.post_catalogue_category(CATALOGUE_CATEGORY_POST_DATA_LEAF_NO_PARENT_NO_PROPERTIES) + self.post_manufacturer(MANUFACTURER_POST_DATA_REQUIRED_VALUES_ONLY) + catalogue_item_id = self.post_catalogue_item(CATALOGUE_ITEM_DATA_REQUIRED_VALUES_ONLY) + self.post_child_item() + new_manufacturer_id = self.post_manufacturer(MANUFACTURER_POST_DATA_ALL_VALUES) -# response = test_client.post("/v1/manufacturers", json=MANUFACTURER) -# manufacturer_id = response.json()["id"] + self.patch_catalogue_item(catalogue_item_id, {"manufacturer_id": new_manufacturer_id}) + self.check_patch_catalogue_item_failed_with_detail( + 409, "Catalogue item has child elements and cannot be updated" + ) -# catalogue_item_post = { -# **CATALOGUE_ITEM_POST_B, -# "catalogue_category_id": catalogue_category_b["id"], -# "manufacturer_id": manufacturer_id, -# "properties": add_ids_to_properties(catalogue_category_b["properties"], CATALOGUE_ITEM_POST_B["properties"]), -# } -# response = test_client.post("/v1/catalogue-items", json=catalogue_item_post) + def test_partial_update_manufacturer_id_with_non_existent_id(self): + """Test updating the `manufacturer_id` of a catalogue item to a non-existent manufacturer.""" -# catalogue_item_patch = { -# "catalogue_category_id": catalogue_category_a["id"], -# "properties": add_ids_to_properties( -# catalogue_category_a["properties"], [CATALOGUE_ITEM_POST_B["properties"][0]] -# ), -# } -# response = test_client.patch(f"/v1/catalogue-items/{response.json()['id']}", json=catalogue_item_patch) + self.post_catalogue_category(CATALOGUE_CATEGORY_POST_DATA_LEAF_NO_PARENT_NO_PROPERTIES) + self.post_manufacturer(MANUFACTURER_POST_DATA_REQUIRED_VALUES_ONLY) + catalogue_item_id = self.post_catalogue_item(CATALOGUE_ITEM_DATA_REQUIRED_VALUES_ONLY) -# assert response.status_code == 422 -# prop_id = catalogue_category_a["properties"][1]["id"] -# assert response.json()["detail"] == f"Missing mandatory property with ID: '{prop_id}'" + self.patch_catalogue_item(catalogue_item_id, {"manufacturer_id": str(ObjectId())}) + self.check_patch_catalogue_item_failed_with_detail(422, "The specified manufacturer does not exist") + def test_partial_update_manufacturer_id_with_invalid_id(self): + """Test updating the `manufacturer_id` of a catalogue item to an invalid ID.""" -# def test_partial_update_catalogue_item_change_catalogue_category_id_missing_non_mandatory_properties(test_client): -# """ -# Test moving a catalogue item to another catalogue category with missing non-mandatory properties. -# """ -# # pylint: disable=duplicate-code -# catalogue_category_a = _post_catalogue_category_with_units(test_client, CATALOGUE_CATEGORY_POST_A) -# response = test_client.post("/v1/catalogue-categories", json=CATALOGUE_CATEGORY_POST_B) -# catalogue_category_b = response.json() -# # pylint: enable=duplicate-code + self.post_catalogue_category(CATALOGUE_CATEGORY_POST_DATA_LEAF_NO_PARENT_NO_PROPERTIES) + self.post_manufacturer(MANUFACTURER_POST_DATA_REQUIRED_VALUES_ONLY) + catalogue_item_id = self.post_catalogue_item(CATALOGUE_ITEM_DATA_REQUIRED_VALUES_ONLY) -# response = test_client.post("/v1/manufacturers", json=MANUFACTURER) -# manufacturer_id = response.json()["id"] + self.patch_catalogue_item(catalogue_item_id, {"manufacturer_id": "invalid-id"}) + self.check_patch_catalogue_item_failed_with_detail(422, "The specified manufacturer does not exist") -# catalogue_item_post = { -# **CATALOGUE_ITEM_POST_B, -# "catalogue_category_id": catalogue_category_b["id"], -# "manufacturer_id": manufacturer_id, -# "properties": add_ids_to_properties(catalogue_category_b["properties"], CATALOGUE_ITEM_POST_B["properties"]), -# } -# response = test_client.post("/v1/catalogue-items", json=catalogue_item_post) + def test_partial_update_properties_with_no_children(self): + """Test updating the `properties` of a catalogue item when it has no children.""" -# catalogue_item_patch = { -# "catalogue_category_id": catalogue_category_a["id"], -# "properties": add_ids_to_properties( -# catalogue_category_a["properties"], CATALOGUE_ITEM_POST_A["properties"][-2:] -# ), -# } -# response = test_client.patch(f"/v1/catalogue-items/{response.json()['id']}", json=catalogue_item_patch) + self.post_catalogue_category(CATALOGUE_CATEGORY_POST_DATA_LEAF_NO_PARENT_NO_PROPERTIES) + self.post_manufacturer(MANUFACTURER_POST_DATA_REQUIRED_VALUES_ONLY) + catalogue_item_id = self.post_catalogue_item(CATALOGUE_ITEM_DATA_REQUIRED_VALUES_ONLY) -# catalogue_item = response.json() + self.patch_catalogue_item(catalogue_item_id, {"properties": []}) + self.check_patch_catalogue_item_response_success(CATALOGUE_ITEM_GET_DATA_REQUIRED_VALUES_ONLY) -# assert catalogue_item == { -# **CATALOGUE_ITEM_POST_B_EXPECTED, -# "catalogue_category_id": catalogue_category_a["id"], -# "manufacturer_id": manufacturer_id, -# "properties": add_ids_to_properties( -# catalogue_category_a["properties"], -# [{"name": "Property A", "unit": "mm", "value": None}, *CATALOGUE_ITEM_POST_A_EXPECTED["properties"][-2:]], -# ), -# } + def test_partial_update_properties_with_children(self): + """Test updating the `properties` of a catalogue item when it has children.""" + self.post_catalogue_category(CATALOGUE_CATEGORY_POST_DATA_LEAF_NO_PARENT_NO_PROPERTIES) + self.post_manufacturer(MANUFACTURER_POST_DATA_REQUIRED_VALUES_ONLY) + catalogue_item_id = self.post_catalogue_item(CATALOGUE_ITEM_DATA_REQUIRED_VALUES_ONLY) + self.post_child_item() -# def test_partial_update_catalogue_item_change_catalogue_category_id_invalid_id(test_client): -# """ -# Test changing the catalogue category ID of a catalogue item to an invalid ID. -# """ -# catalogue_category = _post_catalogue_category_with_units(test_client, CATALOGUE_CATEGORY_POST_A) + self.patch_catalogue_item(catalogue_item_id, {"properties": []}) + self.check_patch_catalogue_item_failed_with_detail( + 409, "Catalogue item has child elements and cannot be updated" + ) -# # pylint: disable=duplicate-code -# response = test_client.post("/v1/manufacturers", json=MANUFACTURER) -# manufacturer_id = response.json()["id"] + def test_partial_update_obsolete_replacement_catalogue_item_id(self): + """Test updating the `obsolete_replacement_catalogue_item` of a catalogue item.""" -# catalogue_item_post = { -# **CATALOGUE_ITEM_POST_A, -# "catalogue_category_id": catalogue_category["id"], -# "manufacturer_id": manufacturer_id, -# "properties": add_ids_to_properties(catalogue_category["properties"], CATALOGUE_ITEM_POST_A["properties"]), -# } -# response = test_client.post("/v1/catalogue-items", json=catalogue_item_post) -# # pylint: enable=duplicate-code + self.post_catalogue_category(CATALOGUE_CATEGORY_POST_DATA_LEAF_NO_PARENT_NO_PROPERTIES) + self.post_manufacturer(MANUFACTURER_POST_DATA_REQUIRED_VALUES_ONLY) + obsolete_replacement_catalogue_item_id = self.post_catalogue_item(CATALOGUE_ITEM_DATA_REQUIRED_VALUES_ONLY) + catalogue_item_id = self.post_catalogue_item(CATALOGUE_ITEM_DATA_REQUIRED_VALUES_ONLY) -# catalogue_item_patch = { -# "catalogue_category_id": "invalid", -# "properties": add_ids_to_properties(None, [CATALOGUE_ITEM_POST_A["properties"][0]]), -# } -# response = test_client.patch(f"/v1/catalogue-items/{response.json()['id']}", json=catalogue_item_patch) + self.patch_catalogue_item( + catalogue_item_id, {"obsolete_replacement_catalogue_item_id": obsolete_replacement_catalogue_item_id} + ) + self.check_patch_catalogue_item_response_success( + { + **CATALOGUE_ITEM_GET_DATA_REQUIRED_VALUES_ONLY, + "obsolete_replacement_catalogue_item_id": obsolete_replacement_catalogue_item_id, + } + ) -# assert response.status_code == 422 -# assert response.json()["detail"] == "The specified catalogue category does not exist" + def test_partial_update_obsolete_replacement_catalogue_item_id_with_non_existent_id(self): + """Test updating the `obsolete_replacement_catalogue_item` of a catalogue item to a non-existent catalogue + item.""" + self.post_catalogue_category(CATALOGUE_CATEGORY_POST_DATA_LEAF_NO_PARENT_NO_PROPERTIES) + self.post_manufacturer(MANUFACTURER_POST_DATA_REQUIRED_VALUES_ONLY) + catalogue_item_id = self.post_catalogue_item(CATALOGUE_ITEM_DATA_REQUIRED_VALUES_ONLY) -# def test_partial_update_catalogue_item_change_catalogue_category_id_non_existent_id(test_client): -# """ -# Test changing the catalogue category ID of a catalogue item to a non-existent ID. -# """ -# catalogue_category = _post_catalogue_category_with_units(test_client, CATALOGUE_CATEGORY_POST_A) -# # pylint: disable=duplicate-code -# response = test_client.post("/v1/manufacturers", json=MANUFACTURER) -# manufacturer_id = response.json()["id"] + self.patch_catalogue_item(catalogue_item_id, {"obsolete_replacement_catalogue_item_id": str(ObjectId())}) + self.check_patch_catalogue_item_failed_with_detail( + 422, "The specified replacement catalogue item does not exist" + ) -# catalogue_item_post = { -# **CATALOGUE_ITEM_POST_A, -# "catalogue_category_id": catalogue_category["id"], -# "manufacturer_id": manufacturer_id, -# "properties": add_ids_to_properties(catalogue_category["properties"], CATALOGUE_ITEM_POST_A["properties"]), -# } -# response = test_client.post("/v1/catalogue-items", json=catalogue_item_post) -# # pylint: enable=duplicate-code + def test_partial_update_obsolete_replacement_catalogue_item_id_with_invalid_id(self): + """Test updating the `obsolete_replacement_catalogue_item` of a catalogue item to an invalid ID.""" -# catalogue_item_patch = { -# "catalogue_category_id": str(ObjectId()), -# "properties": add_ids_to_properties(None, [CATALOGUE_ITEM_POST_A["properties"][0]]), -# } -# response = test_client.patch(f"/v1/catalogue-items/{response.json()['id']}", json=catalogue_item_patch) + self.post_catalogue_category(CATALOGUE_CATEGORY_POST_DATA_LEAF_NO_PARENT_NO_PROPERTIES) + self.post_manufacturer(MANUFACTURER_POST_DATA_REQUIRED_VALUES_ONLY) + catalogue_item_id = self.post_catalogue_item(CATALOGUE_ITEM_DATA_REQUIRED_VALUES_ONLY) -# assert response.status_code == 422 -# assert response.json()["detail"] == "The specified catalogue category does not exist" + self.patch_catalogue_item(catalogue_item_id, {"obsolete_replacement_catalogue_item_id": "invalid-id"}) + self.check_patch_catalogue_item_failed_with_detail( + 422, "The specified replacement catalogue item does not exist" + ) + def test_partial_update_with_non_existent_id(self): + """Test updating a non-existent catalogue item.""" -# def test_partial_update_catalogue_item_change_catalogue_category_id_non_leaf_catalogue_category(test_client): -# """ -# Test moving a catalogue item to a non-leaf catalogue category. -# """ -# catalogue_category_post_a = {"name": "Category A", "is_leaf": False} -# response = test_client.post("/v1/catalogue-categories", json=catalogue_category_post_a) -# catalogue_category_a_id = response.json()["id"] -# response = test_client.post("/v1/catalogue-categories", json=CATALOGUE_CATEGORY_POST_B) -# catalogue_category_b = response.json() + self.patch_catalogue_item(str(ObjectId()), {}) + self.check_patch_catalogue_item_failed_with_detail(404, "Catalogue item not found") -# response = test_client.post("/v1/manufacturers", json=MANUFACTURER) -# manufacturer_id = response.json()["id"] + def test_partial_update_invalid_id(self): + """Test updating a catalogue item with an invalid ID.""" -# catalogue_item_post = { -# **CATALOGUE_ITEM_POST_B, -# "catalogue_category_id": catalogue_category_b["id"], -# "manufacturer_id": manufacturer_id, -# "properties": add_ids_to_properties(catalogue_category_b["properties"], CATALOGUE_ITEM_POST_B["properties"]), -# } -# response = test_client.post("/v1/catalogue-items", json=catalogue_item_post) + self.patch_catalogue_item("invalid-id", {}) + self.check_patch_catalogue_item_failed_with_detail(404, "Catalogue item not found") -# catalogue_item_patch = {"catalogue_category_id": catalogue_category_a_id} -# response = test_client.patch(f"/v1/catalogue-items/{response.json()['id']}", json=catalogue_item_patch) -# assert response.status_code == 409 -# assert response.json()["detail"] == "Adding a catalogue item to a non-leaf catalogue category is not allowed" +class DeleteDSL(UpdateDSL): + """Base class for delete tests.""" + _delete_response_catalogue_item: Response -# def test_partial_update_catalogue_item_change_catalogue_category_id_has_child_items(test_client): -# """ -# Test moving a catalogue item with child items to another catalogue category. -# """ -# # pylint: disable=duplicate-code -# # Parent -# catalogue_category_a = _post_catalogue_category_with_units(test_client, CATALOGUE_CATEGORY_POST_A) -# response = test_client.post("/v1/catalogue-categories", json=CATALOGUE_CATEGORY_POST_B) -# catalogue_category_b = response.json() + def delete_catalogue_item(self, catalogue_item_id: str) -> None: + """ + Deletes a catalogue item with the given ID. -# response = test_client.post("/v1/systems", json=SYSTEM_POST_A) -# system_id = response.json()["id"] + :param catalogue_item_id: ID of the catalogue item to be deleted. + """ -# response = test_client.post("/v1/manufacturers", json=MANUFACTURER) -# manufacturer_id = response.json()["id"] + self._delete_response_catalogue_item = self.test_client.delete(f"/v1/catalogue-items/{catalogue_item_id}") -# catalogue_item_post = { -# **CATALOGUE_ITEM_POST_A, -# "catalogue_category_id": catalogue_category_a["id"], -# "manufacturer_id": manufacturer_id, -# "properties": add_ids_to_properties(catalogue_category_a["properties"], CATALOGUE_ITEM_POST_A["properties"]), -# } -# response = test_client.post("/v1/catalogue-items", json=catalogue_item_post) -# catalogue_item_id = response.json()["id"] + def check_delete_catalogue_item_success(self) -> None: + """Checks that a prior call to `delete_catalogue_item` gave a successful response with the expected data + returned.""" -# catalogue_item_patch = { -# "catalogue_category_id": catalogue_category_b["id"], -# "properties": add_ids_to_properties(catalogue_category_b["properties"], CATALOGUE_ITEM_POST_B["properties"]), -# } + assert self._delete_response_catalogue_item.status_code == 204 -# response = test_client.post("/v1/usage-statuses", json=USAGE_STATUS_POST_A) -# usage_status_id = response.json()["id"] -# # child -# item_post = { -# **ITEM_POST, -# "catalogue_item_id": catalogue_item_id, -# "system_id": system_id, -# "usage_status_id": usage_status_id, -# "properties": add_ids_to_properties(catalogue_category_a["properties"], ITEM_POST["properties"]), -# } -# test_client.post("/v1/items", json=item_post) + def check_delete_catalogue_item_failed_with_detail(self, status_code: int, detail: str) -> None: + """ + Checks that a prior call to `delete_catalogue_item` gave a failed response with the expected code and + error message. -# response = test_client.patch(f"/v1/catalogue-items/{catalogue_item_id}", json=catalogue_item_patch) + :param status_code: Expected status code of the response. + :param detail: Expected detail given in the response. + """ -# assert response.status_code == 409 -# assert response.json()["detail"] == "Catalogue item has child elements and cannot be updated" + assert self._delete_response_catalogue_item.status_code == status_code + assert self._delete_response_catalogue_item.json()["detail"] == detail -# def test_partial_update_catalogue_item_change_obsolete_replacement_catalogue_item_id(test_client): -# """ -# Test updating a catalogue item with an obsolete replacement catalogue item ID. -# """ -# catalogue_category_a = _post_catalogue_category_with_units(test_client, CATALOGUE_CATEGORY_POST_A) -# response = test_client.post("/v1/catalogue-categories", json=CATALOGUE_CATEGORY_POST_B) -# catalogue_category_b = response.json() +class TestDelete(DeleteDSL): + """Tests for deleting a catalogue item.""" -# response = test_client.post("/v1/manufacturers", json=MANUFACTURER) -# manufacturer_id = response.json()["id"] + def test_delete(self): + """Test deleting a catalogue item.""" -# catalogue_item_post_a = { -# **CATALOGUE_ITEM_POST_A, -# "catalogue_category_id": catalogue_category_a["id"], -# "manufacturer_id": manufacturer_id, -# "properties": add_ids_to_properties(catalogue_category_a["properties"], CATALOGUE_ITEM_POST_A["properties"]), -# } -# response = test_client.post("/v1/catalogue-items", json=catalogue_item_post_a) -# catalogue_item_a_id = response.json()["id"] + self.post_catalogue_category(CATALOGUE_CATEGORY_POST_DATA_LEAF_NO_PARENT_NO_PROPERTIES) + self.post_manufacturer(MANUFACTURER_POST_DATA_REQUIRED_VALUES_ONLY) + catalogue_item_id = self.post_catalogue_item(CATALOGUE_ITEM_DATA_REQUIRED_VALUES_ONLY) -# catalogue_item_post_b = { -# **CATALOGUE_ITEM_POST_B, -# "catalogue_category_id": catalogue_category_b["id"], -# "manufacturer_id": manufacturer_id, -# "properties": add_ids_to_properties(catalogue_category_b["properties"], CATALOGUE_ITEM_POST_B["properties"]), -# } -# response = test_client.post("/v1/catalogue-items", json=catalogue_item_post_b) + self.delete_catalogue_item(catalogue_item_id) + self.check_delete_catalogue_item_success() -# catalogue_item_patch_b = {"is_obsolete": True, "obsolete_replacement_catalogue_item_id": catalogue_item_a_id} -# response = test_client.patch(f"/v1/catalogue-items/{response.json()['id']}", json=catalogue_item_patch_b) + self.get_catalogue_item(catalogue_item_id) + self.check_get_catalogue_item_failed_with_detail(404, "Catalogue item not found") -# assert response.status_code == 200 + def test_delete_with_child_item(self): + """Test deleting a catalogue category with a child catalogue item.""" -# catalogue_item = response.json() + self.post_catalogue_category(CATALOGUE_CATEGORY_POST_DATA_LEAF_NO_PARENT_NO_PROPERTIES) + self.post_manufacturer(MANUFACTURER_POST_DATA_REQUIRED_VALUES_ONLY) + catalogue_item_id = self.post_catalogue_item(CATALOGUE_ITEM_DATA_REQUIRED_VALUES_ONLY) + self.post_child_item() -# assert catalogue_item == { -# **CATALOGUE_ITEM_POST_B_EXPECTED, -# "catalogue_category_id": catalogue_category_b["id"], -# "manufacturer_id": manufacturer_id, -# "is_obsolete": True, -# "obsolete_replacement_catalogue_item_id": catalogue_item_a_id, -# "properties": add_ids_to_properties( -# catalogue_category_b["properties"], CATALOGUE_ITEM_POST_B_EXPECTED["properties"] -# ), -# } + self.delete_catalogue_item(catalogue_item_id) + self.check_delete_catalogue_item_failed_with_detail( + 409, "Catalogue item has child elements and cannot be deleted" + ) + def test_delete_with_non_existent_id(self): + """Test deleting a non-existent catalogue item.""" -# def test_partial_update_catalogue_item_change_obsolete_replacement_catalogue_item_id_invalid_id(test_client): -# """ -# Test updating a catalogue item with an invalid obsolete replacement catalogue item ID. -# """ -# catalogue_category = _post_catalogue_category_with_units(test_client, CATALOGUE_CATEGORY_POST_A) + self.delete_catalogue_item(str(ObjectId())) + self.check_delete_catalogue_item_failed_with_detail(404, "Catalogue item not found") -# # pylint: disable=duplicate-code -# response = test_client.post("/v1/manufacturers", json=MANUFACTURER) -# manufacturer_id = response.json()["id"] + def test_delete_with_invalid_id(self): + """Test deleting a catalogue item with an invalid ID.""" -# catalogue_item_post = { -# **CATALOGUE_ITEM_POST_A, -# "catalogue_category_id": catalogue_category["id"], -# "manufacturer_id": manufacturer_id, -# "properties": add_ids_to_properties(catalogue_category["properties"], CATALOGUE_ITEM_POST_A["properties"]), -# } -# response = test_client.post("/v1/catalogue-items", json=catalogue_item_post) -# # pylint: enable=duplicate-code + self.delete_catalogue_item("invalid_id") + self.check_delete_catalogue_item_failed_with_detail(404, "Catalogue item not found") -# catalogue_item_patch_b = {"is_obsolete": True, "obsolete_replacement_catalogue_item_id": "invalid"} -# response = test_client.patch(f"/v1/catalogue-items/{response.json()['id']}", json=catalogue_item_patch_b) -# assert response.status_code == 422 -# assert response.json()["detail"] == "The specified replacement catalogue item does not exist" +# # pylint: disable=duplicate-code +# CATALOGUE_CATEGORY_POST_A = { +# "name": "Category A", +# "is_leaf": True, +# "properties": [ +# {"name": "Property A", "type": "number", "unit": "mm", "mandatory": False}, +# {"name": "Property B", "type": "boolean", "mandatory": True}, +# {"name": "Property C", "type": "string", "unit": "cm", "mandatory": True}, +# ], +# } +# # pylint: enable=duplicate-code +# CATALOGUE_CATEGORY_POST_B = { +# "name": "Category B", +# "is_leaf": True, +# "properties": [ +# {"name": "Property A", "type": "boolean", "mandatory": True}, +# ], +# } -# def test_partial_update_catalogue_item_change_obsolete_replacement_catalogue_item_id_non_existent_id(test_client): -# """ -# Test updating a catalogue item with aa non-existent obsolete replacement catalogue item ID. -# """ -# catalogue_category = _post_catalogue_category_with_units(test_client, CATALOGUE_CATEGORY_POST_A) +# # pylint: disable=duplicate-code +# MANUFACTURER = { +# "name": "Manufacturer D", +# "url": "http://example.com/", +# "address": { +# "address_line": "1 Example Street", +# "town": "Oxford", +# "county": "Oxfordshire", +# "country": "United Kingdom", +# "postcode": "OX1 2AB", +# }, +# "telephone": "0932348348", +# } -# # pylint: disable=duplicate-code -# response = test_client.post("/v1/manufacturers", json=MANUFACTURER) -# manufacturer_id = response.json()["id"] +# CATALOGUE_ITEM_POST_A = { +# "name": "Catalogue Item A", +# "description": "This is Catalogue Item A", +# "cost_gbp": 129.99, +# "days_to_replace": 2.0, +# "drawing_link": "https://drawing-link.com/", +# "item_model_number": "abc123", +# "is_obsolete": False, +# "properties": [ +# {"name": "Property A", "value": 20}, +# {"name": "Property B", "value": False}, +# {"name": "Property C", "value": "20x15x10"}, +# ], +# } -# catalogue_item_post = { -# **CATALOGUE_ITEM_POST_A, -# "catalogue_category_id": catalogue_category["id"], -# "manufacturer_id": manufacturer_id, -# "properties": add_ids_to_properties(catalogue_category["properties"], CATALOGUE_ITEM_POST_A["properties"]), -# } -# response = test_client.post("/v1/catalogue-items", json=catalogue_item_post) -# # pylint: enable=duplicate-code +# CATALOGUE_ITEM_POST_A_EXPECTED = { +# **CATALOGUE_ITEM_POST_A, +# **CREATED_MODIFIED_VALUES_EXPECTED, +# "id": ANY, +# "cost_to_rework_gbp": None, +# "days_to_rework": None, +# "drawing_number": None, +# "obsolete_reason": None, +# "obsolete_replacement_catalogue_item_id": None, +# "notes": None, +# "properties": [ +# {"name": "Property A", "value": 20, "unit": "mm"}, +# {"name": "Property B", "value": False, "unit": None}, +# {"name": "Property C", "value": "20x15x10", "unit": "cm"}, +# ], +# } -# catalogue_item_patch_b = {"is_obsolete": True, "obsolete_replacement_catalogue_item_id": str(ObjectId())} -# response = test_client.patch(f"/v1/catalogue-items/{response.json()['id']}", json=catalogue_item_patch_b) +# CATALOGUE_ITEM_POST_B = { +# "name": "Catalogue Item B", +# "description": "This is Catalogue Item B", +# "cost_gbp": 300.00, +# "cost_to_rework_gbp": 120.99, +# "days_to_replace": 1.5, +# "days_to_rework": 3.0, +# "drawing_number": "789xyz", +# "is_obsolete": False, +# "notes": "Some extra information", +# "properties": [{"name": "Property A", "value": True}], +# } +# # pylint: enable=duplicate-code -# assert response.status_code == 422 -# assert response.json()["detail"] == "The specified replacement catalogue item does not exist" +# CATALOGUE_ITEM_POST_B_EXPECTED = { +# **CATALOGUE_ITEM_POST_B, +# **CREATED_MODIFIED_VALUES_EXPECTED, +# "id": ANY, +# "drawing_link": None, +# "item_model_number": None, +# "obsolete_reason": None, +# "obsolete_replacement_catalogue_item_id": None, +# "properties": [{"name": "Property A", "value": True, "unit": None}], +# } # def test_partial_update_catalogue_item_with_mandatory_properties_given_none(test_client): @@ -1890,211 +1841,3 @@ def test_delete_with_invalid_id(self): # prop_id = catalogue_category["properties"][0]["id"] # assert response.json()["detail"] == f"Invalid value for property with ID '{prop_id}'. Expected one of 2, 4, 6." # # pylint: enable=duplicate-code - - -# def test_partial_update_properties_when_has_child_items(test_client): -# """ -# Test updating the properties of a catalogue item when it has child items. -# """ -# catalogue_category = _post_catalogue_category_with_units(test_client, CATALOGUE_CATEGORY_POST_A) - -# response = test_client.post("/v1/systems", json=SYSTEM_POST_A) -# system_id = response.json()["id"] - -# response = test_client.post("/v1/manufacturers", json=MANUFACTURER) -# manufacturer_d_id = response.json()["id"] - -# manufacturer_e_post = { -# **MANUFACTURER, -# "name": "Manufacturer E", -# } -# response = test_client.post("/v1/manufacturers", json=manufacturer_e_post) -# manufacturer_e_id = response.json()["id"] - -# response = test_client.post("/v1/usage-statuses", json=USAGE_STATUS_POST_B) -# usage_status_id = response.json()["id"] - -# catalogue_item_post = { -# **CATALOGUE_ITEM_POST_A, -# "catalogue_category_id": catalogue_category["id"], -# "manufacturer_id": manufacturer_d_id, -# "properties": add_ids_to_properties(catalogue_category["properties"], CATALOGUE_ITEM_POST_A["properties"]), -# } -# response = test_client.post("/v1/catalogue-items", json=catalogue_item_post) -# catalogue_item_id = response.json()["id"] -# # Child -# # pylint: disable=duplicate-code -# item_post = { -# **ITEM_POST, -# "catalogue_item_id": catalogue_item_id, -# "system_id": system_id, -# "usage_status_id": usage_status_id, -# "properties": add_ids_to_properties(catalogue_category["properties"], ITEM_POST["properties"]), -# } -# test_client.post("/v1/items", json=item_post) -# # pylint: enable=duplicate-code - -# catalogue_item_patch = { -# "manufacturer_id": manufacturer_e_id, -# } -# response = test_client.patch(f"/v1/catalogue-items/{response.json()['id']}", json=catalogue_item_patch) - -# assert response.status_code == 409 -# assert response.json()["detail"] == "Catalogue item has child elements and cannot be updated" - - -# def test_partial_update_catalogue_item_change_manufacturer_id_when_no_child_items(test_client): -# """ -# Test updating the manufacturer ID of a catalogue item when it doesn't have any child items. -# """ -# response = test_client.post("/v1/catalogue-categories", json=CATALOGUE_CATEGORY_POST_B) -# catalogue_category = response.json() - -# response = test_client.post("/v1/manufacturers", json=MANUFACTURER) -# manufacturer_d_id = response.json()["id"] - -# # pylint: disable=duplicate-code -# manufacturer_e_post = { -# "name": "Manufacturer E", -# "url": "http://example.com/", -# "address": { -# "address_line": "2 Example Street", -# "town": "Oxford", -# "county": "Oxfordshire", -# "country": "United Kingdom", -# "postcode": "OX1 2AB", -# }, -# "telephone": "07384723948", -# } -# # pylint: enable=duplicate-code -# response = test_client.post("/v1/manufacturers", json=manufacturer_e_post) -# manufacturer_e_id = response.json()["id"] - -# catalogue_item_post = { -# **CATALOGUE_ITEM_POST_B, -# "catalogue_category_id": catalogue_category["id"], -# "manufacturer_id": manufacturer_d_id, -# "properties": add_ids_to_properties(catalogue_category["properties"], CATALOGUE_ITEM_POST_B["properties"]), -# } -# response = test_client.post("/v1/catalogue-items", json=catalogue_item_post) - -# catalogue_item_patch = { -# "manufacturer_id": manufacturer_e_id, -# } -# response = test_client.patch(f"/v1/catalogue-items/{response.json()['id']}", json=catalogue_item_patch) - -# assert response.status_code == 200 - -# catalogue_item = response.json() - -# assert catalogue_item == { -# **CATALOGUE_ITEM_POST_B_EXPECTED, -# **catalogue_item_patch, -# "catalogue_category_id": catalogue_category["id"], -# "manufacturer_id": manufacturer_e_id, -# "properties": add_ids_to_properties( -# catalogue_category["properties"], CATALOGUE_ITEM_POST_B_EXPECTED["properties"] -# ), -# } - - -# def test_partial_update_catalogue_item_change_manufacturer_id_when_has_child_items(test_client): -# """ -# Test updating the manufacturer ID of a catalogue item when it has child items. -# """ -# catalogue_category = _post_catalogue_category_with_units(test_client, CATALOGUE_CATEGORY_POST_A) - -# response = test_client.post("/v1/systems", json=SYSTEM_POST_A) -# system_id = response.json()["id"] - -# response = test_client.post("/v1/manufacturers", json=MANUFACTURER) -# manufacturer_id = response.json()["id"] - -# # pylint: disable=duplicate-code -# response = test_client.post("/v1/usage-statuses", json=USAGE_STATUS_POST_A) -# usage_status_id = response.json()["id"] - -# catalogue_item_post = { -# **CATALOGUE_ITEM_POST_A, -# "catalogue_category_id": catalogue_category["id"], -# "manufacturer_id": manufacturer_id, -# "properties": add_ids_to_properties(catalogue_category["properties"], CATALOGUE_ITEM_POST_A["properties"]), -# } -# # pylint: enable=duplicate-code -# response = test_client.post("/v1/catalogue-items", json=catalogue_item_post) -# catalogue_item_id = response.json()["id"] - -# # pylint: disable=duplicate-code -# # Child -# # pylint: disable=duplicate-code -# item_post = { -# **ITEM_POST, -# "catalogue_item_id": catalogue_item_id, -# "system_id": system_id, -# "usage_status_id": usage_status_id, -# "properties": add_ids_to_properties(catalogue_category["properties"], ITEM_POST["properties"]), -# } -# test_client.post("/v1/items", json=item_post) -# # pylint: enable=duplicate-code - -# catalogue_item_patch = { -# "properties": add_ids_to_properties(catalogue_category["properties"], CATALOGUE_ITEM_POST_A["properties"]), -# } -# response = test_client.patch(f"/v1/catalogue-items/{response.json()['id']}", json=catalogue_item_patch) - -# assert response.status_code == 409 -# assert response.json()["detail"] == "Catalogue item has child elements and cannot be updated" - - -# def test_partial_update_catalogue_item_change_manufacturer_id_invalid_id(test_client): -# """ -# Test changing the manufacturer ID of a catalogue item to an invalid ID. -# """ -# response = test_client.post("/v1/catalogue-categories", json=CATALOGUE_CATEGORY_POST_B) -# catalogue_category = response.json() - -# response = test_client.post("/v1/manufacturers", json=MANUFACTURER) -# manufacturer_id = response.json()["id"] - -# catalogue_item_post = { -# **CATALOGUE_ITEM_POST_B, -# "catalogue_category_id": catalogue_category["id"], -# "manufacturer_id": manufacturer_id, -# "properties": add_ids_to_properties(catalogue_category["properties"], CATALOGUE_ITEM_POST_B["properties"]), -# } -# response = test_client.post("/v1/catalogue-items", json=catalogue_item_post) - -# catalogue_item_patch = { -# "manufacturer_id": "invalid", -# } -# response = test_client.patch(f"/v1/catalogue-items/{response.json()['id']}", json=catalogue_item_patch) - -# assert response.status_code == 422 -# assert response.json()["detail"] == "The specified manufacturer does not exist" - - -# def test_partial_update_catalogue_item_change_manufacturer_id_non_existent_id(test_client): -# """ -# Test changing the manufacturer ID of a catalogue item to a non-existent ID. -# """ -# response = test_client.post("/v1/catalogue-categories", json=CATALOGUE_CATEGORY_POST_B) -# catalogue_category = response.json() - -# response = test_client.post("/v1/manufacturers", json=MANUFACTURER) -# manufacturer_id = response.json()["id"] - -# catalogue_item_post = { -# **CATALOGUE_ITEM_POST_B, -# "catalogue_category_id": catalogue_category["id"], -# "manufacturer_id": manufacturer_id, -# "properties": add_ids_to_properties(catalogue_category["properties"], CATALOGUE_ITEM_POST_B["properties"]), -# } -# response = test_client.post("/v1/catalogue-items", json=catalogue_item_post) - -# catalogue_item_patch = { -# "manufacturer_id": str(ObjectId()), -# } -# response = test_client.patch(f"/v1/catalogue-items/{response.json()['id']}", json=catalogue_item_patch) - -# assert response.status_code == 422 -# assert response.json()["detail"] == "The specified manufacturer does not exist" diff --git a/test/e2e/test_manufacturer.py b/test/e2e/test_manufacturer.py index 0364c9d9..5faa9b8e 100644 --- a/test/e2e/test_manufacturer.py +++ b/test/e2e/test_manufacturer.py @@ -5,14 +5,13 @@ # Expect some duplicate code inside tests as the tests for the different entities can be very similar # pylint: disable=duplicate-code -from typing import Optional - from test.mock_data import ( + MANUFACTURER_GET_DATA_ALL_VALUES, MANUFACTURER_GET_DATA_REQUIRED_VALUES_ONLY, - MANUFACTURER_POST_DATA_REQUIRED_VALUES_ONLY, MANUFACTURER_POST_DATA_ALL_VALUES, - MANUFACTURER_GET_DATA_ALL_VALUES, + MANUFACTURER_POST_DATA_REQUIRED_VALUES_ONLY, ) +from typing import Optional import pytest from bson import ObjectId @@ -25,7 +24,7 @@ class CreateDSL: test_client: TestClient - _post_response: Response + _post_response_manufacturer: Response @pytest.fixture(autouse=True) def setup(self, test_client): @@ -40,8 +39,12 @@ def post_manufacturer(self, manufacturer_post_data: dict) -> Optional[str]: `ManufacturerPostSchema`. :return: ID of the created manufacturer (or `None` if not successful). """ - self._post_response = self.test_client.post("/v1/manufacturers", json=manufacturer_post_data) - return self._post_response.json()["id"] if self._post_response.status_code == 201 else None + self._post_response_manufacturer = self.test_client.post("/v1/manufacturers", json=manufacturer_post_data) + return ( + self._post_response_manufacturer.json()["id"] + if self._post_response_manufacturer.status_code == 201 + else None + ) def check_post_manufacturer_success(self, expected_manufacturer_get_data: dict) -> None: """ @@ -50,8 +53,8 @@ def check_post_manufacturer_success(self, expected_manufacturer_get_data: dict) :param expected_manufacturer_get_data: Dictionary containing the expected manufacturer data as would be required for a `ManufacturerSchema`. """ - assert self._post_response.status_code == 201 - assert self._post_response.json() == expected_manufacturer_get_data + assert self._post_response_manufacturer.status_code == 201 + assert self._post_response_manufacturer.json() == expected_manufacturer_get_data def check_post_manufacturer_failed_with_detail(self, status_code: int, detail: str) -> None: """ @@ -60,8 +63,8 @@ def check_post_manufacturer_failed_with_detail(self, status_code: int, detail: s :param status_code: Expected status code to be returned. :param detail: Expected detail to be returned. """ - assert self._post_response.status_code == status_code - assert self._post_response.json()["detail"] == detail + assert self._post_response_manufacturer.status_code == status_code + assert self._post_response_manufacturer.json()["detail"] == detail def check_post_manufacturer_failed_with_validation_message(self, status_code: int, message: str) -> None: """ @@ -71,8 +74,8 @@ def check_post_manufacturer_failed_with_validation_message(self, status_code: in :param status_code: Expected status code to be returned. :param message: Expected pydantic validation error message to be returned. """ - assert self._post_response.status_code == status_code - assert self._post_response.json()["detail"][0]["msg"] == message + assert self._post_response_manufacturer.status_code == status_code + assert self._post_response_manufacturer.json()["detail"][0]["msg"] == message class TestCreate(CreateDSL): @@ -98,7 +101,7 @@ def test_create_with_duplicate_name(self): class GetDSL(CreateDSL): """Base class for get tests.""" - _get_response = Response + _get_response_manufacturer = Response def get_manufacturer(self, manufacturer_id: str) -> None: """ @@ -106,7 +109,7 @@ def get_manufacturer(self, manufacturer_id: str) -> None: :param manufacturer_id: ID of the manufacturer to be obtained. """ - self._get_response = self.test_client.get(f"/v1/manufacturers/{manufacturer_id}") + self._get_response_manufacturer = self.test_client.get(f"/v1/manufacturers/{manufacturer_id}") def check_get_manufacturer_success(self, expected_manufacturer_get_data: dict) -> None: """ @@ -115,8 +118,8 @@ def check_get_manufacturer_success(self, expected_manufacturer_get_data: dict) - :param expected_manufacturer_get_data: Dictionary containing the expected manufacturer data as would be required for a `ManufacturerSchema`. """ - assert self._get_response.status_code == 200 - assert self._get_response.json() == expected_manufacturer_get_data + assert self._get_response_manufacturer.status_code == 200 + assert self._get_response_manufacturer.json() == expected_manufacturer_get_data def check_get_manufacturer_failed_with_detail(self, status_code: int, detail: str) -> None: """ @@ -125,8 +128,8 @@ def check_get_manufacturer_failed_with_detail(self, status_code: int, detail: st :param status_code: Expected status code to be returned. :param detail: Expected detail to be returned. """ - assert self._get_response.status_code == status_code - assert self._get_response.json()["detail"] == detail + assert self._get_response_manufacturer.status_code == status_code + assert self._get_response_manufacturer.json()["detail"] == detail class TestGet(GetDSL): @@ -154,7 +157,7 @@ class ListDSL(GetDSL): def get_manufacturers(self) -> None: """Gets a list of manufacturers.""" - self._get_response = self.test_client.get("/v1/manufacturers") + self._get_response_manufacturer = self.test_client.get("/v1/manufacturers") def check_get_manufacturers_success(self, expected_manufacturers_get_data: list[dict]) -> None: """ @@ -163,8 +166,8 @@ def check_get_manufacturers_success(self, expected_manufacturers_get_data: list[ :param expected_manufacturers_get_data: List of dictionaries containing the expected manufacturer data as would be required for a `ManufacturerSchema`. """ - assert self._get_response.status_code == 200 - assert self._get_response.json() == expected_manufacturers_get_data + assert self._get_response_manufacturer.status_code == 200 + assert self._get_response_manufacturer.json() == expected_manufacturers_get_data class TestList(ListDSL): @@ -188,7 +191,7 @@ def test_list_no_manufacturers(self): class UpdateDSL(ListDSL): """Base class for update tests.""" - _patch_response: Response + _patch_response_manufacturer: Response def patch_manufacturer(self, manufacturer_id: str, manufacturer_patch_data: dict) -> None: """ @@ -198,7 +201,7 @@ def patch_manufacturer(self, manufacturer_id: str, manufacturer_patch_data: dict :param manufacturer_patch_data: Dictionary containing the manufacturer patch data as would be required for a `ManufacturerPatchSchema`. """ - self._patch_response = self.test_client.patch( + self._patch_response_manufacturer = self.test_client.patch( f"/v1/manufacturers/{manufacturer_id}", json=manufacturer_patch_data ) @@ -209,8 +212,8 @@ def check_patch_manufacturer_success(self, expected_manufacturer_get_data: dict) :param expected_manufacturer_get_data: Dictionaries containing the expected manufacturer data as would be required for a `ManufacturerSchema`. """ - assert self._patch_response.status_code == 200 - assert self._patch_response.json() == expected_manufacturer_get_data + assert self._patch_response_manufacturer.status_code == 200 + assert self._patch_response_manufacturer.json() == expected_manufacturer_get_data def check_patch_manufacturer_failed_with_detail(self, status_code: int, detail: str) -> None: """ @@ -219,8 +222,8 @@ def check_patch_manufacturer_failed_with_detail(self, status_code: int, detail: :param status_code: Expected status code to be returned. :param detail: Expected detail to be returned. """ - assert self._patch_response.status_code == status_code - assert self._patch_response.json()["detail"] == detail + assert self._patch_response_manufacturer.status_code == status_code + assert self._patch_response_manufacturer.json()["detail"] == detail class TestUpdate(UpdateDSL): @@ -264,7 +267,7 @@ def test_partial_update_invalid_id(self): class DeleteDSL(UpdateDSL): """Base class for delete tests.""" - _delete_response: Response + _delete_response_manufacturer: Response def delete_manufacturer(self, manufacturer_id: str) -> None: """ @@ -272,11 +275,11 @@ def delete_manufacturer(self, manufacturer_id: str) -> None: :param manufacturer_id: ID of the manufacturer to be deleted. """ - self._delete_response = self.test_client.delete(f"/v1/manufacturers/{manufacturer_id}") + self._delete_response_manufacturer = self.test_client.delete(f"/v1/manufacturers/{manufacturer_id}") def check_delete_manufacturer_success(self) -> None: """Checks that a prior call to `delete_manufacturer` gave a successful response.""" - assert self._delete_response.status_code == 204 + assert self._delete_response_manufacturer.status_code == 204 def check_delete_manufacturer_failed_with_detail(self, status_code: int, detail: str) -> None: """ @@ -285,8 +288,8 @@ def check_delete_manufacturer_failed_with_detail(self, status_code: int, detail: :param status_code: Expected status code to be returned. :param detail: Expected detail to be returned. """ - assert self._delete_response.status_code == status_code - assert self._delete_response.json()["detail"] == detail + assert self._delete_response_manufacturer.status_code == status_code + assert self._delete_response_manufacturer.json()["detail"] == detail class TestDelete(DeleteDSL): diff --git a/test/e2e/test_system.py b/test/e2e/test_system.py index a5d742a4..4c393ed1 100644 --- a/test/e2e/test_system.py +++ b/test/e2e/test_system.py @@ -33,7 +33,7 @@ class CreateDSL: test_client: TestClient - _post_response: Response + _post_response_system: Response @pytest.fixture(autouse=True) def setup(self, test_client): @@ -50,8 +50,8 @@ def post_system(self, system_post_data: dict) -> Optional[str]: :return: ID of the created system (or `None` if not successful). """ - self._post_response = self.test_client.post("/v1/systems", json=system_post_data) - return self._post_response.json()["id"] if self._post_response.status_code == 201 else None + self._post_response_system = self.test_client.post("/v1/systems", json=system_post_data) + return self._post_response_system.json()["id"] if self._post_response_system.status_code == 201 else None def check_post_system_success(self, expected_system_get_data: dict) -> None: """ @@ -61,8 +61,8 @@ def check_post_system_success(self, expected_system_get_data: dict) -> None: for a `SystemSchema`. """ - assert self._post_response.status_code == 201 - assert self._post_response.json() == expected_system_get_data + assert self._post_response_system.status_code == 201 + assert self._post_response_system.json() == expected_system_get_data def check_post_system_failed_with_detail(self, status_code: int, detail: str) -> None: """ @@ -72,8 +72,8 @@ def check_post_system_failed_with_detail(self, status_code: int, detail: str) -> :param detail: Expected detail given in the response. """ - assert self._post_response.status_code == status_code - assert self._post_response.json()["detail"] == detail + assert self._post_response_system.status_code == status_code + assert self._post_response_system.json()["detail"] == detail def check_post_system_failed_with_validation_message(self, status_code: int, message: str) -> None: """ @@ -84,8 +84,8 @@ def check_post_system_failed_with_validation_message(self, status_code: int, mes :param message: Expected validation error message given in the response. """ - assert self._post_response.status_code == status_code - assert self._post_response.json()["detail"][0]["msg"] == message + assert self._post_response_system.status_code == status_code + assert self._post_response_system.json()["detail"][0]["msg"] == message class TestCreate(CreateDSL): @@ -143,7 +143,7 @@ def test_create_with_invalid_importance(self): class GetDSL(CreateDSL): """Base class for get tests.""" - _get_response: Response + _get_response_system: Response def get_system(self, system_id: str): """ @@ -152,7 +152,7 @@ def get_system(self, system_id: str): :param system_id: ID of the system to be obtained. """ - self._get_response = self.test_client.get(f"/v1/systems/{system_id}") + self._get_response_system = self.test_client.get(f"/v1/systems/{system_id}") def check_get_system_success(self, expected_system_get_data: dict): """ @@ -162,8 +162,8 @@ def check_get_system_success(self, expected_system_get_data: dict): for a `SystemSchema`. """ - assert self._get_response.status_code == 200 - assert self._get_response.json() == expected_system_get_data + assert self._get_response_system.status_code == 200 + assert self._get_response_system.json() == expected_system_get_data def check_get_system_failed_with_detail(self, status_code: int, detail: str): """ @@ -173,8 +173,8 @@ def check_get_system_failed_with_detail(self, status_code: int, detail: str): :param detail: Expected detail given in the response. """ - assert self._get_response.status_code == status_code - assert self._get_response.json()["detail"] == detail + assert self._get_response_system.status_code == status_code + assert self._get_response_system.json()["detail"] == detail class TestGet(GetDSL): @@ -203,7 +203,7 @@ def test_get_with_invalid_id(self): class GetBreadcrumbsDSL(GetDSL): """Base class for breadcrumbs tests.""" - _get_response: Response + _get_response_system: Response _posted_systems_get_data: list[dict] @@ -226,7 +226,7 @@ def post_nested_systems(self, number: int) -> list[Optional[str]]: system_id = self.post_system( {**SYSTEM_POST_DATA_ALL_VALUES_NO_PARENT, "name": f"System {i}", "parent_id": parent_id} ) - self._posted_systems_get_data.append(self._post_response.json()) + self._posted_systems_get_data.append(self._post_response_system.json()) parent_id = system_id return [system["id"] for system in self._posted_systems_get_data] @@ -238,12 +238,12 @@ def get_system_breadcrumbs(self, system_id: str) -> None: :param system_id: ID of the system to obtain the breadcrumbs of. """ - self._get_response = self.test_client.get(f"/v1/systems/{system_id}/breadcrumbs") + self._get_response_system = self.test_client.get(f"/v1/systems/{system_id}/breadcrumbs") def get_last_system_breadcrumbs(self) -> None: """Gets the last system posted's breadcrumbs.""" - self.get_system_breadcrumbs(self._post_response.json()["id"]) + self.get_system_breadcrumbs(self._post_response_system.json()["id"]) def check_get_system_breadcrumbs_success(self, expected_trail_length: int, expected_full_trail: bool) -> None: """ @@ -254,8 +254,8 @@ def check_get_system_breadcrumbs_success(self, expected_trail_length: int, expec :param expected_full_trail: Whether the expected trail is a full trail or not. """ - assert self._get_response.status_code == 200 - assert self._get_response.json() == { + assert self._get_response_system.status_code == 200 + assert self._get_response_system.json() == { "trail": [ [system["id"], system["name"]] # When the expected trail length is < the number of systems posted, only use the last @@ -275,8 +275,8 @@ def check_get_system_breadcrumbs_failed_with_detail(self, status_code: int, deta :param detail: Expected detail given in the response. """ - assert self._get_response.status_code == status_code - assert self._get_response.json()["detail"] == detail + assert self._get_response_system.status_code == status_code + assert self._get_response_system.json()["detail"] == detail class TestGetBreadcrumbs(GetBreadcrumbsDSL): @@ -341,7 +341,7 @@ def get_systems(self, filters: dict) -> None: :param filters: Filters to use in the request. """ - self._get_response = self.test_client.get("/v1/systems", params=filters) + self._get_response_system = self.test_client.get("/v1/systems", params=filters) def post_test_system_with_child(self) -> list[dict]: """ @@ -364,8 +364,8 @@ def check_get_systems_success(self, expected_systems_get_data: list[dict]) -> No required for `SystemSchema`'s. """ - assert self._get_response.status_code == 200 - assert self._get_response.json() == expected_systems_get_data + assert self._get_response_system.status_code == 200 + assert self._get_response_system.json() == expected_systems_get_data class TestList(ListDSL): @@ -422,7 +422,7 @@ def test_list_with_invalid_parent_id_filter(self): class UpdateDSL(ListDSL): """Base class for update tests.""" - _patch_response: Response + _patch_response_system: Response def patch_system(self, system_id: str, system_patch_data: dict) -> None: """ @@ -432,7 +432,7 @@ def patch_system(self, system_id: str, system_patch_data: dict) -> None: :param system_patch_data: Dictionary containing the patch data as would be required for a `SystemPatchSchema`. """ - self._patch_response = self.test_client.patch(f"/v1/systems/{system_id}", json=system_patch_data) + self._patch_response_system = self.test_client.patch(f"/v1/systems/{system_id}", json=system_patch_data) def check_patch_system_response_success(self, expected_system_get_data: dict) -> None: """ @@ -442,10 +442,12 @@ def check_patch_system_response_success(self, expected_system_get_data: dict) -> for a `SystemSchema`. """ - assert self._patch_response.status_code == 200 - assert self._patch_response.json() == expected_system_get_data + assert self._patch_response_system.status_code == 200 + assert self._patch_response_system.json() == expected_system_get_data - E2ETestHelpers.check_created_and_modified_times_updated_correctly(self._post_response, self._patch_response) + E2ETestHelpers.check_created_and_modified_times_updated_correctly( + self._post_response_system, self._patch_response_system + ) def check_patch_system_failed_with_detail(self, status_code: int, detail: str) -> None: """ @@ -455,8 +457,8 @@ def check_patch_system_failed_with_detail(self, status_code: int, detail: str) - :param detail: Expected detail given in the response. """ - assert self._patch_response.status_code == status_code - assert self._patch_response.json()["detail"] == detail + assert self._patch_response_system.status_code == status_code + assert self._patch_response_system.json()["detail"] == detail class TestUpdate(UpdateDSL): @@ -550,7 +552,7 @@ def test_partial_update_invalid_id(self): class DeleteDSL(UpdateDSL): """Base class for delete tests.""" - _delete_response: Response + _delete_response_system: Response def delete_system(self, system_id: str) -> None: """ @@ -559,12 +561,12 @@ def delete_system(self, system_id: str) -> None: :param system_id: ID of the system to be deleted. """ - self._delete_response = self.test_client.delete(f"/v1/systems/{system_id}") + self._delete_response_system = self.test_client.delete(f"/v1/systems/{system_id}") def check_delete_system_success(self) -> None: """Checks that a prior call to `delete_system` gave a successful response with the expected data returned.""" - assert self._delete_response.status_code == 204 + assert self._delete_response_system.status_code == 204 def check_delete_system_failed_with_detail(self, status_code: int, detail: str) -> None: """ @@ -575,8 +577,8 @@ def check_delete_system_failed_with_detail(self, status_code: int, detail: str) :param detail: Expected detail given in the response. """ - assert self._delete_response.status_code == status_code - assert self._delete_response.json()["detail"] == detail + assert self._delete_response_system.status_code == status_code + assert self._delete_response_system.json()["detail"] == detail class TestDelete(DeleteDSL): diff --git a/test/unit/services/test_catalogue_item.py b/test/unit/services/test_catalogue_item.py index cbe110b2..5ccdb803 100644 --- a/test/unit/services/test_catalogue_item.py +++ b/test/unit/services/test_catalogue_item.py @@ -852,7 +852,7 @@ def test_update_catalogue_category_id_no_properties(self): self.call_update(catalogue_item_id) self.check_update_success() - def test_update_catalogue_category_id_without_properties_with_same_defined_properties(self): + def test_update_catalogue_category_id_with_same_defined_properties(self): """Test updating the catalogue item's `catalogue_category_id` when both the old and new catalogue category has identical properties. """ @@ -889,7 +889,7 @@ def test_update_catalogue_category_id_and_properties_with_same_defined_propertie self.call_update(catalogue_item_id) self.check_update_success() - def test_update_catalogue_category_id_without_properties_with_same_defined_properties_different_order(self): + def test_update_catalogue_category_id_with_same_defined_properties_different_order(self): """Test updating the catalogue item's `catalogue_category_id` when both the old and new catalogue category has identical properties but in a different order. """ @@ -935,7 +935,7 @@ def test_update_catalogue_category_id_and_properties_with_same_defined_propertie self.call_update(catalogue_item_id) self.check_update_success() - def test_update_catalogue_category_id_without_properties_with_different_defined_properties(self): + def test_update_catalogue_category_id_with_different_defined_properties(self): """Test updating the catalogue item's `catalogue_category_id` when the old and new catalogue category have different properties. """ @@ -981,45 +981,45 @@ def test_update_catalogue_category_id_and_properties_with_different_defined_prop self.call_update(catalogue_item_id) self.check_update_success() - def test_update_catalogue_category_id_and_properties_while_removing_defined_properties(self): - """Test updating the catalogue item's `catalogue_category_id` and `properties` when the old catalogue category - and item has properties but the new one does not. + def test_update_catalogue_category_id_while_removing_all_defined_properties(self): + """Test updating the catalogue item's `catalogue_category_id` when the old catalogue category and item has + properties but the new one does not. """ catalogue_item_id = str(ObjectId()) self.mock_update( catalogue_item_id, - catalogue_item_update_data={"catalogue_category_id": str(ObjectId()), "properties": []}, + catalogue_item_update_data={"catalogue_category_id": str(ObjectId())}, stored_catalogue_item_data=CATALOGUE_ITEM_DATA_WITH_ALL_PROPERTIES, stored_catalogue_category_in_data=CATALOGUE_CATEGORY_IN_DATA_LEAF_NO_PARENT_WITH_PROPERTIES_MM, new_catalogue_category_in_data=CATALOGUE_CATEGORY_IN_DATA_LEAF_NO_PARENT_NO_PROPERTIES, ) - self.call_update(catalogue_item_id) - self.check_update_success() + self.call_update_expecting_error(catalogue_item_id, InvalidActionError) + self.check_update_failed_with_exception( + "Cannot move catalogue item to a category with different properties " + "without specifying the new properties" + ) - def test_update_catalogue_category_id_without_properties_while_removing_defined_properties(self): - """Test updating the catalogue item's `catalogue_category_id` when the old catalogue category and item has - properties but the new one does not. + def test_update_catalogue_category_id_and_properties_while_removing_all_defined_properties(self): + """Test updating the catalogue item's `catalogue_category_id` and `properties` when the old catalogue category + and item has properties but the new one does not. """ catalogue_item_id = str(ObjectId()) self.mock_update( catalogue_item_id, - catalogue_item_update_data={"catalogue_category_id": str(ObjectId())}, + catalogue_item_update_data={"catalogue_category_id": str(ObjectId()), "properties": []}, stored_catalogue_item_data=CATALOGUE_ITEM_DATA_WITH_ALL_PROPERTIES, stored_catalogue_category_in_data=CATALOGUE_CATEGORY_IN_DATA_LEAF_NO_PARENT_WITH_PROPERTIES_MM, new_catalogue_category_in_data=CATALOGUE_CATEGORY_IN_DATA_LEAF_NO_PARENT_NO_PROPERTIES, ) - self.call_update_expecting_error(catalogue_item_id, InvalidActionError) - self.check_update_failed_with_exception( - "Cannot move catalogue item to a category with different properties " - "without specifying the new properties" - ) + self.call_update(catalogue_item_id) + self.check_update_success() - def test_update_with_non_existent_catalogue_category_id(self): - """Test updating the catalogue item's `catalogue_category_id` to a non-existent catalogue category.""" + def test_update_with_non_leaf_catalogue_category_id(self): + """Test updating the catalogue item's `catalogue_category_id` to a leaf catalogue category.""" catalogue_item_id = str(ObjectId()) catalogue_category_id = str(ObjectId()) @@ -1028,12 +1028,13 @@ def test_update_with_non_existent_catalogue_category_id(self): catalogue_item_id, catalogue_item_update_data={"catalogue_category_id": catalogue_category_id}, stored_catalogue_item_data=CATALOGUE_ITEM_DATA_REQUIRED_VALUES_ONLY, + new_catalogue_category_in_data=CATALOGUE_CATEGORY_IN_DATA_NON_LEAF_NO_PARENT_NO_PROPERTIES_A, ) - self.call_update_expecting_error(catalogue_item_id, MissingRecordError) - self.check_update_failed_with_exception(f"No catalogue category found with ID: {catalogue_category_id}") + self.call_update_expecting_error(catalogue_item_id, NonLeafCatalogueCategoryError) + self.check_update_failed_with_exception("Cannot add catalogue item to a non-leaf catalogue category") - def test_update_with_non_leaf_catalogue_category_id(self): - """Test updating the catalogue item's `catalogue_category_id` to a leaf catalogue category.""" + def test_update_with_non_existent_catalogue_category_id(self): + """Test updating the catalogue item's `catalogue_category_id` to a non-existent catalogue category.""" catalogue_item_id = str(ObjectId()) catalogue_category_id = str(ObjectId()) @@ -1042,10 +1043,9 @@ def test_update_with_non_leaf_catalogue_category_id(self): catalogue_item_id, catalogue_item_update_data={"catalogue_category_id": catalogue_category_id}, stored_catalogue_item_data=CATALOGUE_ITEM_DATA_REQUIRED_VALUES_ONLY, - new_catalogue_category_in_data=CATALOGUE_CATEGORY_IN_DATA_NON_LEAF_NO_PARENT_NO_PROPERTIES_A, ) - self.call_update_expecting_error(catalogue_item_id, NonLeafCatalogueCategoryError) - self.check_update_failed_with_exception("Cannot add catalogue item to a non-leaf catalogue category") + self.call_update_expecting_error(catalogue_item_id, MissingRecordError) + self.check_update_failed_with_exception(f"No catalogue category found with ID: {catalogue_category_id}") def test_update_manufacturer_id_with_no_children(self): """Test updating the catalogue item's `manufacturer_id` when it has no children."""