diff --git a/CHANGELOG.md b/CHANGELOG.md index 013beb94..417d2bb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ - add tutorial for protected endpoint with bearer authentication ([#208](https://github.com/RWTH-EBC/FiLiP/issues/208)) - update pandas version to `~=2.1.4` for `python>=3.9` ([#231](https://github.com/RWTH-EBC/FiLiP/pull/231)) - fix: wrong msg in iotac post device ([#214](https://github.com/RWTH-EBC/FiLiP/pull/214)) +- add function to override the existing entity ([#232 ](https://github.com/RWTH-EBC/FiLiP/pull/232 )) #### v0.3.0 - fix: bug in typePattern validation @richardmarston ([#180](https://github.com/RWTH-EBC/FiLiP/pull/180)) diff --git a/filip/clients/ngsi_v2/cb.py b/filip/clients/ngsi_v2/cb.py index baa7546c..745b1cfc 100644 --- a/filip/clients/ngsi_v2/cb.py +++ b/filip/clients/ngsi_v2/cb.py @@ -242,7 +242,7 @@ def post_entity(self, res.raise_for_status() except requests.RequestException as err: if update and err.response.status_code == 422: - return self.update_entity( + return self.override_entity( entity=entity) if patch and err.response.status_code == 422: return self.patch_entity( @@ -770,6 +770,23 @@ def update_existing_entity_attributes( self.log_error(err=err, msg=msg) raise + def override_entity(self, entity: ContextEntity): + """ + The request payload is an object representing the attributes to + override the existing entity. + + Note: + If you want to manipulate you should rather use patch_entity. + + Args: + entity (ContextEntity): + Returns: + None + """ + self.replace_entity_attributes(entity_id=entity.id, + entity_type=entity.type, + attrs=entity.get_properties()) + def replace_entity_attributes( self, entity_id: str, diff --git a/tests/clients/test_ngsi_v2_cb.py b/tests/clients/test_ngsi_v2_cb.py index e4204c36..7836f7fa 100644 --- a/tests/clients/test_ngsi_v2_cb.py +++ b/tests/clients/test_ngsi_v2_cb.py @@ -11,6 +11,8 @@ import paho.mqtt.client as mqtt from datetime import datetime, timedelta + +import requests from requests import RequestException from filip.models.base import FiwareHeader from filip.utils.simple_ql import QueryString @@ -216,7 +218,10 @@ def test_entity_operations(self): fiware_header=self.fiware_header) as client: client.post_entity(entity=self.entity, update=True) res_entity = client.get_entity(entity_id=self.entity.id) - client.get_entity(entity_id=self.entity.id, attrs=['temperature']) + self.assertEqual(res_entity, + client.get_entity( + entity_id=self.entity.id, + attrs=list(res_entity.get_attribute_names()))) self.assertEqual(client.get_entity_attributes( entity_id=self.entity.id), res_entity.get_properties( response_format='dict')) @@ -229,6 +234,164 @@ def test_entity_operations(self): client.update_entity(entity=res_entity) self.assertEqual(client.get_entity(entity_id=self.entity.id), res_entity) + # delete attribute + res_entity.delete_attributes(attrs={'pressure': ContextAttribute( + type='Number', value=1050)}) + client.post_entity(entity=res_entity, update=True) + self.assertEqual(client.get_entity(entity_id=self.entity.id), + res_entity) + + @clean_test(fiware_service=settings.FIWARE_SERVICE, + fiware_servicepath=settings.FIWARE_SERVICEPATH, + cb_url=settings.CB_URL) + def test_entity_update(self): + """ + Test different ways (post, update, override, patch) to update entity + Both with the update scenario + 1) append attribute + 2) update existing attribute value + 1) delete attribute + + Returns: + + """ + with ContextBrokerClient( + url=settings.CB_URL, + fiware_header=self.fiware_header) as client: + entity_init = self.entity.model_copy(deep=True) + attr_init = entity_init.get_attribute("temperature") + attr_init.metadata = { + "metadata_init": { + "type": "Text", + "value": "something"} + } + attr_append = NamedContextAttribute(**{ + "name": 'pressure', + "type": 'Number', + "value": 1050}) + entity_init.update_attribute(attrs=[attr_init]) + + # Post + if "post": + client.post_entity(entity=entity_init, update=True) + entity_post = entity_init.model_copy(deep=True) + # 1) append attribute + entity_post.add_attributes(attrs=[attr_append]) + client.post_entity(entity=entity_post, patch=True) + self.assertEqual(client.get_entity(entity_id=entity_post.id), + entity_post) + # 2) update existing attribute value + attr_append_update = NamedContextAttribute(**{ + "name": 'pressure', + "type": 'Number', + "value": 2050}) + entity_post.update_attribute(attrs=[attr_append_update]) + client.post_entity(entity=entity_post, patch=True) + self.assertEqual(client.get_entity(entity_id=entity_post.id), + entity_post) + # 3) delete attribute + entity_post.delete_attributes(attrs=[attr_append]) + client.post_entity(entity=entity_post, update=True) + self.assertEqual(client.get_entity(entity_id=entity_post.id), + entity_post) + clear_all(fiware_header=self.fiware_header, + cb_url=settings.CB_URL) + + # update_entity() + if "update_entity": + client.post_entity(entity=entity_init, update=True) + entity_update = entity_init.model_copy(deep=True) + # 1) append attribute + entity_update.add_attributes(attrs=[attr_append]) + # change the value of existing attributes + entity_update.temperature.value = 30 + with self.assertRaises(requests.RequestException): + client.update_entity(entity=entity_update, + append_strict=True) + entity_updated = client.get_entity(entity_id=entity_update.id) + self.assertEqual(entity_updated.get_attribute_names(), + entity_update.get_attribute_names()) + self.assertNotEqual(entity_updated.temperature.value, + entity_update.temperature.value) + # change back the value + entity_update.temperature.value = 20.0 + # 2) update existing attribute value + attr_append_update = NamedContextAttribute(**{ + "name": 'pressure', + "type": 'Number', + "value": 2050}) + entity_update.update_attribute(attrs=[attr_append_update]) + client.update_entity(entity=ContextEntity( + **{ + "id": entity_update.id, + "type": entity_update.type, + "pressure": { + "type": 'Number', + "value": 2050 + } + } + )) + self.assertEqual(client.get_entity(entity_id=entity_update.id), + entity_update) + # 3) delete attribute + entity_update.delete_attributes(attrs=[attr_append]) + client.update_entity(entity=entity_update) + self.assertNotEqual(client.get_entity(entity_id=entity_update.id), + entity_update) + clear_all(fiware_header=self.fiware_header, + cb_url=settings.CB_URL) + + # override_entity() + if "override_entity": + client.post_entity(entity=entity_init, update=True) + entity_override = entity_init.model_copy(deep=True) + # 1) append attribute + entity_override.add_attributes(attrs=[attr_append]) + client.override_entity(entity=entity_override) + self.assertEqual(client.get_entity(entity_id=entity_override.id), + entity_override) + # 2) update existing attribute value + attr_append_update = NamedContextAttribute(**{ + "name": 'pressure', + "type": 'Number', + "value": 2050}) + entity_override.update_attribute(attrs=[attr_append_update]) + client.override_entity(entity=entity_override) + self.assertEqual(client.get_entity(entity_id=entity_override.id), + entity_override) + # 3) delete attribute + entity_override.delete_attributes(attrs=[attr_append]) + client.override_entity(entity=entity_override) + self.assertEqual(client.get_entity(entity_id=entity_override.id), + entity_override) + clear_all(fiware_header=self.fiware_header, + cb_url=settings.CB_URL) + + # patch_entity + if "patch_entity": + client.post_entity(entity=entity_init, update=True) + entity_patch = entity_init.model_copy(deep=True) + # 1) append attribute + entity_patch.add_attributes(attrs=[attr_append]) + client.patch_entity(entity=entity_patch) + self.assertEqual(client.get_entity(entity_id=entity_patch.id), + entity_patch) + # 2) update existing attribute value + attr_append_update = NamedContextAttribute(**{ + "name": 'pressure', + "type": 'Number', + "value": 2050}) + entity_patch.update_attribute(attrs=[attr_append_update]) + client.patch_entity(entity=entity_patch) + self.assertEqual(client.get_entity(entity_id=entity_patch.id), + entity_patch) + # 3) delete attribute + entity_patch.delete_attributes(attrs=[attr_append]) + client.patch_entity(entity=entity_patch) + self.assertEqual(client.get_entity(entity_id=entity_patch.id), + entity_patch) + clear_all(fiware_header=self.fiware_header, + cb_url=settings.CB_URL) @clean_test(fiware_service=settings.FIWARE_SERVICE, fiware_servicepath=settings.FIWARE_SERVICEPATH,