diff --git a/MEC010p2/MEPM/PKGM/AppPkgMgt.robot b/MEC010p2/MEPM/PKGM/AppPkgMgt.robot index 2da898f8624d82ae1aeb7688836df0cb39c1414b..711a7e5605178c7b2d55176b0f244093319dac47 100644 --- a/MEC010p2/MEPM/PKGM/AppPkgMgt.robot +++ b/MEC010p2/MEPM/PKGM/AppPkgMgt.robot @@ -8,7 +8,7 @@ Library REST ${MEPM_SCHEMA}://${MEPM_HOST}:${MEPM_PORT} ssl_verify=fa Library BuiltIn Library OperatingSystem Resource ../../../pics.txt - +Library libraries/Server.py *** Test Cases *** TC_MEC_MEC010p2_MEPM_PKGM_001_01_OK @@ -28,7 +28,7 @@ TC_MEC_MEC010p2_MEPM_PKGM_001_01_OK [Teardown] Delete an individual APP Package identified by ID ${APP_PKG_ID} -TC_MEC_MEC010p2_MEPM_PKGM_002_01_OK +TC_MEC_MEC010p2_MEPM_PKGM_001_02_OK [Documentation] TP_MEC_MEC010p2_MEPM_PKGM_002_01_OK ... Check that MEPM returns the list of on-boarded App Packages when requested - Note 3 ... ETSI GS MEC 010-2 3.1.1, clause 7.3.1.3.1 @@ -187,7 +187,7 @@ TC_MEC_MEC010p2_MEPM_PKGM_006_OK Delete a subscription ${SUBSCRIPTION_ID} Check HTTP Response Status Code Is 204 -TC_MEC_MEC010p2_MEPM_PKGM_006_OK +TC_MEC_MEC010p2_MEPM_PKGM_006_NF [Documentation] TP_MEC_MEC010p2_MEPM_PKGM_006_NF ... Check that MEPM service sends an error ... when it receives a deletion request for a subscription on AppPackages @@ -198,8 +198,177 @@ TC_MEC_MEC010p2_MEPM_PKGM_006_OK Delete a subscription ${NON_EXISTENT_SUBSCRIPTION_ID} Check HTTP Response Status Code Is 404 + +TC_MEC_MEC010p2_MEPM_PKGM_007_OK + [Documentation] TP_MEC_MEC010p2_MEPM_PKGM_007_OK + ... Check that the MEPM service sends a application package notification + ... if the MEPM service has an associated subscription and the event is generated + ... ETSI GS MEC 010-2 3.1.1, clause 7.3.5.3.1, + ... ETSI GS MEC 010-2 3.1.1, clause 6.2.3.6.2 ##AppPkgNotification + [Tags] PIC_APP_PACKAGE_NOTIFICATIONS + [Setup] Create a subscription AppPkgSubscription.json + Set Suite Variable ${SUBSCRIPTION_ID} ${response['body']['id']} + Spawn Notification Server AppPkgNotification + Validate Json AppPkgNotification.schema.json ${payload_notification} + [TearDown] Delete a subscription ${SUBSCRIPTION_ID} + + + + +TC_MEC_MEC010p2_MEPM_PKGM_008_NA + [Documentation] TP_MEC_MEC010p2_MEPM_PKGM_008_NA + ... Check that MEPM responds with an error when it receives + ... a POST request referring an application descriptor AppD + ... ETSI GS MEC 010-2 3.1.1, clause 7.3.6.3.1 + + [Tags] PIC_APP_PACKAGE_MANAGEMENT + [Setup] Create new App Package CreateAppPackage.json + Set Suite Variable ${APP_PKG_ID} ${response['body']['id']} + Set Suite Variable ${APPD_ID} ${response['body']['appDId']} + Post an AppD identified by ${APP_PKG_ID} + Check HTTP Response Status Code Is 405 + [Teardown] Delete an individual APP Package identified by ID ${APP_PKG_ID} + + + + + +TC_MEC_MEC010p2_MEPM_PKGM_009_OK + [Documentation] TP_MEC_MEC010p2_MEPM_PKGM_009_OK + ... Check that MEPM returns the Application Descriptor contained on an on-boarded Application Package when requested + ... ETSI GS MEC 010-2 3.1.1, clause 7.3.6.3.2 + ... ETSI GS MEC 010-2 3.1.1, clause 6.2.1.2.2 ##AppD + [Tags] PIC_APP_PACKAGE_MANAGEMENT + [Setup] Create new App Package CreateAppPackage.json + Set Suite Variable ${APP_PKG_ID} ${response['body']['id']} + Set Suite Variable ${ON_BOARDED_APPD_ID} ${response['body']['appDId']} + Get an AppD identified by ${ON_BOARDED_APPD_ID} + Check HTTP Response Status Code Is 200 + [Teardown] Delete an individual APP Package identified by ID ${APP_PKG_ID} + + +TC_MEC_MEC010p2_MEPM_PKGM_009_NF + [Documentation] TP_MEC_MEC010p2_MEPM_PKGM_009_NF + ... Check that MEPM responds with an error when it receives + ... a request for returning a App Descriptor referred with a wrong App Package ID + ... ETSI GS MEC 010-2 3.1.1, clause 7.3.6.3.2 + [Tags] PIC_APP_PACKAGE_MANAGEMENT + [Setup] Delete an AppD by ID ${NON_EXISTENT_APP_PKG_ID} + Get an AppD identified by ${NON_EXISTENT_APP_PKG_ID} + Check HTTP Response Status Code Is 404 + + +TC_MEC_MEC010p2_MEPM_PKGM_010_FO + [Documentation] TP_MEC_MEC010p2_MEPM_PKGM_010_FO + ... Check that MEPM responds with an error when it receives + ... a PUT request referring an application descriptor AppD + ... ETSI GS MEC 010-2 3.1.1, clause 7.3.6.3.3 + [Tags] PIC_APP_PACKAGE_MANAGEMENT + [Setup] Create new App Package CreateAppPackage.json + Set Suite Variable ${APP_PKG_ID} ${response['body']['id']} + Set Suite Variable ${ON_BOARDED_APPD_ID} ${response['body']['appDId']} + Update an AppD identified by ${ON_BOARDED_APPD_ID} + Check HTTP Response Status Code Is 403 + [Teardown] Delete an individual APP Package identified by ID ${APP_PKG_ID} + + +TC_MEC_MEC010p2_MEPM_PKGM_011_NA + [Documentation] TP_MEC_MEC010p2_MEPM_PKGM_011_NA + ... Check that MEPM responds with an error when it receives + ... a DELETE request referring an application descriptor AppD + ... ETSI GS MEC 010-2 3.1.1, clause 7.3.6.3.4 + [Tags] PIC_APP_PACKAGE_MANAGEMENT + [Setup] Create new App Package CreateAppPackage.json + Set Suite Variable ${APP_PKG_ID} ${response['body']['id']} + Delete an AppD by ID ${APP_PKG_ID} + Check HTTP Response Status Code Is 405 + [Teardown] Delete an individual APP Package identified by ID ${APP_PKG_ID} + + + +TC_MEC_MEC010p2_MEPM_PKGM_012_01_OK + [Documentation] TP_MEC_MEC010p2_MEPM_PKGM_012_01_OK + ... Check that MEPM fetches the on-boarded application package content identified by appPkgId when requested + ... ETSI GS MEC 010-2 3.1.1, clause 7.3.7.3.2 + [Tags] PIC_APP_PACKAGE_MANAGEMENT + [Setup] Create new App Package CreateAppPackage.json + Set Suite Variable ${APP_PKG_ID} ${response['body']['id']} + GET all app Packages content by appPkgId ${APP_PKG_ID} + Check HTTP Response Status Code Is 200 + [Teardown] Delete an individual APP Package identified by ID ${APP_PKG_ID} + +TC_MEC_MEC010p2_MEPM_PKGM_012_02_OK + [Documentation] TP_MEC_MEC010p2_MEPM_PKGM_012_02_OK + ... heck that MEPM fetches the on-boarded application package content identified by appDId when requested + ... ETSI GS MEC 010-2 3.1.1, clause 7.3.7.3.2 + [Tags] PIC_APP_PACKAGE_MANAGEMENT + [Setup] Create new App Package CreateAppPackage.json + Set Suite Variable ${APP_PKG_ID} ${response['body']['id']} + Set Suite Variable ${ON_BOARDED_APPD_ID} ${response['body']['appDId']} + GET all app Packages content by appPkgId ${ON_BOARDED_APPD_ID} + Check HTTP Response Status Code Is 200 + [Teardown] Delete an individual APP Package identified by ID ${APP_PKG_ID} + + + +TC_MEC_MEC010p2_MEPM_PKGM_012_01_NF + [Documentation] TP_MEC_MEC010p2_MEPM_PKGM_012_01_NF + ... Check that MEPM fetches the on-boarded application package content identified by appPkgId when requested + ... ETSI GS MEC 010-2 3.1.1, clause 7.3.7.3.2 + [Tags] PIC_APP_PACKAGE_MANAGEMENT + [Setup] Delete an individual APP Package identified by ID ${NON_EXISTENT_APP_PKG_ID} + GET all app Packages content by appPkgId ${NON_EXISTENT_APP_PKG_ID} + Check HTTP Response Status Code Is 404 + + + +TC_MEC_MEC010p2_MEPM_PKGM_012_02_NF + [Documentation] TP_MEC_MEC010p2_MEPM_PKGM_012_02_NF + ... Check that MEPM service sends an error when it receives a query with an application package with a wrong identifier + ... ETSI GS MEC 010-2 3.1.1, clause 7.3.7.3.2 + [Tags] PIC_APP_PACKAGE_MANAGEMENT + [Setup] Delete an individual APP Package identified by ID ${NON_EXISTENT_APPD_ID} + GET all app Packages content by appPkgId ${NON_EXISTENT_APPD_ID} + Check HTTP Response Status Code Is 404 + *** Keywords *** +Get an AppD identified by + [Arguments] ${appDId} + Log Getting App descriptor for App Package + Set Headers {"Accept":"${ACCEPTED_CONTENT_TYPE}"} + Set Headers {"Authorization":"${TOKEN}"} + Get ${apiRoot}/${apiName}/${apiVersion}/app_packages/${appDId}/appd + ${output}= Output response + Set Suite Variable ${response} ${output} + +Post an AppD identified by + [Arguments] ${appDId} + Log Getting App descriptor for App Package + Set Headers {"Accept":"${ACCEPTED_CONTENT_TYPE}"} + Set Headers {"Authorization":"${TOKEN}"} + Post ${apiRoot}/${apiName}/${apiVersion}/app_packages/${appDId}/appd + ${output}= Output response + Set Suite Variable ${response} ${output} + +Update an AppD identified by + [Arguments] ${appDId} + Log Getting App descriptor for App Package + Set Headers {"Accept":"${ACCEPTED_CONTENT_TYPE}"} + Set Headers {"Authorization":"${TOKEN}"} + Put ${apiRoot}/${apiName}/${apiVersion}/app_packages/${appDId}/appd + ${output}= Output response + Set Suite Variable ${response} ${output} + +Delete an AppD by ID + [Arguments] ${identifier} + Set Headers {"Accept":"application/json"} + Set Headers {"Content-Type":"*/*"} + Set Headers {"Authorization":"${TOKEN}"} + Delete ${apiRoot}/${apiName}/${apiVersion}/app_packages/${identifier}/appd + ${output}= Output response + Set Suite Variable ${response} ${output} + Create new App Package [Arguments] ${content} Set Headers {"Accept":"*/*"} @@ -211,7 +380,6 @@ Create new App Package ${output}= Output response Set Suite Variable ${response} ${output} - GET all app Packages Set Headers {"Accept":"application/json"} Set Headers {"Content-Type":"*/*"} @@ -220,7 +388,6 @@ GET all app Packages ${output}= Output response Set Suite Variable ${response} ${output} - GET all app Packages with filter [Arguments] ${key} ${value} Log Getting all App Packages using filtering parameters @@ -242,6 +409,17 @@ Get an individual APP Package identified by ID Set Suite Variable ${response} ${output} + +GET all app Packages content by appPkgId + [Arguments] ${identifier} + Set Headers {"Accept":"application/zip"} + Set Headers {"Content-Type":"*/*"} + Set Headers {"Authorization":"${TOKEN}"} + Get ${apiRoot}/${apiName}/${apiVersion}/app_packages/${identifier}/package_content + ${output}= Output response + Set Suite Variable ${response} ${output} + + Create a subscription [Arguments] ${content} Set Headers {"Accept":"application/json"} @@ -293,8 +471,6 @@ Delete an individual APP Package identified by ID Spawn Notification Server - [Arguments] ${host} ${port} ${timeout} ${method} ${endpoint} ${notification_content} ${autosent_notification} - ${file}= Catenate SEPARATOR= jsons/ ${notification_content} .json - ${body}= Get File ${file} - #Spawn Web Server ${host} ${port} ${timeout} ${method} ${endpoint} ${body} ${autosent_notification} - + [Arguments] ${payload_notification} + ${output} Spawn Web Server ${NOTIFICATION_SERVER_IP} ${NOTIFICATION_SERVER_PORT} ${NOTIFICATION_SERVER_TIMEOUT} ${NOTIFICATION_SERVER_HTTP_METHOD} ${NOTIFICATION_SERVER_URI} ${payload_notification} + Set Suite Variable ${payload_notification} ${output} diff --git a/MEC010p2/MEPM/PKGM/environment/variables.txt b/MEC010p2/MEPM/PKGM/environment/variables.txt index fc95e302a32d96786b394947f023c44679d2213e..fa58be8ac3f21bfb6702554316d42d18e23337bd 100644 --- a/MEC010p2/MEPM/PKGM/environment/variables.txt +++ b/MEC010p2/MEPM/PKGM/environment/variables.txt @@ -23,4 +23,12 @@ ${FILTER_VALUE} ENABLED ${NON_EXISTENT_APP_PKG_ID} NON_EXISTENT_APP_PKG_ID ${NON_EXISTENT_SUBSCRIPTION_ID} NON_EXISTENT_SUBSCRIPTION_ID ${NON_EXISTENT_APPD_ID} NON_EXISTENT_APPD_ID -${ONBOARDING_STATE} CREATED \ No newline at end of file +${ONBOARDING_STATE} CREATED + + +##Notification Server variables +${NOTIFICATION_SERVER_IP} 127.0.0.1 +${NOTIFICATION_SERVER_PORT} 8888 +${NOTIFICATION_SERVER_HTTP_METHOD} POST +${NOTIFICATION_SERVER_URI} /callback_url +${NOTIFICATION_SERVER_TIMEOUT} 5 \ No newline at end of file diff --git a/MEC010p2/MEPM/PKGM/jsons/AppPkgNotification.json b/MEC010p2/MEPM/PKGM/jsons/AppPkgNotification.json new file mode 100644 index 0000000000000000000000000000000000000000..6e1ae305947d2f739243b7a90d715af8c45d6c0b --- /dev/null +++ b/MEC010p2/MEPM/PKGM/jsons/AppPkgNotification.json @@ -0,0 +1,17 @@ +{ + "id": "1234", + "notificationType": "AppPackageOnBoarded", + "subscriptionId": "1234", + "timeStamp": { + "seconds": 1234, + "nanoSeconds": 1234 + }, + "appPkgId": "appPkgId", + "appDId": "appDId", + "operationalState": "ENABLED", + "_links": { + "subscription": { + "href": "someuri/url" + } + } +} \ No newline at end of file diff --git a/MEC010p2/MEPM/PKGM/libraries/Server.py b/MEC010p2/MEPM/PKGM/libraries/Server.py new file mode 100644 index 0000000000000000000000000000000000000000..c983c3b78a770fa8b41bb3976ebbd5543d739337 --- /dev/null +++ b/MEC010p2/MEPM/PKGM/libraries/Server.py @@ -0,0 +1,144 @@ +#!/usr/bin/python3 + +from http.server import BaseHTTPRequestHandler, HTTPServer +import json, os +import logging + +# Library version +__version__ = '0.0.1' + +def import_notification_json(subscription_type): + notification_type = subscription_type.split("Subscription")[0] + file_path = "./jsons/"+notification_type+".json" + logging.info(file_path) + logging.info(os.listdir()) + try: + with open(file_path, 'r') as json_file: + # Load the JSON data + data = json.load(json_file) + logging.info(data) + return data + except FileNotFoundError: + logging.error(f"Error: File not found at {file_path}") + + +class Server ( object ): + + ROBOT_LIBRARY_VERSION = '0.0.1' + + def spawn_web_server (self, host="127.0.0.1", port=8080, timeout=15, method="POST", endpoint="/callback_url", resp_body=None): + + class GET_Server(BaseHTTPRequestHandler): + + def __call__(self, *args, **kwargs): + """Handle a request.""" + super().__init__(*args, **kwargs) + + def __init__(self, endpoint, resp_body): + self.resp_body = resp_body + self.endpoint = endpoint + + def do_GET(self): + self.send_response(200) + self.send_header('Content-Type', 'application/json') + self.end_headers() + if self.path == self.endpoint: + self.wfile.write(json.dumps(self.resp_body).encode(encoding='utf_8')) + else: + self.wfile.write(json.dumps("wrong endpoint").encode(encoding='utf_8')) + + class POST_Server(BaseHTTPRequestHandler): + + def __call__(self, *args, **kwargs): + """Handle a request.""" + super().__init__(*args, **kwargs) + + def __init__(self, endpoint, resp_body): + self.resp_body = resp_body + self.endpoint = endpoint + self.req_body = None + + + def do_POST(self): + self.send_response(200) + self.send_header('Content-Type', 'application/json') + self.end_headers() + + #if self.path == self.endpoint: + # self.wfile.write(json.dumps(self.resp_body).encode(encoding='utf_8')) + #else: + # self.wfile.write(json.dumps("wrong endpoint").encode(encoding='utf_8')) + + content_len = int(self.headers.get('Content-Length')) + post_body = self.rfile.read(content_len) + self.req_body=post_body + + def get_req_body(self): + return self.req_body + + def get_resp_body(self): + return self.resp_body + + + class PUT_Server(BaseHTTPRequestHandler): + + def __call__(self, *args, **kwargs): + """Handle a request.""" + super().__init__(*args, **kwargs) + + def __init__(self, endpoint, resp_body): + self.resp_body = resp_body + self.endpoint = endpoint + + def do_PUT(self): + self.send_response(200) + self.send_header('Content-Type', 'application/json') + self.end_headers() + if self.path == self.endpoint: + self.wfile.write(json.dumps(self.resp_body).encode(encoding='utf_8')) + else: + self.wfile.write(json.dumps("wrong endpoint").encode(encoding='utf_8')) + + class DELETE_Server(BaseHTTPRequestHandler): + + def __call__(self, *args, **kwargs): + """Handle a request.""" + super().__init__(*args, **kwargs) + + def __init__(self, endpoint, resp_body): + self.resp_body = resp_body + self.endpoint = endpoint + + def do_DELETE(self): + self.send_response(200) + self.send_header('Content-Type', 'application/json') + self.end_headers() + if self.path == self.endpoint: + self.wfile.write(json.dumps(self.resp_body).encode(encoding='utf_8')) + else: + self.wfile.write(json.dumps("wrong endpoint").encode(encoding='utf_8')) + + if method == "GET": + self.handler = GET_Server(endpoint, resp_body) + elif method == "POST": + self.handler = POST_Server(endpoint, resp_body) + elif method == "PUT": + self.handler = PUT_Server(endpoint, resp_body) + elif method == "DELETE": + self.handler = DELETE_Server(endpoint, resp_body) + else: + logging.info("Error, unknown endpoint") + exit(1) + + self.app = HTTPServer((host, int(port)), self.handler) + self.app.timeout = int(timeout) + + + self.app.handle_request() + self.app.server_close() + logging.info(self.handler.get_resp_body()) + if(self.handler.get_req_body()!=None): + return json.loads(self.handler.get_req_body().decode("windows-1252")) + notification_json= import_notification_json(self.handler.get_resp_body()) + return notification_json + diff --git a/MEC010p2/MEPM/PKGM/libraries/__pycache__/Server.cpython-39.pyc b/MEC010p2/MEPM/PKGM/libraries/__pycache__/Server.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6174a8848396b041de13ac5e846ee7d788db8b7b Binary files /dev/null and b/MEC010p2/MEPM/PKGM/libraries/__pycache__/Server.cpython-39.pyc differ diff --git a/MEC010p2/MEPM/PKGM/schemas/AppPkgNotification.schema.json b/MEC010p2/MEPM/PKGM/schemas/AppPkgNotification.schema.json new file mode 100644 index 0000000000000000000000000000000000000000..a021991e4d5ddd2366e54411a5feadc59eeda31c --- /dev/null +++ b/MEC010p2/MEPM/PKGM/schemas/AppPkgNotification.schema.json @@ -0,0 +1,68 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "notificationType": { + "type": "string" + }, + "subscriptionId": { + "type": "string" + }, + "timeStamp": { + "type": "object", + "properties": { + "seconds": { + "type": "integer" + }, + "nanoSeconds": { + "type": "integer" + } + }, + "required": [ + "seconds", + "nanoSeconds" + ] + }, + "appPkgId": { + "type": "string" + }, + "appDId": { + "type": "string" + }, + "operationalState": { + "type": "string" + }, + "_links": { + "type": "object", + "properties": { + "subscription": { + "type": "object", + "properties": { + "href": { + "type": "string" + } + }, + "required": [ + "href" + ] + } + }, + "required": [ + "subscription" + ] + } + }, + "required": [ + "id", + "notificationType", + "subscriptionId", + "timeStamp", + "appPkgId", + "appDId", + "operationalState", + "_links" + ] +} \ No newline at end of file