From: BjornMagnussonXA Date: Thu, 22 Oct 2020 22:38:18 +0000 (+0200) Subject: A1 simulator for STD 2.0.0 X-Git-Tag: 2.1.0~1 X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?p=sim%2Fa1-interface.git;a=commitdiff_plain;h=967079bda24e7a0f5268728f1474ce0ddc9e52d0 A1 simulator for STD 2.0.0 Issue-ID: NONRTRIC-303 Signed-off-by: BjornMagnussonXA Change-Id: Ic73473cc4e1c3502cc15495169e1279a5ccd8585 --- diff --git a/.gitignore b/.gitignore index 65910c3..50aeff4 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,7 @@ docs/_build/ # IDE .project .vscode + +.coverage +coverage.xml +htmlcov/ diff --git a/near-rt-ric-simulator/README.md b/near-rt-ric-simulator/README.md index fc67bb1..b3c35d2 100644 --- a/near-rt-ric-simulator/README.md +++ b/near-rt-ric-simulator/README.md @@ -7,6 +7,7 @@ The simulator supports multiple A1 interface versions (version of the open API y | --------------------- | ------------------- | | OSC 2.1.0, | OSC\_2.1.0 | | A1 Standard 1.1.3, | STD\_1.1.3 | +| A1 Standard 2.0.0, | STD\_2.0.0 | All versions are supported by the same container, see section 'Configuring the simulator' below for details about how to the start the simulator with the intended version id. @@ -87,7 +88,7 @@ URIs for A1: | PUT a policy instance(create or update it) | http://localhost:8085/A1-P/v1/policies/{policyId} | | GET a policy | http://localhost:8085/A1-P/v1/policies/{policyId} | | DELETE a policy instance | http://localhost:8085/A1-P/v1/policies/{policyId} | -| GET a policy status | http://localhost:8085/A1-P/v1/policies/{policyid} | +| GET a policy status | http://localhost:8085/A1-P/v1/policies/{policyid}/status | Swagger UI at: http://localhost:8085/A1-P/v1/ui/ For the documentation of the admin API, see [A1 Standard 1.1.3](https://docs.o-ran-sc.org/projects/o-ran-sc-sim-a1-interface/en/latest/simulator-api.html#a1-standard-1-1-3). @@ -105,6 +106,41 @@ URIs for admin operations: | POST, send status for policy | http://localhost:8085/sendstatus?policyid=<policyid> | | GET a counter
(counter-name: 'num\_instances', 'num\_types'(always 0), 'interface' or 'remote\_hosts') | http://localhost:8085/counter/<counter-name> | +# Supported operations in simulator A1 Standard 2.0.0 + +For the complete yaml specification, see [ORAN_A1-p_V2.0.0_api.yaml](../near-rt-ric-simulator/api/STD_2.0.0/ORAN_A1-p_V2.0.0_api.yaml). + +URIs for A1: +| Function | Path and parameters | +| --------------------- | ------------------- | +| GET all policy type identities | http://localhost:8085/A1-P/v2/policytypes | +| GET a policy type | http://localhost:8085/A1-P/v2/policytypes/{policyTypeId} | +| GET all policy identities | http://localhost:8085/A1-P/v2/policytypes/{policyTypeId}/policies | +| PUT a policy instance(create or update it) | http://localhost:8085/A1-P/v2/policytypes/{policyTypeId}/policies/{policyId} | +| GET a policy | http://localhost:8085/A1-P/v2/policytypes/{policyTypeId}/policies/{policyId} | +| DELETE a policy instance | http://localhost:8085/A1-P/v2/policytypes/{policyTypeId}/policies/{policyId} | +| GET a policy status | http://localhost:8085/A1-P/v2/policytypes/{policyTypeId}/policies/{policyid}/status | +Swagger UI at: http://localhost:8085/A1-P/v2/ui/ + +For the documentation of the admin API, see [A1 Standard 2.0.0](https://docs.o-ran-sc.org/projects/o-ran-sc-sim-a1-interface/en/latest/simulator-api.html#a1-standard-2-0-0). + +URIs for admin operations: +| Function | Path and parameters | +| --------------------- | ------------------- | +| GET, a basic healthcheck | http://localhost:8085/ | +| GET, a list of all supported interfaces | http://localhost:8085/container\_interfaces | +| POST, delete all policy instances | http://localhost:8085/deleteinstances | +| POST, full reset | http://localhost:8085/deleteall | +| PUT, create/update a policy type | http://localhost:8085/policytype?id=<policytypeid> | +| DELETE, delete a policy type | http://localhost:8085/policytype?id=<policytypeid> | +| GET, list of policy type id | http://localhost:8085/policytypes | +| POST, force a specific response code for an A1 operation | http://localhost:8085/forceresponse?code=<http-code> | +| POST, force delayed response of all A1 operations | http://localhost:8085/forcedelay?delay=<seconds> | +| PUT, set status and optional reason | http://localhost:8085/status?status=<status>[&reason=<reason>] | +| POST, send status for policy | http://localhost:8085/sendstatus?policyid=<policyid> | +| POST, deliver data | http://localhost:8085/datadelivery | +| GET a counter
(counter-name: 'num\_instances', 'num\_types'(always 0), 'interface', 'remote\_hosts' or 'datadelivery') | http://localhost:8085/counter/<counter-name> | + # Configuring the simulator diff --git a/near-rt-ric-simulator/api/STD_2.0.0/ORAN_A1-p_V2.0.0_api.yaml b/near-rt-ric-simulator/api/STD_2.0.0/ORAN_A1-p_V2.0.0_api.yaml new file mode 100644 index 0000000..3cb62c5 --- /dev/null +++ b/near-rt-ric-simulator/api/STD_2.0.0/ORAN_A1-p_V2.0.0_api.yaml @@ -0,0 +1,341 @@ +openapi: 3.0.0 +info: + title: 'A1-P Policy Management Service' + version: 2.0.0 + description: | + API for Policy Management Service. + © 2020, O-RAN Alliance. + All rights reserved. +externalDocs: + description: 'O-RAN.WG2.A1AP-v02.00 A1 interface: Application Protocol' + url: 'https://www.o-ran.org/specifications' +servers: + - url: '{apiRoot}/A1-P/v2' + variables: + apiRoot: + default: 'https://example.com' + description: 'apiRoot as defined in clause 4.2.1 in ORAN-WG2.A1.AP' +paths: + '/policytypes': + get: + operationId: a1.get_all_policy_types + description: 'Get all policy type identifiers' + tags: + - All Policy Type Identifiers + responses: + 200: + description: 'Array of all policy type identifiers' + content: + application/json: + schema: + type: array + items: + "$ref": "#/components/schemas/PolicyTypeId" + minItems: 0 + 429: + "$ref": "#/components/responses/429-TooManyRequests" + 503: + "$ref": "#/components/responses/503-ServiceUnavailable" + + '/policytypes/{policyTypeId}': + parameters: + - name: policyTypeId + in: path + required: true + schema: + "$ref": "#/components/schemas/PolicyTypeId" + get: + operationId: a1.get_policy_type + description: 'Get the schemas for a policy type' + tags: + - Individual Policy Type + responses: + 200: + description: 'The policy type schemas' + content: + application/json: + schema: + "$ref": "#/components/schemas/PolicyTypeObject" + 404: + "$ref": "#/components/responses/404-NotFound" + 429: + "$ref": "#/components/responses/429-TooManyRequests" + 503: + "$ref": "#/components/responses/503-ServiceUnavailable" + + '/policytypes/{policyTypeId}/policies': + get: + operationId: a1.get_all_policy_identities + description: 'Get all policy identifiers' + tags: + - All Policy Identifiers + parameters: + - name: policyTypeId + in: path + required: true + schema: + "$ref": "#/components/schemas/PolicyTypeId" + responses: + 200: + description: 'Array of all policy identifiers' + content: + application/json: + schema: + type: array + items: + "$ref": "#/components/schemas/PolicyId" + minItems: 0 + 429: + "$ref": "#/components/responses/429-TooManyRequests" + 503: + "$ref": "#/components/responses/503-ServiceUnavailable" + + '/policytypes/{policyTypeId}/policies/{policyId}': + parameters: + - name: policyTypeId + in: path + required: true + schema: + "$ref": "#/components/schemas/PolicyTypeId" + - name: policyId + in: path + required: true + schema: + "$ref": "#/components/schemas/PolicyId" + put: + operationId: a1.put_policy + description: 'Create, or update, a policy' + tags: + - Individual Policy Object + parameters: + - name: notificationDestination + in: query + required: false + schema: + "$ref": "#/components/schemas/NotificationDestination" + requestBody: + required: true + content: + application/json: + schema: + "$ref": "#/components/schemas/PolicyObject" + responses: + 200: + description: 'The policy was updated' + content: + application/json: + schema: + "$ref": "#/components/schemas/PolicyObject" + 201: + description: 'The policy was created' + content: + application/json: + schema: + "$ref": "#/components/schemas/PolicyObject" + headers: + Location: + description: 'Contains the URI of the created policy' + required: true + schema: + type: string + 400: + "$ref": "#/components/responses/400-BadRequest" + 409: + "$ref": "#/components/responses/409-Conflict" + 429: + "$ref": "#/components/responses/429-TooManyRequests" + 503: + "$ref": "#/components/responses/503-ServiceUnavailable" + 507: + "$ref": "#/components/responses/507-InsufficientStorage" + callbacks: + policyStatusNotification: + '{$request.query.notificationDestination}': + post: + description: 'Notify about status changes for this policy' + requestBody: + required: true + content: + application/json: + schema: + "$ref": "#/components/schemas/PolicyStatusObject" + responses: + 204: + description: 'Notification received' + get: + operationId: a1.get_policy + description: 'Query a policy' + tags: + - Individual Policy Object + responses: + 200: + description: 'The requested policy' + content: + application/json: + schema: + "$ref": "#/components/schemas/PolicyObject" + 404: + "$ref": "#/components/responses/404-NotFound" + 409: + "$ref": "#/components/responses/409-Conflict" + 429: + "$ref": "#/components/responses/429-TooManyRequests" + 503: + "$ref": "#/components/responses/503-ServiceUnavailable" + delete: + operationId: a1.delete_policy + description: 'Delete a policy' + tags: + - Individual Policy Object + responses: + 204: + description: 'The policy was deleted' + 404: + "$ref": "#/components/responses/404-NotFound" + 429: + "$ref": "#/components/responses/429-TooManyRequests" + 503: + "$ref": "#/components/responses/503-ServiceUnavailable" + + '/policytypes/{policyTypeId}/policies/{policyId}/status': + parameters: + - name: policyTypeId + in: path + required: true + schema: + "$ref": "#/components/schemas/PolicyTypeId" + - name: policyId + in: path + required: true + schema: + "$ref": "#/components/schemas/PolicyId" + get: + operationId: a1.get_policy_status + description: 'Query a policy status' + tags: + - Individual Policy Status Object + responses: + 200: + description: 'The requested policy status' + content: + application/json: + schema: + "$ref": "#/components/schemas/PolicyStatusObject" + 404: + "$ref": "#/components/responses/404-NotFound" + 409: + "$ref": "#/components/responses/409-Conflict" + 429: + "$ref": "#/components/responses/429-TooManyRequests" + 503: + "$ref": "#/components/responses/503-ServiceUnavailable" + +components: + schemas: + # + # Representation objects + # + PolicyObject: + description: 'A generic policy object that can be used to transport any policy. Additionally, a policy shall be valid according to the schema of its specific policy type.' + type: object + + PolicyStatusObject: + description: 'A generic policy status object that can be used to transport any policy status. Additionally, a policy status shall be valid according to the schema of its specific policy type.' + type: object + + PolicyTypeObject: + description: 'A definition of a policy type, i.e. the schemas for a policy respectively its status' + type: object + properties: + policySchema: + "$ref": "#/components/schemas/JsonSchema" + statusSchema: + "$ref": "#/components/schemas/JsonSchema" + required: + - policySchema + + ProblemDetails: + description: 'A problem detail to carry details in a HTTP response according to RFC 7807' + type: object + properties: + type: + type: string + title: + type: string + status: + type: number + detail: + type: string + instance: + type: string + + # + # Simple data types + # + JsonSchema: + description: 'A JSON schema following http://json-schema.org/draft-07/schema' + type: object + + NotificationDestination: + description: 'A complete callback URI defined according to IETF RFC 3986 where to send notifications' + type: string + + PolicyId: + description: 'Policy identifier assigned by the A1-P Consumer when a policy is created' + type: string + + PolicyTypeId: + description: 'Policy type identifier assigned by the A1-P Provider' + type: string + + responses: + 400-BadRequest: + description: 'Object in payload not properly formulated or not related to the method' + content: + application/problem+json: + schema: + "$ref": "#/components/schemas/ProblemDetails" + + 404-NotFound: + description: 'No resource found at the URI' + content: + application/problem+json: + schema: + "$ref": "#/components/schemas/ProblemDetails" + + 405-MethodNotAllowed: + description: 'Method not allowed for the URI' + content: + application/problem+json: + schema: + "$ref": "#/components/schemas/ProblemDetails" + + 409-Conflict: + description: 'Request could not be processed in the current state of the resource' + content: + application/problem+json: + schema: + "$ref": "#/components/schemas/ProblemDetails" + + 429-TooManyRequests: + description: 'Too many requests have been sent in a given amount of time' + content: + application/problem+json: + schema: + "$ref": "#/components/schemas/ProblemDetails" + + 503-ServiceUnavailable: + description: 'The provider is currently unable to handle the request due to a temporary overload' + content: + application/problem+json: + schema: + "$ref": "#/components/schemas/ProblemDetails" + + 507-InsufficientStorage: + description: 'The method could not be performed on the resource because the provider is unable to store the representation needed to successfully complete the request' + content: + application/problem+json: + schema: + "$ref": "#/components/schemas/ProblemDetails" + + diff --git a/near-rt-ric-simulator/src/OSC_2.1.0/.gitignore b/near-rt-ric-simulator/src/OSC_2.1.0/.gitignore new file mode 100644 index 0000000..bee8a64 --- /dev/null +++ b/near-rt-ric-simulator/src/OSC_2.1.0/.gitignore @@ -0,0 +1 @@ +__pycache__ diff --git a/near-rt-ric-simulator/src/OSC_2.1.0/main.py b/near-rt-ric-simulator/src/OSC_2.1.0/main.py index 48fbe91..e0766d8 100644 --- a/near-rt-ric-simulator/src/OSC_2.1.0/main.py +++ b/near-rt-ric-simulator/src/OSC_2.1.0/main.py @@ -206,6 +206,8 @@ def getcounter(countername): elif (countername == "remote_hosts"): hosts=",".join(hosts_set) return str(hosts),200 + elif (countername == "datadelivery"): + return Response(str(0),200, mimetype=TEXT_PLAIN) else: return Response("Counter name: "+countername+" not found.",404, mimetype=TEXT_PLAIN) diff --git a/near-rt-ric-simulator/src/STD_1.1.3/.gitignore b/near-rt-ric-simulator/src/STD_1.1.3/.gitignore new file mode 100644 index 0000000..bee8a64 --- /dev/null +++ b/near-rt-ric-simulator/src/STD_1.1.3/.gitignore @@ -0,0 +1 @@ +__pycache__ diff --git a/near-rt-ric-simulator/src/STD_1.1.3/main.py b/near-rt-ric-simulator/src/STD_1.1.3/main.py index b7ecdcd..5742791 100644 --- a/near-rt-ric-simulator/src/STD_1.1.3/main.py +++ b/near-rt-ric-simulator/src/STD_1.1.3/main.py @@ -163,6 +163,8 @@ def getcounter(countername): elif (countername == "remote_hosts"): hosts=",".join(hosts_set) return str(hosts),200 + elif (countername == "datadelivery"): + return Response(str(0),200, mimetype=TEXT_PLAIN) else: return Response("Counter name: "+countername+" not found.",404, mimetype=TEXT_PLAIN) diff --git a/near-rt-ric-simulator/src/STD_2.0.0/.gitignore b/near-rt-ric-simulator/src/STD_2.0.0/.gitignore new file mode 100644 index 0000000..bee8a64 --- /dev/null +++ b/near-rt-ric-simulator/src/STD_2.0.0/.gitignore @@ -0,0 +1 @@ +__pycache__ diff --git a/near-rt-ric-simulator/src/STD_2.0.0/a1.py b/near-rt-ric-simulator/src/STD_2.0.0/a1.py new file mode 100644 index 0000000..c4aa4ca --- /dev/null +++ b/near-rt-ric-simulator/src/STD_2.0.0/a1.py @@ -0,0 +1,271 @@ +# ============LICENSE_START=============================================== +# Copyright (C) 2020 Nordix Foundation. All rights reserved. +# ======================================================================== +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END================================================= +# + +import copy +import datetime +import json +import logging +import collections +import time + +from connexion import NoContent +from flask import Flask, escape, request, Response, make_response +from jsonschema import validate +from var_declaration import policy_instances, policy_types, policy_status, callbacks, forced_settings, policy_fingerprint, hosts_set +from utils import calcFingerprint +from maincommon import check_apipath, apipath, get_supported_interfaces_response, extract_host_name + +#Constsants +APPL_JSON='application/json' +APPL_PROB_JSON='application/problem+json' + +# API Function: Get all policy type ids +def get_all_policy_types(): + + extract_host_name(hosts_set, request) + + if ((r := check_modified_response()) is not None): + return r + + res = list(policy_types.keys()) + return (res, 200) + +# API Function: Get a policy type +def get_policy_type(policyTypeId): + + extract_host_name(hosts_set, request) + + if ((r := check_modified_response()) is not None): + return r + + policy_type_id=str(policyTypeId) + + if (policy_type_id not in policy_types.keys()): + pjson=create_problem_json(None, "The policy type does not exist.", 404, None, policy_type_id) + return Response(json.dumps(pjson), 404, mimetype=APPL_PROB_JSON) + + return Response(json.dumps(policy_types[policy_type_id]), 200, mimetype=APPL_JSON) + +# API Function: Get all policy ids +def get_all_policy_identities(policyTypeId): + + extract_host_name(hosts_set, request) + + if ((r := check_modified_response()) is not None): + return r + + policy_type_id=str(policyTypeId) + + if (policy_type_id not in policy_types.keys()): + pjson=create_problem_json(None, "The policy type does not exist.", 404, None, policy_type_id) + return Response(json.dumps(pjson), 404, mimetype=APPL_PROB_JSON) + + return (list(policy_instances[policy_type_id].keys()), 200) + +# API Function: Create or update a policy +def put_policy(policyTypeId, policyId): + + extract_host_name(hosts_set, request) + + if ((r := check_modified_response()) is not None): + return r + + policy_type_id=str(policyTypeId) + policy_id=str(policyId) + + if (policy_type_id not in policy_types.keys()): + pjson=create_problem_json(None, "The policy type does not exist.", 404, None, policy_id) + return Response(json.dumps(pjson), 404, mimetype=APPL_PROB_JSON) + + try: + data = request.data + data = json.loads(data) + except Exception: + pjson=create_problem_json(None, "The policy is corrupt or missing.", 400, None, policy_id) + return Response(json.dumps(pjson), 400, mimetype=APPL_PROB_JSON) + + try: + validate(instance=data, schema=policy_types[policy_type_id]['policySchema']) + except Exception: + return (None, 400) + + fp_previous=None + retcode=201 + if policy_id in policy_instances[policy_type_id].keys(): + retcode=200 + fp_previous=calcFingerprint(policy_instances[policy_type_id][policy_id]) + else: + if (policy_id in policy_fingerprint.values()): + return (None, 400) + + fp=calcFingerprint(data) + if (fp in policy_fingerprint.keys()): + p_id=policy_fingerprint[fp] + if (p_id != policy_id): + pjson=create_problem_json(None, "Duplicate, the policy json already exists.", 400, None, policy_id) + return Response(json.dumps(pjson), 400, mimetype=APPL_PROB_JSON) + + if (fp_previous is not None): + del policy_fingerprint[fp_previous] + + policy_fingerprint[fp]=policy_id + + noti=request.args.get('notificationDestination') + callbacks[policy_id]=noti + + policy_instances[policy_type_id][policy_id]=data + + if (policy_types[policy_type_id]['statusSchema'] is not None): + ps = {} + ps["enforceStatus"] = "" + ps["enforceReason"] = "" + policy_status[policy_id] = ps + + if (retcode == 200): + return Response(json.dumps(data), 200, mimetype=APPL_JSON) + else: + headers={} + headers['Location']='/A1-P/v2/policytypes/' + policy_type_id + '/policies/' + policy_id + return Response(json.dumps(data), 201, headers=headers, mimetype=APPL_JSON) + +# API Function: Get a policy +def get_policy(policyTypeId, policyId): + + extract_host_name(hosts_set, request) + + if ((r := check_modified_response()) is not None): + return r + + policy_type_id=str(policyTypeId) + policy_id=str(policyId) + + if (policy_type_id not in policy_types.keys()): + pjson=create_problem_json(None, "The policy type does not exist.", 404, None, policy_id) + return Response(json.dumps(pjson), 404, mimetype=APPL_PROB_JSON) + + if (policy_id not in policy_instances[policy_type_id].keys()): + pjson=create_problem_json(None, "The requested policy does not exist.", 404, None, policy_id) + return Response(json.dumps(pjson), 404, mimetype=APPL_PROB_JSON) + + return Response(json.dumps(policy_instances[policy_type_id][policy_id]), 200, mimetype=APPL_JSON) + + +# API Function: Delete a policy +def delete_policy(policyTypeId, policyId): + + extract_host_name(hosts_set, request) + + if ((r := check_modified_response()) is not None): + return r + + policy_type_id=str(policyTypeId) + policy_id=str(policyId) + + if (policy_type_id not in policy_types.keys()): + pjson=create_problem_json(None, "The policy type does not exist.", 404, None, policy_id) + return Response(json.dumps(pjson), 404, mimetype=APPL_PROB_JSON) + + if (policy_id not in policy_instances[policy_type_id].keys()): + pjson=create_problem_json(None, "The requested policy does not exist.", 404, None, policy_id) + return Response(json.dumps(pjson), 404, mimetype=APPL_PROB_JSON) + + fp_previous=calcFingerprint(policy_instances[policy_type_id][policy_id]) + policy_fingerprint.pop(fp_previous) + policy_instances[policy_type_id].pop(policy_id) + policy_status.pop(policy_id) + callbacks.pop(policy_id) + return Response('', 204, mimetype=APPL_JSON) + + +# API Function: Get status for a policy +def get_policy_status(policyTypeId, policyId): + + extract_host_name(hosts_set, request) + + if ((r := check_modified_response()) is not None): + return r + + policy_type_id=str(policyTypeId) + policy_id=str(policyId) + + if (policy_type_id not in policy_types.keys()): + pjson=create_problem_json(None, "The policy type does not exist.", 404, None, policy_id) + return Response(json.dumps(pjson), 404, mimetype=APPL_PROB_JSON) + + if (policy_id not in policy_instances[policy_type_id].keys()): + pjson=create_problem_json(None, "The requested policy does not exist.", 404, None, policy_id) + return Response(json.dumps(pjson), 404, mimetype=APPL_PROB_JSON) + + return Response(json.dumps(policy_status[policy_id]), status=200, mimetype=APPL_JSON) + +# Helper: Create a response object if forced http response code is set +def get_forced_response(): + if (forced_settings['code'] is not None): + pjson=create_error_response(forced_settings['code']) + forced_settings['code']=None + return Response(json.dumps(pjson), pjson['status'], mimetype=APPL_PROB_JSON) + return None + +# Helper: Delay if delayed response code is set +def do_delay(): + if (forced_settings['delay'] is not None): + try: + val=int(forced_settings['delay']) + time.sleep(val) + except Exception: + return + +# Helper: Check if response shall be delayed or a forced response shall be sent +def check_modified_response(): + do_delay() + return get_forced_response() + +# Helper: Create a problem json object +def create_problem_json(type_of, title, status, detail, instance): + + error = {} + if type_of is not None: + error["type"] = type_of + if title is not None: + error["title"] = title + if status is not None: + error["status"] = status + if detail is not None: + error["detail"] = detail + if instance is not None: + error["instance"] = instance + return error + +# Helper: Create a problem json based on a generic http response code +def create_error_response(code): + + if code == '400': + return(create_problem_json(None, "Bad request", 400, "Object in payload not properly formulated or not related to the method", None)) + elif code == '404': + return(create_problem_json(None, "Not found", 404, "No resource found at the URI", None)) + elif code == '405': + return(create_problem_json(None, "Method not allowed", 405, "Method not allowed for the URI", None)) + elif code == '409': + return(create_problem_json(None, "Conflict", 409, "Request could not be processed in the current state of the resource", None)) + elif code == '429': + return(create_problem_json(None, "Too many requests", 429, "Too many requests have been sent in a given amount of time", None)) + elif code == '507': + return(create_problem_json(None, "Insufficient storage", 507, "The method could not be performed on the resource because the provider is unable to store the representation needed to successfully complete the request", None)) + elif code == '503': + return(create_problem_json(None, "Service unavailable", 503, "The provider is currently unable to handle the request due to a temporary overload", None)) + else: + return(create_problem_json(None, "Unknown", code, "Not implemented response code", None)) diff --git a/near-rt-ric-simulator/src/STD_2.0.0/callBack.py b/near-rt-ric-simulator/src/STD_2.0.0/callBack.py new file mode 100644 index 0000000..0e8e416 --- /dev/null +++ b/near-rt-ric-simulator/src/STD_2.0.0/callBack.py @@ -0,0 +1,43 @@ +# ============LICENSE_START=============================================== +# Copyright (C) 2020 Nordix Foundation. All rights reserved. +# ======================================================================== +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END================================================= +# + +import json +from flask import Flask, request, Response + +app = Flask(__name__) #NOSONAR + +#Check alive function +@app.route('/', methods=['GET']) +def test(): + + return Response("OK", 200, mimetype='text/plain') + +#Receive status (only for testing callbacks) +#/statustest +@app.route('/statustest', methods=['POST', 'PUT']) +def statustest(): + try: + data = request.data + data = json.loads(data) + except Exception: + return Response("The status data is corrupt or missing.", 400, mimetype='text/plain') + + return Response(json.dumps(data), 200, mimetype='application/json') + +port_number = 2223 + +app.run(port=port_number, host="127.0.0.1", threaded=False) \ No newline at end of file diff --git a/near-rt-ric-simulator/src/STD_2.0.0/main.py b/near-rt-ric-simulator/src/STD_2.0.0/main.py new file mode 100644 index 0000000..dcf835e --- /dev/null +++ b/near-rt-ric-simulator/src/STD_2.0.0/main.py @@ -0,0 +1,255 @@ +# ============LICENSE_START=============================================== +# Copyright (C) 2020 Nordix Foundation. All rights reserved. +# ======================================================================== +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END================================================= +# + +import connexion +import json +import sys +import os +import requests + + +from pathlib import Path +from flask import Flask, escape, request, Response +from jsonschema import validate +from var_declaration import policy_instances, policy_types, policy_status, callbacks, forced_settings, policy_fingerprint, hosts_set, data_delivery_counter +from maincommon import check_apipath, apipath, get_supported_interfaces_response, extract_host_name + +#Constants +TEXT_PLAIN='text/plain' + +check_apipath() + +app = connexion.App(__name__, specification_dir=apipath) + +#Check alive function +@app.route('/', methods=['GET']) +def test(): + + return Response("OK", 200, mimetype=TEXT_PLAIN) + +#Return the current and all supported yamls for the this container +@app.route('/container_interfaces', methods=['GET']) +def container_interfaces(): + + return get_supported_interfaces_response() + +#Delete all created instances and status +@app.route('/deleteinstances', methods=['POST']) +def delete_instances(): + + for i in policy_instances.keys(): + policy_instances[i]={} + policy_status.clear() + callbacks.clear() + forced_settings['code']=None + forced_settings['delay']=None + policy_fingerprint.clear() + return Response("All policy instances deleted", 200, mimetype=TEXT_PLAIN) + +#Delete all - all reset +#(same as delete_instances but kept to in order to use the same interface as other version of the simulator) +@app.route('/deleteall', methods=['POST']) +def delete_all(): + + policy_instances.clear() + policy_types.clear() + policy_status.clear() + callbacks.clear() + forced_settings['code']=None + forced_settings['delay']=None + policy_fingerprint.clear() + return Response("All policy instances and types deleted", 200, mimetype=TEXT_PLAIN) + +#Load a policy type +@app.route('/policytype', methods=['PUT']) +def policytype(): + + policy_type_id=request.args.get('id') + if (policy_type_id is None): + return Response('Parameter missing in request', status=400, mimetype=TEXT_PLAIN) + + try: + data = request.data + data = json.loads(data) + except Exception: + return Response("The policy type is corrupt or missing", 400, mimetype=TEXT_PLAIN) + + if ('policySchema' not in data.keys()): + return Response("The policy type atribute policySchema is missing", 400, mimetype=TEXT_PLAIN) + + retcode=201 + if (policy_type_id in policy_types.keys()): + retcode=200 + if (len(policy_instances[policy_type_id]) > 0): + return Response("The policy type already exists and instances exists", 400, mimetype=TEXT_PLAIN) + + policy_types[policy_type_id]=data + policy_instances[policy_type_id]={} + return Response("Policy type " + policy_type_id + " is OK.", retcode, mimetype=TEXT_PLAIN) + +#Delete a policy type +@app.route('/policytype', methods=['DELETE']) +def del_policytype(): + + policy_type_id=request.args.get('id') + if (policy_type_id is None): + return Response('Parameter missing in request', status=400, mimetype=TEXT_PLAIN) + + if (policy_type_id in policy_types.keys()): + if (len(policy_instances[policy_type_id]) > 0): + return Response("The policy type already exists and instances exists", 400, mimetype=TEXT_PLAIN) + + del policy_types[policy_type_id] + del policy_instances[policy_type_id] + return Response("Policy type " + policy_type_id + " is OK.", 204, mimetype=TEXT_PLAIN) + + return Response("Policy type " + policy_type_id + " not found.", 204, mimetype=TEXT_PLAIN) + + +# Get all policy type ids +@app.route('/policytypes', methods=['GET']) +def get_policytype_ids(): + + return (json.dumps(list(policy_instances.keys())), 200) + + +#Set force response for one A1 response +#/forceresponse?code= +@app.route('/forceresponse', methods=['POST']) +def forceresponse(): + + try: + forced_settings['code']=request.args.get('code') + except Exception: + forced_settings['code']=None + return Response("Force response code: " + str(forced_settings['code']) + " set for one single A1 response", 200, mimetype=TEXT_PLAIN) + +#Set force delay response, in seconds, for all A1 responses +#/froceesponse?delay= +@app.route('/forcedelay', methods=['POST']) +def forcedelay(): + + try: + forced_settings['delay']=request.args.get('delay') + except Exception: + forced_settings['delay']=None + return Response("Force delay: " + str(forced_settings['delay']) + " sec set for all A1 responses", 200, mimetype=TEXT_PLAIN) + + +#Set status and reason +#/status?policyid=&status=[&reason=] +@app.route('/status', methods=['PUT']) +def setstatus(): + + policy_id=request.args.get('policyid') + if (policy_id is None): + return Response('Parameter missing in request', status=400, mimetype=TEXT_PLAIN) + if policy_id not in policy_status.keys(): + return Response('Policyid: '+policy_id+' not found.', status=404, mimetype=TEXT_PLAIN) + status=request.args.get('status') + if (status is None): + return Response('Parameter missing in request', status=400, mimetype=TEXT_PLAIN) + reason=request.args.get('reason') + ps = {} + ps["enforceStatus"] = status + msg="Status set to "+status + if (reason is not None): + ps["enforceReason"] = reason + msg=msg+" and "+reason + policy_status[policy_id] = ps + msg=msg+" for policy: " + policy_id + return Response(msg, 200, mimetype=TEXT_PLAIN) + +#Send status +#/status?policyid= +@app.route('/sendstatus', methods=['POST']) +def sendstatus(): + policyid=request.args.get('policyid') + if (policyid is None): + return Response('Parameter missing in request', status=400, mimetype=TEXT_PLAIN) + + if (policyid not in policy_status.keys()): + return Response('Policyid: '+policyid+' not found.', status=404, mimetype=TEXT_PLAIN) + + ps=policy_status[policyid] + cb=callbacks[policyid] + try: + print("Callback url: " + str(cb)) + resp=requests.post(cb,json=json.dumps(ps), verify=False) # NOSONAR + except: + return Response('Post status failed, could not send to: '+str(cb), status=500, mimetype=TEXT_PLAIN) + if (resp.status_code<199 & resp.status_code > 299): + return Response('Post status failed with code: '+resp.status_code, status=500, mimetype=TEXT_PLAIN) + + data = resp.json() + return Response(data, 200, mimetype='application/json') + +#Receive status (only for testing callbacks) +#/statustest +@app.route('/statustest', methods=['POST', 'PUT']) +def statustest(): + try: + data = request.data + data = json.loads(data) + except Exception: + return Response("The status data is corrupt or missing.", 400, mimetype=TEXT_PLAIN) + + return Response(json.dumps(data), 200, mimetype='application/json') + +#Receive a data delivery package +#/datadelivery +@app.route('/datadelivery', methods=['POST']) +def datadelivery(): + global data_delivery_counter + try: + data = request.data + data = json.loads(data) + except Exception: + return Response("The data is corrupt or missing.", 400, mimetype=TEXT_PLAIN) + data_delivery_counter += 1 + return Response("", 200, mimetype=TEXT_PLAIN) + +#Metrics function +#Get a named counter +@app.route('/counter/', methods=['GET']) +def getcounter(countername): + + if (countername == "num_instances"): + return Response(str(len(policy_fingerprint)), 200, mimetype=TEXT_PLAIN) + elif (countername == "num_types"): + return Response(str(len(policy_instances)),200, mimetype=TEXT_PLAIN) + elif (countername == "interface"): + p=Path(os.getcwd()) + pp=p.parts + return Response(str(pp[len(pp)-1]),200, mimetype=TEXT_PLAIN) + elif (countername == "remote_hosts"): + hosts=",".join(hosts_set) + return str(hosts),200 + elif (countername == "datadelivery"): + return Response(str(data_delivery_counter),200, mimetype=TEXT_PLAIN) + else: + return Response("Counter name: "+countername+" not found.",404, mimetype=TEXT_PLAIN) + +port_number = 2222 +if len(sys.argv) >= 2: + if isinstance(sys.argv[1], int): + port_number = sys.argv[1] + +app.add_api('ORAN_A1-p_V2.0.0_api.yaml') + +if __name__ == '__main__': + app.run(port=port_number, host="127.0.0.1", threaded=False) \ No newline at end of file diff --git a/near-rt-ric-simulator/src/STD_2.0.0/var_declaration.py b/near-rt-ric-simulator/src/STD_2.0.0/var_declaration.py new file mode 100644 index 0000000..5136404 --- /dev/null +++ b/near-rt-ric-simulator/src/STD_2.0.0/var_declaration.py @@ -0,0 +1,27 @@ +# ============LICENSE_START=============================================== +# Copyright (C) 2020 Nordix Foundation. All rights reserved. +# ======================================================================== +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END================================================= +# + +policy_types={} +policy_instances = {} +policy_status = {} +callbacks = {} +forced_settings = {} +forced_settings['code']=None +forced_settings['delay']=None +policy_fingerprint={} +hosts_set=set() +data_delivery_counter=0 diff --git a/near-rt-ric-simulator/src/common/.gitignore b/near-rt-ric-simulator/src/common/.gitignore new file mode 100644 index 0000000..bee8a64 --- /dev/null +++ b/near-rt-ric-simulator/src/common/.gitignore @@ -0,0 +1 @@ +__pycache__ diff --git a/near-rt-ric-simulator/src/start.sh b/near-rt-ric-simulator/src/start.sh index 3fe7d4b..feb5a1d 100755 --- a/near-rt-ric-simulator/src/start.sh +++ b/near-rt-ric-simulator/src/start.sh @@ -41,7 +41,7 @@ cd $1 nginx -c /usr/src/app/nginx.conf #start callBack server -if [ ${A1_VERSION} == "STD_1.1.3" ]; then +if [[ ${A1_VERSION} == "STD"* ]]; then echo "Path to callBack.py: "$PWD python -u callBack.py & fi diff --git a/near-rt-ric-simulator/test/OSC_2.1.0/basic_test.sh b/near-rt-ric-simulator/test/OSC_2.1.0/basic_test.sh index 41ff2d1..bc2413d 100755 --- a/near-rt-ric-simulator/test/OSC_2.1.0/basic_test.sh +++ b/near-rt-ric-simulator/test/OSC_2.1.0/basic_test.sh @@ -47,7 +47,7 @@ RESULT="OK" do_curl GET / 200 echo "=== Check used and implemented interfaces ===" -RESULT="Current interface: OSC_2.1.0 All supported A1 interface yamls in this container: ['OSC_2.1.0', 'STD_1.1.3']" +RESULT="Current interface: OSC_2.1.0 All supported A1 interface yamls in this container: ['OSC_2.1.0', 'STD_1.1.3', 'STD_2.0.0']" do_curl GET /container_interfaces 200 echo "=== Reset simulator instances ===" diff --git a/near-rt-ric-simulator/test/OSC_2.1.0/build_and_start.sh b/near-rt-ric-simulator/test/OSC_2.1.0/build_and_start.sh index e182782..f376971 100755 --- a/near-rt-ric-simulator/test/OSC_2.1.0/build_and_start.sh +++ b/near-rt-ric-simulator/test/OSC_2.1.0/build_and_start.sh @@ -25,6 +25,9 @@ cd ../../ #Build the image docker build -t a1test . +docker stop a1OscSimulator > /dev/null 2>&1 +docker rm -f a1OscSimulator > /dev/null 2>&1 + echo "Starting $1 mode" #Run the container in interactive mode, unsecure port 8085, secure port 8185. docker run -it -p 8085:8085 -p 8185:8185 -e A1_VERSION=OSC_2.1.0 -e ALLOW_HTTP=true -e REMOTE_HOSTS_LOGGING=1 --volume "$PWD/certificate:/usr/src/app/cert" --name a1OscSimulator a1test diff --git a/near-rt-ric-simulator/test/STD_1.1.3/basic_test.sh b/near-rt-ric-simulator/test/STD_1.1.3/basic_test.sh index 77f10a6..3a828d2 100755 --- a/near-rt-ric-simulator/test/STD_1.1.3/basic_test.sh +++ b/near-rt-ric-simulator/test/STD_1.1.3/basic_test.sh @@ -48,7 +48,7 @@ RESULT="OK" do_curl GET / 200 echo "=== Check used and implemented interfaces ===" -RESULT="Current interface: STD_1.1.3 All supported A1 interface yamls in this container: ['OSC_2.1.0', 'STD_1.1.3']" +RESULT="Current interface: STD_1.1.3 All supported A1 interface yamls in this container: ['OSC_2.1.0', 'STD_1.1.3', 'STD_2.0.0']" do_curl GET /container_interfaces 200 echo "=== Reset simulator instances ===" diff --git a/near-rt-ric-simulator/test/STD_1.1.3/build_and_start.sh b/near-rt-ric-simulator/test/STD_1.1.3/build_and_start.sh index fa59f49..1d56487 100755 --- a/near-rt-ric-simulator/test/STD_1.1.3/build_and_start.sh +++ b/near-rt-ric-simulator/test/STD_1.1.3/build_and_start.sh @@ -25,6 +25,9 @@ cd ../../ #Build the image docker build -t a1test . +docker stop a1StdSimulator > /dev/null 2>&1 +docker rm -f a1StdSimulator > /dev/null 2>&1 + echo "Starting ric-sim" #Run the container in interactive mode, unsecure port 8085, secure port 8185 docker run -it -p 8085:8085 -p 8185:8185 -e A1_VERSION=STD_1.1.3 -e ALLOW_HTTP=true -e REMOTE_HOSTS_LOGGING=1 --volume "$PWD/certificate:/usr/src/app/cert" --name a1StdSimulator a1test diff --git a/near-rt-ric-simulator/test/STD_2.0.0/.p.json b/near-rt-ric-simulator/test/STD_2.0.0/.p.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/near-rt-ric-simulator/test/STD_2.0.0/.p.json @@ -0,0 +1 @@ +{} diff --git a/near-rt-ric-simulator/test/STD_2.0.0/basic_test.sh b/near-rt-ric-simulator/test/STD_2.0.0/basic_test.sh new file mode 100755 index 0000000..576bd5e --- /dev/null +++ b/near-rt-ric-simulator/test/STD_2.0.0/basic_test.sh @@ -0,0 +1,288 @@ +#!/bin/bash + +# ============LICENSE_START=============================================== +# Copyright (C) 2020 Nordix Foundation. All rights reserved. +# ======================================================================== +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END================================================= +# + +# Script for basic test of the simulator. +# Run the build_and_start with the same arg as this script +if [ $# -ne 1 ]; then + echo "Usage: ./basic_test.sh nonsecure|secure" + exit 1 +fi +if [ "$1" != "nonsecure" ] && [ "$1" != "secure" ]; then + echo "Usage: ./basic_test.sh nonsecure|secure" + exit 1 +fi + +if [ $1 == "nonsecure" ]; then + #Default http port for the simulator + PORT=8085 + # Set http protocol + HTTPX="http" +else + #Default https port for the simulator + PORT=8185 + # Set https protocol + HTTPX="https" +fi + +. ../common/test_common.sh + + +echo "=== Simulator hello world ===" +RESULT="OK" +do_curl GET / 200 + +echo "=== Check used and implemented interfaces ===" +RESULT="Current interface: STD_2.0.0 All supported A1 interface yamls in this container: ['OSC_2.1.0', 'STD_1.1.3', 'STD_2.0.0']" +do_curl GET /container_interfaces 200 + +echo "=== Reset simulator instances ===" +RESULT="All policy instances deleted" +do_curl POST /deleteinstances 200 + +echo "=== Reset simulator, all ===" +RESULT="All policy instances and types deleted" +do_curl POST /deleteall 200 + +echo "=== Get counter: interface ===" +RESULT="STD_2.0.0" +do_curl GET /counter/interface 200 + +echo "=== Get counter: remote hosts ===" +RESULT="*" +do_curl GET /counter/remote_hosts 200 + +echo "=== Get counter: intstance ===" +RESULT="0" +do_curl GET /counter/num_instances 200 + +echo "=== Get counter: types (shall be 0)===" +RESULT="0" +do_curl GET /counter/num_types 200 + +echo "=== API: Get policy types, shall be empty array ==" +RESULT="json:[]" +do_curl GET /A1-P/v2/policytypes 200 + +echo "=== API: Get policy instances for type 1, type not found==" +RESULT="json:{\"title\": \"The policy type does not exist.\", \"status\": 404, \"instance\": \"1\"}" +do_curl GET /A1-P/v2/policytypes/1/policies 404 + +echo "=== API: Get policy instances, type not found==" +RESULT="json:{\"title\": \"The policy type does not exist.\", \"status\": 404, \"instance\": \"test\"}" +do_curl GET /A1-P/v2/policytypes/test/policies 404 + +echo "=== Put a policy type: STD_1 ===" +RESULT="Policy type STD_1 is OK." +do_curl PUT '/policytype?id=STD_1' 201 jsonfiles/std_1.json + +echo "=== Put a policy type: STD_1, again ===" +RESULT="Policy type STD_1 is OK." +do_curl PUT '/policytype?id=STD_1' 200 jsonfiles/std_1.json + +echo "=== API: Get policy type ids, shall contain type STD_1 ==" +RESULT="json:[ \"STD_1\" ]" +do_curl GET /A1-P/v2/policytypes 200 + +echo "=== Delete a policy type: STD_1 ===" +RESULT="" +do_curl DELETE '/policytype?id=STD_1' 204 + +echo "=== API: Get policy type ids, shall be empty ==" +RESULT="json:[]" +do_curl GET /A1-P/v2/policytypes 200 + +echo "=== Put a policy type: STD_1 ===" +RESULT="Policy type STD_1 is OK." +do_curl PUT '/policytype?id=STD_1' 201 jsonfiles/std_1.json + +echo "=== API: Get policy type ids, shall contain type STD_1 ==" +RESULT="json:[ \"STD_1\" ]" +do_curl GET /A1-P/v2/policytypes 200 + +echo "=== Get counter: types (shall be 1)===" +RESULT="1" +do_curl GET /counter/num_types 200 + +echo "=== API: Get policy type: STD_1 ===" +res=$(cat jsonfiles/std_1.json) +RESULT="json:$res" +do_curl GET /A1-P/v2/policytypes/STD_1 200 + +echo "=== API: Get policy instances, shall be empty==" +RESULT="json:[ ]" +do_curl GET /A1-P/v2/policytypes/STD_1/policies 200 + +echo "=== API: Create policy instance pi1 of type: STD_1 ===" +res=$(cat jsonfiles/pi1.json) +RESULT="json:$res" +do_curl PUT /A1-P/v2/policytypes/STD_1/policies/pi1 201 jsonfiles/pi1.json + +echo "=== API: Get policy instance pi1 of type: STD_1 ===" +res=$(cat jsonfiles/pi1.json) +RESULT="json:$res" +do_curl GET /A1-P/v2/policytypes/STD_1/policies/pi1 200 + +echo "=== API: Update policy instance pi1 of type: STD_1===" +res=$(cat jsonfiles/pi1.json) +RESULT="json:$res" +do_curl PUT /A1-P/v2/policytypes/STD_1/policies/pi1 200 jsonfiles/pi1.json + +echo "=== API: Update policy instance pi1 of type: STD_1===" +res=$(cat jsonfiles/pi1_updated.json) +RESULT="json:$res" +do_curl PUT /A1-P/v2/policytypes/STD_1/policies/pi1 200 jsonfiles/pi1_updated.json + +echo "=== API: Duplicate policy instance pi2 of type: STD_1===" +res=$(cat jsonfiles/pi1_updated.json) +RESULT="json:{\"title\": \"Duplicate, the policy json already exists.\", \"status\": 400, \"instance\": \"pi2\"}" +do_curl PUT /A1-P/v2/policytypes/STD_1/policies/pi2 400 jsonfiles/pi1_updated.json + +echo "=== API: Get policy instances, shall contain pi1==" +RESULT="json:[ \"pi1\" ]" +do_curl GET /A1-P/v2/policytypes/STD_1/policies 200 + +echo "=== Get counter: types (shall be 1)===" +RESULT="1" +do_curl GET /counter/num_types 200 + +echo "=== Get counter: intstance ===" +RESULT="1" +do_curl GET /counter/num_instances 200 + + +echo "=== Set force response code 409. ===" +RESULT="*" +do_curl POST '/forceresponse?code=409' 200 + +echo "=== API: Get policy instances, shall fail with 409 ==" +RESULT="json:{\"title\": \"Conflict\", \"status\": 409, \"detail\": \"Request could not be processed in the current state of the resource\"}" +do_curl GET /A1-P/v2/policytypes/STD_1/policies 409 + +echo "=== API: Get policy status ===" +RESULT="json:{\"enforceStatus\": \"\", \"enforceReason\": \"\"}" +do_curl GET /A1-P/v2/policytypes/STD_1/policies/pi1/status 200 + +echo "=== API: Create policy instance pi2 of type: STD_1 ===" +res=$(cat jsonfiles/pi2.json) +RESULT="json:$res" +do_curl PUT /A1-P/v2/policytypes/STD_1/policies/pi2 201 jsonfiles/pi2.json + +echo "=== API: Update policy instance pi2 of type: STD_1 ===" +res=$(cat jsonfiles/pi2.json) +RESULT="json:$res" +do_curl PUT '/A1-P/v2/policytypes/STD_1/policies/pi2?notificationDestination=http://localhost:2223/statustest' 200 jsonfiles/pi2.json + +echo "=== API: Get policy instances, shall contain pi1 and pi2==" +RESULT="json:[ \"pi1\", \"pi2\" ]" +do_curl GET /A1-P/v2/policytypes/STD_1/policies 200 + +echo "=== Get counter: types (shall be 1)===" +RESULT="1" +do_curl GET /counter/num_types 200 + +echo "=== Get counter: intstance ===" +RESULT="2" +do_curl GET /counter/num_instances 200 + +echo "=== Set force delay 10. ===" +RESULT="Force delay: 10 sec set for all A1 responses" +do_curl POST '/forcedelay?delay=10' 200 + +echo "=== API: Get policy instances, shall contain pi1 and pi2==" +RESULT="json:[ \"pi1\", \"pi2\" ]" +do_curl GET /A1-P/v2/policytypes/STD_1/policies 200 + +echo "=== Reset force delay. ===" +RESULT="Force delay: None sec set for all A1 responses" +do_curl POST /forcedelay 200 + +echo "=== API: Get policy instance pi1 of type: STD_1 ===" +res=$(cat jsonfiles/pi1_updated.json) +RESULT="json:$res" +do_curl GET /A1-P/v2/policytypes/STD_1/policies/pi1 200 + +echo "=== API: Get policy instance pi2 of type: STD_1 ===" +res=$(cat jsonfiles/pi2.json) +RESULT="json:$res" +do_curl GET /A1-P/v2/policytypes/STD_1/policies/pi2 200 + +echo "=== API: DELETE policy instance pi1 ===" +RESULT="" +do_curl DELETE /A1-P/v2/policytypes/STD_1/policies/pi1 204 + +echo "=== API: Get policy instances, shall contain pi1 and pi2==" +RESULT="json:[ \"pi2\" ]" +do_curl GET /A1-P/v2/policytypes/STD_1/policies 200 + +echo "=== API: Get policy status ===" +RESULT="json:{\"enforceStatus\": \"\", \"enforceReason\": \"\"}" +do_curl GET /A1-P/v2/policytypes/STD_1/policies/pi2/status 200 + +echo "=== Set status for policy instance pi2 ===" +RESULT="Status set to OK for policy: pi2" +do_curl PUT '/status?policyid=pi2&status=OK' 200 + +echo "=== API: Get policy status ===" +RESULT="json:{\"enforceStatus\": \"OK\"}" +do_curl GET /A1-P/v2/policytypes/STD_1/policies/pi2/status 200 + +echo "=== Set status for policy instance pi2 ===" +RESULT="Status set to NOTOK and notok_reason for policy: pi2" +do_curl PUT '/status?policyid=pi2&status=NOTOK&reason=notok_reason' 200 + +echo "=== API: Get policy status ===" +RESULT="json:{\"enforceStatus\": \"NOTOK\", \"enforceReason\":\"notok_reason\"}" +do_curl GET /A1-P/v2/policytypes/STD_1/policies/pi2/status 200 + +echo "=== Send status for pi2===" +RESULT="json:{\"enforceStatus\": \"NOTOK\", \"enforceReason\": \"notok_reason\"}" +do_curl POST '/sendstatus?policyid=pi2' 200 + +echo "=== Get counter: datadelivery ===" +RESULT="0" +do_curl GET /counter/datadelivery 200 + +echo "=== Send data ===" +echo "{}" > .p.json +RESULT="" +do_curl POST /datadelivery 200 .p.json + +echo "=== Get counter: datadelivery ===" +RESULT="1" +do_curl GET /counter/datadelivery 200 + +echo "=== Get counter: intstance ===" +RESULT="1" +do_curl GET /counter/num_instances 200 + +echo "=== Get counter: types (shall be 0)===" +RESULT="1" +do_curl GET /counter/num_types 200 + +echo "=== Get counter: interface ===" +RESULT="STD_2.0.0" +do_curl GET /counter/interface 200 + +echo "=== Get counter: remote hosts ===" +RESULT="*" +do_curl GET /counter/remote_hosts 200 + +echo "********************" +echo "*** All tests ok ***" +echo "********************" diff --git a/near-rt-ric-simulator/test/STD_2.0.0/build_and_start.sh b/near-rt-ric-simulator/test/STD_2.0.0/build_and_start.sh new file mode 100755 index 0000000..2cba8c1 --- /dev/null +++ b/near-rt-ric-simulator/test/STD_2.0.0/build_and_start.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +# ============LICENSE_START=============================================== +# Copyright (C) 2020 Nordix Foundation. All rights reserved. +# ======================================================================== +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END================================================= +# + +# Script to build and start the container + +echo "Building image" +cd ../../ + +#Build the image +docker build -t a1test . + +docker stop a1StdSimulator > /dev/null 2>&1 +docker rm -f a1StdSimulator > /dev/null 2>&1 + +echo "Starting ric-sim" +#Run the container in interactive mode, unsecure port 8085, secure port 8185 +docker run -it -p 8085:8085 -p 8185:8185 -e A1_VERSION=STD_2.0.0 -e ALLOW_HTTP=true -e REMOTE_HOSTS_LOGGING=1 --volume "$PWD/certificate:/usr/src/app/cert" --name a1StdSimulator a1test diff --git a/near-rt-ric-simulator/test/STD_2.0.0/jsonfiles/pi1.json b/near-rt-ric-simulator/test/STD_2.0.0/jsonfiles/pi1.json new file mode 100644 index 0000000..25247a1 --- /dev/null +++ b/near-rt-ric-simulator/test/STD_2.0.0/jsonfiles/pi1.json @@ -0,0 +1,10 @@ +{ + "scope": { + "ueId": "ue1", + "qosId": "qos1" + }, + "statement": { + "priorityLevel": 5 + } +} + diff --git a/near-rt-ric-simulator/test/STD_2.0.0/jsonfiles/pi1_updated.json b/near-rt-ric-simulator/test/STD_2.0.0/jsonfiles/pi1_updated.json new file mode 100644 index 0000000..7b4ada7 --- /dev/null +++ b/near-rt-ric-simulator/test/STD_2.0.0/jsonfiles/pi1_updated.json @@ -0,0 +1,10 @@ +{ + "scope": { + "ueId": "ue1", + "qosId": "qos1" + }, + "statement": { + "priorityLevel": 6 + } +} + diff --git a/near-rt-ric-simulator/test/STD_2.0.0/jsonfiles/pi2.json b/near-rt-ric-simulator/test/STD_2.0.0/jsonfiles/pi2.json new file mode 100644 index 0000000..441a9cf --- /dev/null +++ b/near-rt-ric-simulator/test/STD_2.0.0/jsonfiles/pi2.json @@ -0,0 +1,10 @@ +{ + "scope": { + "ueId": "ue2", + "qosId": "qos2" + }, + "statement": { + "priorityLevel": 5 + } +} + diff --git a/near-rt-ric-simulator/test/STD_2.0.0/jsonfiles/std_1.json b/near-rt-ric-simulator/test/STD_2.0.0/jsonfiles/std_1.json new file mode 100644 index 0000000..9b0c302 --- /dev/null +++ b/near-rt-ric-simulator/test/STD_2.0.0/jsonfiles/std_1.json @@ -0,0 +1,56 @@ +{ + "policySchema": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "STD_1_0.2.0", + "description": "STD 1 policy type", + "type": "object", + "properties": { + "scope": { + "type": "object", + "properties": { + "ueId": { + "type": "string" + }, + "qosId": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "ueId", + "qosId" + ] + }, + "statement": { + "type": "object", + "properties": { + "priorityLevel": { + "type": "number" + } + }, + "additionalProperties": false, + "required": [ + "priorityLevel" + ] + } + } + }, + "statusSchema": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "STD_1_0.2.0", + "description": "STD 1 policy type status", + "type": "object", + "properties": { + "enforceStatus": { + "type": "string" + }, + "enforceReason": { + "type": "string" + }, + "additionalProperties": false, + "required": [ + "enforceStatus" + ] + } + } +} \ No newline at end of file diff --git a/near-rt-ric-simulator/test/common/.gitignore b/near-rt-ric-simulator/test/common/.gitignore new file mode 100644 index 0000000..bee8a64 --- /dev/null +++ b/near-rt-ric-simulator/test/common/.gitignore @@ -0,0 +1 @@ +__pycache__ diff --git a/near-rt-ric-simulator/test/common/test_common.sh b/near-rt-ric-simulator/test/common/test_common.sh index 6c669c1..a45a6ff 100755 --- a/near-rt-ric-simulator/test/common/test_common.sh +++ b/near-rt-ric-simulator/test/common/test_common.sh @@ -36,7 +36,7 @@ do_curl() { if [ $# -gt 3 ]; then curlstr=$curlstr" -H Content-Type:application/json --data-binary @"$4 fi - echo " CMD:"$curlstr + echo " CMD (${BASH_LINENO[0]}):"$curlstr res=$($curlstr) status=${res:${#res}-3} body=${res:0:${#res}-3} @@ -53,7 +53,6 @@ do_curl() { elif [[ "$RESULT" == "json:"* ]]; then result=${RESULT:5:${#RESULT}} #Remove 'json:' from the result string res=$(python ../common/compare_json.py "$result" "$body") - echo $res if [ $res -eq 0 ]; then echo " Expected json body :"$result echo " Body as expected" diff --git a/near-rt-ric-simulator/tests/.gitignore b/near-rt-ric-simulator/tests/.gitignore new file mode 100644 index 0000000..bee8a64 --- /dev/null +++ b/near-rt-ric-simulator/tests/.gitignore @@ -0,0 +1 @@ +__pycache__ diff --git a/near-rt-ric-simulator/tests/test_osc_2_1_0.py b/near-rt-ric-simulator/tests/test_osc_2_1_0.py index 31e70fd..9d70ed0 100644 --- a/near-rt-ric-simulator/tests/test_osc_2_1_0.py +++ b/near-rt-ric-simulator/tests/test_osc_2_1_0.py @@ -40,7 +40,7 @@ def test_apis(client): # Check used and implemented interfaces response=client.get(SERVER_URL+'container_interfaces') assert response.status_code == 200 - assert response.data == b"Current interface: OSC_2.1.0 All supported A1 interface yamls in this container: ['OSC_2.1.0', 'STD_1.1.3']" + assert response.data == b"Current interface: OSC_2.1.0 All supported A1 interface yamls in this container: ['OSC_2.1.0', 'STD_1.1.3', 'STD_2.0.0']" # Reset simulator instances response=client.post(SERVER_URL+'deleteinstances') diff --git a/near-rt-ric-simulator/tests/test_std_1_1_3.py b/near-rt-ric-simulator/tests/test_std_1_1_3.py index 0d2959a..721d7a6 100644 --- a/near-rt-ric-simulator/tests/test_std_1_1_3.py +++ b/near-rt-ric-simulator/tests/test_std_1_1_3.py @@ -38,7 +38,7 @@ def test_apis(client): # Check used and implemented interfaces response=client.get(SERVER_URL+'container_interfaces') assert response.status_code == 200 - assert response.data == b"Current interface: STD_1.1.3 All supported A1 interface yamls in this container: ['OSC_2.1.0', 'STD_1.1.3']" + assert response.data == b"Current interface: STD_1.1.3 All supported A1 interface yamls in this container: ['OSC_2.1.0', 'STD_1.1.3', 'STD_2.0.0']" # Reset simulator instances response=client.post(SERVER_URL+'deleteinstances') diff --git a/near-rt-ric-simulator/tests/test_std_2_0_0.py b/near-rt-ric-simulator/tests/test_std_2_0_0.py new file mode 100644 index 0000000..d63d4c3 --- /dev/null +++ b/near-rt-ric-simulator/tests/test_std_2_0_0.py @@ -0,0 +1,436 @@ +# ============LICENSE_START=============================================== +# Copyright (C) 2020 Nordix Foundation. All rights reserved. +# ======================================================================== +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END================================================= +# + +# This test case test the STD_2.0.0 version of the simulator + +import json +import time + +#Version of simulator +INTERFACE_VERSION="STD_2.0.0" + +from unittest_setup import SERVER_URL, HOST_IP, PORT_NUMBER, setup_env, get_testdata_dir, client + +#Setup env and import paths +setup_env(INTERFACE_VERSION) + +from compare_json import compare + +def test_apis(client): + + testdata=get_testdata_dir() + + # Header for json payload + header = { + "Content-Type" : "application/json" + } + + # Simulator hello world + response=client.get(SERVER_URL) + assert response.status_code == 200 + + # Check used and implemented interfaces + response=client.get(SERVER_URL+'container_interfaces') + assert response.status_code == 200 + assert response.data == b"Current interface: STD_2.0.0 All supported A1 interface yamls in this container: ['OSC_2.1.0', 'STD_1.1.3', 'STD_2.0.0']" + + # Reset simulator instances + response=client.post(SERVER_URL+'deleteinstances') + assert response.status_code == 200 + + # Reset simulator, all + response=client.post(SERVER_URL+'deleteall') + assert response.status_code == 200 + + # Get counter: interface + response=client.get(SERVER_URL+'counter/interface') + assert response.status_code == 200 + assert response.data == b"STD_2.0.0" + + # Get counter: remote hosts + response=client.get(SERVER_URL+'counter/remote_hosts') + assert response.status_code == 200 + + # Get counter: intstance + response=client.get(SERVER_URL+'counter/num_instances') + assert response.status_code == 200 + assert response.data == b"0" + + # Get counter: types + response=client.get(SERVER_URL+'counter/num_types') + assert response.status_code == 200 + assert response.data == b"0" + + # API: Get policy type, shall be empty + data_response = [ ] + response=client.get(SERVER_URL+'A1-P/v2/policytypes') + assert response.status_code == 200 + result=json.loads(response.data) + res=compare(data_response, result) + assert res == True + + # API: Get policy instances for type 1, type not found + data_response = {"title": "The policy type does not exist.", "status": 404, "instance": "1"} + response=client.get(SERVER_URL+'A1-P/v2/policytypes/1/policies') + assert response.status_code == 404 + result=json.loads(response.data) + res=compare(data_response, result) + assert res == True + + # API: Get policy instances, type not found + data_response = {"title": "The policy type does not exist.", "status": 404, "instance": "test"} + response=client.get(SERVER_URL+'A1-P/v2/policytypes/test/policies') + assert response.status_code == 404 + result=json.loads(response.data) + res=compare(data_response, result) + assert res == True + + # Put a policy type: STD_1 + with open(testdata+'std_1.json') as json_file: + data_response = b"Policy type STD_1 is OK." + json_payload=json.load(json_file) + response=client.put(SERVER_URL+'policytype?id=STD_1', headers=header, data=json.dumps(json_payload)) + assert response.status_code == 201 + assert data_response == response.data + + # Put a policy type: STD_1, again + with open(testdata+'std_1.json') as json_file: + data_response = b"Policy type STD_1 is OK." + json_payload=json.load(json_file) + response=client.put(SERVER_URL+'policytype?id=STD_1', headers=header, data=json.dumps(json_payload)) + assert response.status_code == 200 + assert data_response == response.data + + # API: Get policy type ids, shall contain type STD_1 + data_response = [ "STD_1" ] + response=client.get(SERVER_URL+'A1-P/v2/policytypes') + assert response.status_code == 200 + result=json.loads(response.data) + res=compare(data_response, result) + assert res == True + + # Delete a policy type: STD_1 + data_response = b"" + response=client.delete(SERVER_URL+'policytype?id=STD_1') + assert response.status_code == 204 + assert data_response == response.data + + # API: Get policy type ids, shall be empty + data_response = [ ] + response=client.get(SERVER_URL+'A1-P/v2/policytypes') + assert response.status_code == 200 + result=json.loads(response.data) + res=compare(data_response, result) + assert res == True + + # Put a policy type: STD_1 + with open(testdata+'std_1.json') as json_file: + data_response = b"Policy type STD_1 is OK." + json_payload=json.load(json_file) + response=client.put(SERVER_URL+'policytype?id=STD_1', headers=header, data=json.dumps(json_payload)) + assert response.status_code == 201 + assert data_response == response.data + + # API: Get policy type ids, shall contain type STD_1 + data_response = [ "STD_1" ] + response=client.get(SERVER_URL+'A1-P/v2/policytypes') + assert response.status_code == 200 + result=json.loads(response.data) + res=compare(data_response, result) + assert res == True + + # Get counter: types (shall be 1) + response=client.get(SERVER_URL+'counter/num_types') + assert response.status_code == 200 + assert response.data == b"1" + + # API: Get policy type: STD_1 + with open(testdata+'std_1.json') as json_file: + data_response = json.load(json_file) + response=client.get(SERVER_URL+'A1-P/v2/policytypes/STD_1') + assert response.status_code == 200 + result=json.loads(response.data) + res=compare(data_response, result) + assert res == True + + # API: API: Get policy instances, shall be empty + data_response = [] + response=client.get(SERVER_URL+'A1-P/v2/policytypes/STD_1/policies') + assert response.status_code == 200 + result=json.loads(response.data) + res=compare(data_response, result) + assert res == True + + # API: Create policy instance pi1 of type: STD_1 + with open(testdata+'pi1.json') as json_file: + json_payload=json.load(json_file) + response=client.put(SERVER_URL+'A1-P/v2/policytypes/STD_1/policies/pi1', headers=header, data=json.dumps(json_payload)) + assert response.status_code == 201 + result=json.loads(response.data) + res=compare(json_payload, result) + assert res == True + + # API: API: Get policy instance pi1 of type: STD_1 + with open(testdata+'pi1.json') as json_file: + data_response = json.load(json_file) + response=client.get(SERVER_URL+'A1-P/v2/policytypes/STD_1/policies/pi1') + assert response.status_code == 200 + result=json.loads(response.data) + res=compare(data_response, result) + assert res == True + + # API: Update policy instance pi1 of type: STD_1 + with open(testdata+'pi1.json') as json_file: + json_payload=json.load(json_file) + response=client.put(SERVER_URL+'A1-P/v2/policytypes/STD_1/policies/pi1', headers=header, data=json.dumps(json_payload)) + assert response.status_code == 200 + result=json.loads(response.data) + res=compare(json_payload, result) + assert res == True + + # API: Update policy instance pi1 of type: STD_1 + with open(testdata+'pi1_updated.json') as json_file: + json_payload=json.load(json_file) + response=client.put(SERVER_URL+'A1-P/v2/policytypes/STD_1/policies/pi1', headers=header, data=json.dumps(json_payload)) + assert response.status_code == 200 + result=json.loads(response.data) + res=compare(json_payload, result) + assert res == True + + # API: Duplicate policy instance pi2 of type: STD_1 + with open(testdata+'pi1_updated.json') as json_file: + data_response = {"title": "Duplicate, the policy json already exists.", "status": 400, "instance": "pi2"} + json_payload=json.load(json_file) + response=client.put(SERVER_URL+'A1-P/v2/policytypes/STD_1/policies/pi2', headers=header, data=json.dumps(json_payload)) + assert response.status_code == 400 + result=json.loads(response.data) + res=compare(data_response, result) + assert res == True + + # API: Get policy instances, shall contain pi1 + data_response = ["pi1"] + response=client.get(SERVER_URL+'A1-P/v2/policytypes/STD_1/policies') + assert response.status_code == 200 + result=json.loads(response.data) + res=compare(data_response, result) + assert res == True + + # Get counter: intstance + response=client.get(SERVER_URL+'counter/num_instances') + assert response.status_code == 200 + assert response.data == b"1" + + # Get counter: types + response=client.get(SERVER_URL+'counter/num_types') + assert response.status_code == 200 + assert response.data == b"1" + + # Set force response code 409. ===" + response=client.post(SERVER_URL+'forceresponse?code=409') + assert response.status_code == 200 + + # API: Get policy instances, shall fail + data_response = {"title" : "Conflict", "status" : 409, "detail" : "Request could not be processed in the current state of the resource"} + response=client.get(SERVER_URL+'A1-P/v2/policytypes/STD_1/policies') + assert response.status_code == 409 + result=json.loads(response.data) + res=compare(data_response, result) + assert res == True + + # API: API: Get policy status + data_response = {"enforceStatus" : "", "enforceReason" : ""} + response=client.get(SERVER_URL+'A1-P/v2/policytypes/STD_1/policies/pi1/status') + assert response.status_code == 200 + result=json.loads(response.data) + res=compare(data_response, result) + assert res == True + + # API: Create policy instance pi2 of type: STD_1 + with open(testdata+'pi2.json') as json_file: + json_payload=json.load(json_file) + response=client.put(SERVER_URL+'A1-P/v2/policytypes/STD_1/policies/pi2', headers=header, data=json.dumps(json_payload)) + assert response.status_code == 201 + result=json.loads(response.data) + res=compare(json_payload, result) + assert res == True + + # API: Update policy instance pi2 of type: STD_1 + with open(testdata+'pi2.json') as json_file: + json_payload=json.load(json_file) + response=client.put(SERVER_URL+'A1-P/v2/policytypes/STD_1/policies/pi2', headers=header, data=json.dumps(json_payload)) + assert response.status_code == 200 + result=json.loads(response.data) + res=compare(json_payload, result) + assert res == True + + # API: Get policy instances, shall contain pi1 and pi2 + data_response = ["pi1","pi2"] + response=client.get(SERVER_URL+'A1-P/v2/policytypes/STD_1/policies') + assert response.status_code == 200 + result=json.loads(response.data) + res=compare(data_response, result) + assert res == True + + # Get counter: intstance + response=client.get(SERVER_URL+'counter/num_instances') + assert response.status_code == 200 + assert response.data == b"2" + + # Get counter: types + response=client.get(SERVER_URL+'counter/num_types') + assert response.status_code == 200 + assert response.data == b"1" + + # Set force delay 10 + response=client.post(SERVER_URL+'forcedelay?delay=10') + assert response.status_code == 200 + assert response.data == b"Force delay: 10 sec set for all A1 responses" + + #start time stamp + start=time.time() + + # API: Get policy instances, shall contain pi1 and pi2 and delayed 10 sec + data_response = ["pi1","pi2"] + response=client.get(SERVER_URL+'A1-P/v2/policytypes/STD_1/policies') + assert response.status_code == 200 + result=json.loads(response.data) + res=compare(data_response, result) + assert res == True + + end=time.time() + + assert (end-start) > 9 + + # Reset force delay + response=client.post(SERVER_URL+'forcedelay') + assert response.status_code == 200 + assert response.data == b"Force delay: None sec set for all A1 responses" + + # API: API: Get policy instance pi1 of type: STD_1 + with open(testdata+'pi1_updated.json') as json_file: + data_response = json.load(json_file) + response=client.get(SERVER_URL+'A1-P/v2/policytypes/STD_1/policies/pi1') + assert response.status_code == 200 + result=json.loads(response.data) + res=compare(data_response, result) + assert res == True + + # API: API: Get policy instance pi2 of type: STD_1 + with open(testdata+'pi2.json') as json_file: + data_response = json.load(json_file) + response=client.get(SERVER_URL+'A1-P/v2/policytypes/STD_1/policies/pi2') + assert response.status_code == 200 + result=json.loads(response.data) + res=compare(data_response, result) + assert res == True + + # API: DELETE policy instance pi1 + data_response = b"" + response=client.delete(SERVER_URL+'A1-P/v2/policytypes/STD_1/policies/pi1') + assert response.status_code == 204 + assert data_response == response.data + + # API: Get policy instances, shall contain pi2 + data_response = ["pi2"] + response=client.get(SERVER_URL+'A1-P/v2/policytypes/STD_1/policies') + assert response.status_code == 200 + result=json.loads(response.data) + res=compare(data_response, result) + assert res == True + + # API: API: Get policy status + data_response = {"enforceStatus" : "", "enforceReason" : ""} + response=client.get(SERVER_URL+'A1-P/v2/policytypes/STD_1/policies/pi2/status') + assert response.status_code == 200 + result=json.loads(response.data) + res=compare(data_response, result) + assert res == True + + # Set status for policy instance pi2 + response=client.put(SERVER_URL+'status?policyid=pi2&status=OK') + assert response.status_code == 200 + + # API: API: Get policy status + data_response = {"enforceStatus" : "OK"} + response=client.get(SERVER_URL+'A1-P/v2/policytypes/STD_1/policies/pi2/status') + assert response.status_code == 200 + result=json.loads(response.data) + res=compare(data_response, result) + print(response.data) + assert res == True + + # Set status for policy instance pi2 + response=client.put(SERVER_URL+'status?policyid=pi2&status=NOTOK&reason=notok_reason') + assert response.status_code == 200 + + # API: API: Get policy status + data_response = {"enforceStatus" : "NOTOK", "enforceReason" : "notok_reason"} + response=client.get(SERVER_URL+'A1-P/v2/policytypes/STD_1/policies/pi2/status') + assert response.status_code == 200 + result=json.loads(response.data) + res=compare(data_response, result) + assert res == True + + + # #Found no way to test these functions + # #'sendstatus' will send a http request that will fail + # #since no server will receive the call + # #These function is instead tested when running the bash script in the 'test' dir + # # # Send status for pi2 + # # response=client.post(SERVER_URL+'sendstatus?policyid=pi2') + # # assert response.status_code == 200 + # # result=json.loads(response.data) + # # res=compare(data_get_status, result) + # # assert res == True + + # # # Send status, shall fail + # # response=client.post(SERVER_URL+'sendstatus') + # # assert response.status_code == 400 + + # Get counter: data_delivery + response=client.get(SERVER_URL+'counter/datadelivery') + assert response.status_code == 200 + assert response.data == b"0" + + # Send data + json_payload={} + response=client.post(SERVER_URL+'datadelivery', headers=header, data=json.dumps(json_payload)) + assert response.status_code == 200 + + # Get counter: data_delivery + response=client.get(SERVER_URL+'counter/datadelivery') + assert response.status_code == 200 + assert response.data == b"1" + + # Get counter: interface + response=client.get(SERVER_URL+'counter/interface') + assert response.status_code == 200 + assert response.data == b"STD_2.0.0" + + # Get counter: remote hosts + response=client.get(SERVER_URL+'counter/remote_hosts') + assert response.status_code == 200 + + # Get counter: intstance + response=client.get(SERVER_URL+'counter/num_instances') + assert response.status_code == 200 + assert response.data == b"1" + + # Get counter: types + response=client.get(SERVER_URL+'counter/num_types') + assert response.status_code == 200 + assert response.data == b"1" \ No newline at end of file diff --git a/tox.ini b/tox.ini index e27e15d..8250799 100644 --- a/tox.ini +++ b/tox.ini @@ -41,6 +41,8 @@ commands = {toxinidir}/near-rt-ric-simulator/tests/test_osc_2_1_0.py pytest --cov-append --cov {toxinidir}/near-rt-ric-simulator --cov-report xml --cov-report term-missing --cov-report html \ --cov-fail-under=70 {toxinidir}/near-rt-ric-simulator/tests/test_std_1_1_3.py + pytest --cov-append --cov {toxinidir}/near-rt-ric-simulator --cov-report xml --cov-report term-missing --cov-report html \ + --cov-fail-under=70 {toxinidir}/near-rt-ric-simulator/tests/test_std_2_0_0.py coverage xml -i # doc jobs