diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/controllers/default_controller.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/controllers/default_controller.py index 27c4b6424bd1e3000e78db0ef656e7b7cdf547a2..29839084d1420d7243c9c1bd655a8f8cdf52a5cf 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/controllers/default_controller.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/controllers/default_controller.py @@ -7,6 +7,7 @@ from published_apis.vendor_specific import find_attribute_in_body, vendor_specif from ..core.responses import bad_request_error from ..core.serviceapidescriptions import PublishServiceOperations +from ..core.serviceapidescriptions import return_negotiated_supp_feat_dict from ..core.validate_user import ControlAccess from ..models.service_api_description import ServiceAPIDescription # noqa: E501 @@ -88,7 +89,7 @@ def apf_id_service_apis_post(apf_id, body): # noqa: E501 invalid_params=[{"param": "supportedFeatures", "reason": "not defined"}] ) - supp_feat_dict = ServiceAPIDescription.return_supp_feat_dict( + supp_feat_dict = return_negotiated_supp_feat_dict( body['supportedFeatures']) vendor_specific = [] diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/serviceapidescriptions.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/serviceapidescriptions.py index d5b451756eab0773972e3c438c065068cddfc472..658957efe4602fe98d6151662c35d52ec95a24af 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/serviceapidescriptions.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/serviceapidescriptions.py @@ -21,12 +21,33 @@ from .responses import ( unauthorized_error ) + +TOTAL_FEATURES = 10 +SUPPORTED_FEATURES_HEX = "120" + publisher_ops = Publisher() service_api_not_found_message = "Service API not found" +def return_negotiated_supp_feat_dict(supp_feat): + final_supp_feat = bin(int(supp_feat, 16) & int(SUPPORTED_FEATURES_HEX, 16))[2:].zfill(TOTAL_FEATURES)[::-1] + + return { + "ApiSupportedFeaturePublishing": True if final_supp_feat[0] == "1" else False, + "PatchUpdate": True if final_supp_feat[1] == "1" else False, + "ExtendedIntfDesc": True if final_supp_feat[2] == "1" else False, + "MultipleCustomOperations": True if final_supp_feat[3] == "1" else False, + "ProtocDataFormats_Ext1": True if final_supp_feat[4] == "1" else False, + "ApiStatusMonitoring": True if final_supp_feat[5] == "1" else False, + "EdgeApp_2": True if final_supp_feat[6] == "1" else False, + "RNAA": True if final_supp_feat[7] == "1" else False, + "VendorExt": True if final_supp_feat[8] == "1" else False, + "SliceBasedAPIExposure": True if final_supp_feat[9] == "1" else False, + "Final": hex(int(final_supp_feat[::-1], 2))[2:].zfill(3) + } + class PublishServiceOperations(Resource): def check_apf(self, apf_id): @@ -126,7 +147,7 @@ class PublishServiceOperations(Resource): vendor_specific, serviceapidescription_dict) rec.update(serviceapidescription_dict) - if not ServiceAPIDescription.return_supp_feat_dict(rec.get("supported_features"))["ApiStatusMonitoring"] and rec.get("api_status", None) is not None: + if not return_negotiated_supp_feat_dict(rec.get("supported_features"))["ApiStatusMonitoring"] and rec.get("api_status", None) is not None: return bad_request_error( detail="Set apiStatus with apiStatusMonitoring feature inactive at supportedFeatures if not allowed", cause="apiStatus can't be set if apiStatusMonitoring is inactive", @@ -296,8 +317,9 @@ class PublishServiceOperations(Resource): service_api_description["apf_id"] = serviceapidescription_old["apf_id"] service_api_description["onboarding_date"] = serviceapidescription_old["onboarding_date"] service_api_description["api_id"] = serviceapidescription_old["api_id"] + service_api_description["supported_features"] = return_negotiated_supp_feat_dict(service_api_description["supported_features"])["Final"] - if not ServiceAPIDescription.return_supp_feat_dict(service_api_description.get("supported_features"))["ApiStatusMonitoring"] and service_api_description.get("api_status", None) is not None: + if not return_negotiated_supp_feat_dict(service_api_description.get("supported_features"))["ApiStatusMonitoring"] and service_api_description.get("api_status", None) is not None: return bad_request_error( detail="Set apiStatus with apiStatusMonitoring feature inactive at supportedFeatures if not allowed", cause="apiStatus can't be set if apiStatusMonitoring is inactive", @@ -382,11 +404,14 @@ class PublishServiceOperations(Resource): patch_service_api_description = patch_service_api_description.to_dict() api_status = patch_service_api_description.get("api_status", None) + supported_features = patch_service_api_description.get("supported_features", None) patch_service_api_description = clean_empty(patch_service_api_description) if api_status: patch_service_api_description["api_status"]=api_status + if supported_features: + patch_service_api_description["supported_features"] = return_negotiated_supp_feat_dict(patch_service_api_description["supported_features"])["Final"] - if not ServiceAPIDescription.return_supp_feat_dict(serviceapidescription_old.get("supported_features"))["ApiStatusMonitoring"] and patch_service_api_description.get("api_status", None) is not None: + if not return_negotiated_supp_feat_dict(serviceapidescription_old.get("supported_features"))["ApiStatusMonitoring"] and patch_service_api_description.get("api_status", None) is not None: return bad_request_error( detail="Set apiStatus with apiStatusMonitoring feature inactive at supportedFeatures if not allowed", cause="apiStatus can't be set if apiStatusMonitoring is inactive", @@ -471,7 +496,7 @@ class PublishServiceOperations(Resource): def service_api_availability_event(self, service_api_description): service_api_status = "" - if ServiceAPIDescription.return_supp_feat_dict(service_api_description.get("supportedFeatures"))["ApiStatusMonitoring"]: + if return_negotiated_supp_feat_dict(service_api_description.get("supportedFeatures"))["ApiStatusMonitoring"]: current_app.logger.info( "ApiStatusMonitoring active") if service_api_description.get("apiStatus") is None or len(service_api_description.get("apiStatus").get("aefIds")) > 0: diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/service_api_description.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/service_api_description.py index 0111b908811623633bfc80232974455b322d950f..3f97250d39f8451513b1ff6905f7dfff8a4258b1 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/service_api_description.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/service_api_description.py @@ -87,25 +87,6 @@ class ServiceAPIDescription(Model): self._ccf_id = ccf_id self._api_prov_name = api_prov_name - @classmethod - def return_supp_feat_dict(cls, supp_feat): - TOTAL_FEATURES = 9 - supp_feat_in_hex = int(supp_feat, 16) - supp_feat_in_bin = bin(supp_feat_in_hex)[2:].zfill(TOTAL_FEATURES)[::-1] - - - return { - "ApiSupportedFeaturePublishing": True if supp_feat_in_bin[0] == "1" else False, - "PatchUpdate": True if supp_feat_in_bin[1] == "1" else False, - "ExtendedIntfDesc": True if supp_feat_in_bin[2] == "1" else False, - "MultipleCustomOperations": True if supp_feat_in_bin[3] == "1" else False, - "ProtocDataFormats_Ext1": True if supp_feat_in_bin[4] == "1" else False, - "ApiStatusMonitoring": True if supp_feat_in_bin[5] == "1" else False, - "EdgeApp_2": True if supp_feat_in_bin[6] == "1" else False, - "RNAA": True if supp_feat_in_bin[7] == "1" else False, - "VendorExt": True if supp_feat_in_bin[8] == "1" else False - } - @classmethod def from_dict(cls, dikt) -> 'ServiceAPIDescription': diff --git a/tests/features/Api Status/api_status.robot b/tests/features/Api Status/api_status.robot index 9e9f92f9a7cccaa4010502e9e13810b177670a20..d4798e765dc31f7b8df6fca41e1b2ae4dba095d4 100644 --- a/tests/features/Api Status/api_status.robot +++ b/tests/features/Api Status/api_status.robot @@ -1155,7 +1155,7 @@ Update published API with apiStatus empty and apiStatusMonitoring active ${service_api_description_modified}= Create Service Api Description ... service_1 ... aef_id=${aef_ids} - ... supported_features=20 + ... supported_features=020 ... api_status=${aef_empty_list} ${resp}= Put Request Capif ... ${resource_url.path} @@ -1260,7 +1260,7 @@ Update published API with apiStatus only aef2 and apiStatusMonitoring active ${service_api_description_modified}= Create Service Api Description ... service_1 ... aef_id=${aef_ids} - ... supported_features=20 + ... supported_features=020 ... api_status=${aef_id_2} ${resp}= Put Request Capif ... ${resource_url.path} @@ -1357,7 +1357,7 @@ Published API without aefs available updated to one aef available ${service_api_description_modified}= Create Service Api Description ... service_1 ... aef_id=${aef_ids} - ... supported_features=20 + ... supported_features=020 ... api_status=${aef_id_2} ${resp}= Put Request Capif ... ${resource_url.path} diff --git a/tests/features/Event Filter/event_filter.robot b/tests/features/Event Filter/event_filter.robot index 95f9431041ef76ebe83d395e1787034de61fb03e..9853646b4fdf8acda651790e2ae0053694a18499 100644 --- a/tests/features/Event Filter/event_filter.robot +++ b/tests/features/Event Filter/event_filter.robot @@ -84,7 +84,7 @@ Invoker subscribed to SERVICE_API_AVAILABLE, SERVICE_API_UNAVAILABLE and SERVICE ${service_api_description_modified}= Create Service Api Description ... service_1 ... aef_id=${aef_ids} - ... supported_features=20 + ... supported_features=020 ... api_status=${aef_ids} ${resp}= Put Request Capif ... ${resource_url.path} diff --git a/tests/libraries/api_publish_service/bodyRequests.py b/tests/libraries/api_publish_service/bodyRequests.py index 046e8e18f5e9d2f6d94b8af7de8c5dde24db7c3c..5f969a548f9fa8e5dd578933dc97f3e92610ae63 100644 --- a/tests/libraries/api_publish_service/bodyRequests.py +++ b/tests/libraries/api_publish_service/bodyRequests.py @@ -1,6 +1,6 @@ def create_service_api_description(api_name="service_1", aef_id="aef_id", - supported_features="0", + supported_features="000", vendor_specific_service_api_description=None, vendor_specific_aef_profile=None, api_status=None,