From 5ce1086464f022cfbc673062d3b9a1ec6ed3c7dc Mon Sep 17 00:00:00 2001 From: "halil.cakal" Date: Fri, 27 May 2022 15:04:29 +0100 Subject: [PATCH] Create an external web server building RESTful API -A Python server building REST supports HTTP/HTTPS protocols -Reviewed for patchset2 -patch set 3 : Create a secondary docker image and move external server inside in it -patch set 4 : Create Open API specs and move base API operations inside in it, change json schema of the test_message to a basic json file -patch set 5 : Implement set|reset forced response and forced delay including negative unit tests as well as get API for a single policy. Code review cleanup -patch set 6 : Change API URL of admin functions, add a test case to check if an request lasts for an amount of time, and clean-up. -patch set 7 : Remove container-tag.yaml. -patch set 8 : Make forced delay test case parametric function which expected delay time in seconds can be passed in. -patch set 9 : Fix typo. -patch set 10: Generate my own certificate and key. Issue-ID: NONRTRIC-755 Change-Id: I0ee622ad82e18639e4eb2d4a02863904f9bf3201 Signed-off-by: halil.cakal --- near-rt-ric-simulator/test/EXT_SRV/Dockerfile | 47 +++++ .../test/EXT_SRV/api/EXT_SRV_api.yaml | 205 +++++++++++++++++++++ .../test/EXT_SRV/certificate/cert.crt | 24 +++ .../EXT_SRV/certificate/generate_cert_and_key.sh | 26 +++ .../test/EXT_SRV/certificate/key.crt | 30 +++ .../test/EXT_SRV/certificate/pass | 1 + near-rt-ric-simulator/test/EXT_SRV/nginx.conf | 93 ++++++++++ near-rt-ric-simulator/test/EXT_SRV/src/main.py | 82 +++++++++ .../test/EXT_SRV/src/maincommon.py | 34 ++++ .../test/EXT_SRV/src/payload_logging.py | 60 ++++++ near-rt-ric-simulator/test/EXT_SRV/src/server.py | 164 +++++++++++++++++ near-rt-ric-simulator/test/EXT_SRV/src/start.sh | 31 ++++ .../test/EXT_SRV/src/var_declaration.py | 27 +++ .../test/EXT_SRV_TEST/basic_test.sh | 146 +++++++++++++++ .../test/EXT_SRV_TEST/build_and_start.sh | 45 +++++ .../test/EXT_SRV_TEST/jsonfiles/alpha_policy.json | 11 ++ .../test/EXT_SRV_TEST/jsonfiles/beta_policy.json | 11 ++ .../EXT_SRV_TEST/jsonfiles/forced_response.json | 5 + .../test/common/elapse_time_curl.sh | 93 ++++++++++ 19 files changed, 1135 insertions(+) create mode 100644 near-rt-ric-simulator/test/EXT_SRV/Dockerfile create mode 100644 near-rt-ric-simulator/test/EXT_SRV/api/EXT_SRV_api.yaml create mode 100644 near-rt-ric-simulator/test/EXT_SRV/certificate/cert.crt create mode 100644 near-rt-ric-simulator/test/EXT_SRV/certificate/generate_cert_and_key.sh create mode 100644 near-rt-ric-simulator/test/EXT_SRV/certificate/key.crt create mode 100644 near-rt-ric-simulator/test/EXT_SRV/certificate/pass create mode 100644 near-rt-ric-simulator/test/EXT_SRV/nginx.conf create mode 100644 near-rt-ric-simulator/test/EXT_SRV/src/main.py create mode 100644 near-rt-ric-simulator/test/EXT_SRV/src/maincommon.py create mode 100644 near-rt-ric-simulator/test/EXT_SRV/src/payload_logging.py create mode 100644 near-rt-ric-simulator/test/EXT_SRV/src/server.py create mode 100644 near-rt-ric-simulator/test/EXT_SRV/src/start.sh create mode 100644 near-rt-ric-simulator/test/EXT_SRV/src/var_declaration.py create mode 100644 near-rt-ric-simulator/test/EXT_SRV_TEST/basic_test.sh create mode 100644 near-rt-ric-simulator/test/EXT_SRV_TEST/build_and_start.sh create mode 100644 near-rt-ric-simulator/test/EXT_SRV_TEST/jsonfiles/alpha_policy.json create mode 100644 near-rt-ric-simulator/test/EXT_SRV_TEST/jsonfiles/beta_policy.json create mode 100644 near-rt-ric-simulator/test/EXT_SRV_TEST/jsonfiles/forced_response.json create mode 100644 near-rt-ric-simulator/test/common/elapse_time_curl.sh diff --git a/near-rt-ric-simulator/test/EXT_SRV/Dockerfile b/near-rt-ric-simulator/test/EXT_SRV/Dockerfile new file mode 100644 index 0000000..84144d7 --- /dev/null +++ b/near-rt-ric-simulator/test/EXT_SRV/Dockerfile @@ -0,0 +1,47 @@ +# ============LICENSE_START=============================================== +# Copyright (C) 2022 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================================================= +# + +FROM python:3.8-slim-buster + +RUN pip install connexion[swagger-ui] + +#install nginx and curl +RUN apt-get update && apt-get install -y nginx=1.14.* nginx-extras curl + +WORKDIR /usr/src/app + +COPY api api +COPY nginx.conf nginx.conf +COPY certificate /usr/src/app/cert +COPY src src + +ARG user=nonrtric +ARG group=nonrtric + +RUN groupadd $user && \ + useradd -r -g $group $user +RUN chown -R $user:$group /usr/src/app +RUN chown -R $user:$group /var/log/nginx +RUN chown -R $user:$group /var/lib/nginx +RUN chown -R $user:$group /etc/nginx/conf.d +RUN touch /var/run/nginx.pid +RUN chown -R $user:$group /var/run/nginx.pid + +USER ${user} + +RUN chmod +x src/start.sh +CMD src/start.sh diff --git a/near-rt-ric-simulator/test/EXT_SRV/api/EXT_SRV_api.yaml b/near-rt-ric-simulator/test/EXT_SRV/api/EXT_SRV_api.yaml new file mode 100644 index 0000000..d37db61 --- /dev/null +++ b/near-rt-ric-simulator/test/EXT_SRV/api/EXT_SRV_api.yaml @@ -0,0 +1,205 @@ +openapi: 3.0.0 +info: + title: 'External Server for A1 simulator' + version: 2.0.0 + description: | + External test server. + © 2022, O-RAN Alliance. + All rights reserved. +externalDocs: + description: 'An external server building CRUD RestFUL APIs which is provisioned by A1 simulator. It will be a refrence point for the callouts' + url: 'https://www.testserver/specifications' +servers: + - url: '{apiRoot}' + variables: + apiRoot: + default: 'https://testserver.com' +paths: + '/a1policies': + get: + operationId: server.get_all_a1_policies + description: 'Get all a1 policies' + tags: + - All a1policies + responses: + 200: + description: 'Array of all a1 policies' + content: + application/json: + schema: + type: array + items: + "$ref": "#/components/schemas/A1PolicyObject" + minItems: 0 + 429: + "$ref": "#/components/responses/429-TooManyRequests" + 503: + "$ref": "#/components/responses/503-ServiceUnavailable" + '/a1policy/{a1policyId}': + parameters: + - name: a1policyId + in: path + required: true + schema: + "$ref": "#/components/schemas/A1PolicyId" + get: + operationId: server.get_a1_policy + description: 'Query for an A1 policy' + tags: + - Single A1 Policy Object + responses: + 200: + description: 'The requested A1 policy object' + content: + application/json: + schema: + "$ref": "#/components/schemas/A1PolicyObject" + 404: + "$ref": "#/components/responses/404-NotFound" + 409: + "$ref": "#/components/responses/409-Conflict" + 429: + "$ref": "#/components/responses/429-TooManyRequests" + 503: + "$ref": "#/components/responses/503-ServiceUnavailable" + put: + operationId: server.put_a1_policy + description: 'Create an A1 policy' + tags: + - Individual A1 policy Object + requestBody: + required: true + content: + application/json: + schema: + "$ref": "#/components/schemas/A1PolicyObject" + responses: + 200: + description: 'The A1 policy was updated' + content: + application/json: + schema: + "$ref": "#/components/schemas/A1PolicyObject" + 201: + description: 'The A1 policy was created' + content: + application/json: + schema: + "$ref": "#/components/schemas/A1PolicyObject" + headers: + Location: + description: 'Contains the URI of the created A1 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" + + delete: + operationId: server.delete_a1_policy + description: 'Delete an A1 policy' + tags: + - Individual a1policy Object + responses: + 204: + description: 'The A1 policy was deleted' + 404: + "$ref": "#/components/responses/404-NotFound" + 429: + "$ref": "#/components/responses/429-TooManyRequests" + 503: + "$ref": "#/components/responses/503-ServiceUnavailable" + +components: + schemas: + # + # Representation objects + # + A1PolicyObject: + title: 'Title' + description: 'A generic A1 policy object' + type: object + + 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 + + A1PolicyId: + description: 'A1 policy identifier.' + type: string + + responses: + 400-BadRequest: + description: 'A1 policy 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/test/EXT_SRV/certificate/cert.crt b/near-rt-ric-simulator/test/EXT_SRV/certificate/cert.crt new file mode 100644 index 0000000..8e4e282 --- /dev/null +++ b/near-rt-ric-simulator/test/EXT_SRV/certificate/cert.crt @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIID+zCCAuOgAwIBAgIUdGlOkoRDHpVMWilOvEsiKhwP0U4wDQYJKoZIhvcNAQEL +BQAwgYwxCzAJBgNVBAYTAklFMRIwEAYDVQQIDAlXRVNUTUVBVEgxEDAOBgNVBAcM +B0FUSExPTkUxETAPBgNVBAoMCEVyaWNzc29uMQwwCgYDVQQLDANFU1QxETAPBgNV +BAMMCGVzdC50ZWNoMSMwIQYJKoZIhvcNAQkBFhRoYWxpbC5jYWthbEBlc3QudGVj +aDAeFw0yMjA2MDgxNDAzMjZaFw00OTEwMjMxNDAzMjZaMIGMMQswCQYDVQQGEwJJ +RTESMBAGA1UECAwJV0VTVE1FQVRIMRAwDgYDVQQHDAdBVEhMT05FMREwDwYDVQQK +DAhFcmljc3NvbjEMMAoGA1UECwwDRVNUMREwDwYDVQQDDAhlc3QudGVjaDEjMCEG +CSqGSIb3DQEJARYUaGFsaWwuY2FrYWxAZXN0LnRlY2gwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQCz6jckM1gDW/cpj/w5lmw5IvMe8LGJIodhd1d4Sjg0 +qOBleTDlG7c9/qfzP2JBV7fDN/+nBYIvoRp3UckuJqj7KKU9ZUu7wJ9ffAixz3xa +yfygWQF4IPfBlDqD9Pn5VULJteLIUxUv6Jx3Dz/c1lasAi2sNqOk5BckMT6xVrZQ ++sBcF+Qjo6b7mT0PsqvCmDeY/3QkmkKPzpuuEtsaQd6X3SKJ6yfVXArTPhrkePIU +wUDm1epg5kbMtGdXrO9aJExib6pSRIswWVmWLL6oJLImVq7VvV9SD033KZY9qPyk +R4OxMpN/VviDI9+gxCDLkdLDU/rGPKIj4JBctrCt9eExAgMBAAGjUzBRMB0GA1Ud +DgQWBBQZAkRome+A3RsZ1fQbcl+TYfzIsDAfBgNVHSMEGDAWgBQZAkRome+A3RsZ +1fQbcl+TYfzIsDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBR +LlTvSe+qxpw0yblQ9htAbw6s8nuCuNMV4T3GxQZMklAXXej8IE36lOFLNMvCIBsb +CPvjC34vADJDdNL6B/iWX+6h7zC6/QCtB3MvagMTxbZ+61uhrNqf/X+imVL8xbaK +Hw20eooowqqbbRpmmTR9J20vTXv9xF1QiqPgLbv6R0yHxky4GTeO42VtR/I9k9qK +VmC+7LM9BlTo1p/fHFfglt+/OdYgND0LGxLZkkNLZdX01KBqzE1xdn4z2MZxIkm8 +qXh7O/eDANHY2D/Uh9jF7mUGG1yaiJMrqsi8COE0BukI4xabAcxb8hSMvjHjMtDt +8FtKa3bbjHAH9I/C11gZ +-----END CERTIFICATE----- diff --git a/near-rt-ric-simulator/test/EXT_SRV/certificate/generate_cert_and_key.sh b/near-rt-ric-simulator/test/EXT_SRV/certificate/generate_cert_and_key.sh new file mode 100644 index 0000000..7e6d29c --- /dev/null +++ b/near-rt-ric-simulator/test/EXT_SRV/certificate/generate_cert_and_key.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# ============LICENSE_START=============================================== +# Copyright (C) 2022 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 will generate a self-signed certificate with password 'test' + +SUBJECT="/C=IE/ST=WESTMEATH/L=ATHLONE/O=Ericsson/OU=EST/CN=est.tech/emailAddress=halil.cakal@est.tech" +PW=test +echo $PW > pass + +openssl req -x509 -passout file:pass -newkey rsa:2048 -keyout key.crt -subj "$SUBJECT" -out cert.crt -days 9999 diff --git a/near-rt-ric-simulator/test/EXT_SRV/certificate/key.crt b/near-rt-ric-simulator/test/EXT_SRV/certificate/key.crt new file mode 100644 index 0000000..0804e6d --- /dev/null +++ b/near-rt-ric-simulator/test/EXT_SRV/certificate/key.crt @@ -0,0 +1,30 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIFHDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIX3ACKBAs5wUCAggA +MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECPPoseIGFm4PBIIEyA/wL1c+zb6s +ucyML47Ye9Xe4CFu1hzKRQ28BJlC/JKaPC0vn2JEwn1ZpuPy/Tiy3DoPiUkENvLQ +OgKBgjZdPGj1kv8dcWBg45RAo8gKw2uuw/8R29K+Ch44JTaTRdnYolky5ZijiyJN +i5MG5h7BNCHZg+eAat+o8NgNHCMoaVLN2q5NM5jlryoLUj0hUL/SQsx7FUfkDBX4 +VksLUaJgCTHiU4EPh1qPH/oh6vk8qYRw3Y9S7ot7Ghccbnzd3eHyflwmQROt7jGg +ufe9beVx43yjNzM5nm5W6W1xYPhRpVeFIlTZz4+UPEC0IaC/N8gR5gXPMfC61aYq +BlXq7XQxGqQokUtOpOBC3B1avflvTdQcP8L14Mo8BmHUKMoJAjC/dO3Rl932f+Rv +UWSprGKJIADr8BCYAIiVwCMa4sXefmXg+IeFNrTyKcR9Ew2bn2AbUy4GQjHVW78l +21cuc2VgnJq1+TqpJWkkJ95qcGRHB3JqbVdSsHLktkSa8mn/kn0TgkgmxCkAqcnz +/9/F1VNIpQ2NveVpBVVBk4yFudHkvJ3D1mJ1aDnimPe830pB5eSWnnM2ZS/U8xsc +3HDx0P36JqpoHdzdSrUx5fIE+rfIkhiSfb1uolurcVWlIb4AP3pVepWmQv9WGswP +AVdX80Mdv4sAWPWwxOHOienR2SWYy0pHxEmyNx3NdpAD/rDsJW6quMoauCtHLy1w +9nPh3mJrhi+AmAYyyZKdvTQhBj7JInwVX40uAnxuhIuwj1CcxOLNhFLOX6WLhNan +Boc9QveAXzY5PVq2crdR3zPxQRMPAbp2/DQ4VeMfLZbkNxvG0ATm7LqygMu51/q6 +OT0KgIAn+602Q7ncOdYj4PKqSO05BzNVWtWqRT1DxIg5cZbisNJo51X1AIW0BTlh +lhgbtHmwB80T367XPTSMp2gWjUVikSPO3+qc8pQEqqxFe5BsO3ueN2QoqzR77YbO +2CjXX7IXLxdqQhZJjiFLv8FbFDEG0dw2cNwmFw2fHSdCL0q0DYZK0glQv1QDtDTj +eiHO3pMSrvqB4e3EmitoskqPn/e+jjOsv9ETrTvOM0x2RftAm4MBozff7DqKs+uR +rQfAk5/HzRq0ARlw/xM8BoSd6lwV61bGegaH/+X/y5EU1Cy0hwZqhww1cT/DdGgJ +ukga3f8J7W/eNOHZzse2X1koBr4LarXgZigQGsW21V7Rg5HX6sAyBJGNcg61pBdi +SNJz2O76jUMNtZ1y3UvLZiuGcLPrQXCpm21EaMWWLbH6tSiz03r657DXIjtdN/Li +uoBqznQJ/EwYeicA+cFQkjbszxB96aVxM88fpGigOU6mWVYsi3/5DBDVSINtrzVh +0oHK0lar4iPuXNw9eQkk52MhQqHqCg5jtsiIGlVAFWDlVKnvGKoyVWzKmS3UsGWE +LDLpdvIHVTXMBaNwqLn6+7Tk6wgJ0OMAdc1CCJ+iGyLXnV3KIPJzMmit/aFHlhnq +tEFMvW+ghl1DyMTJUxgoGg246gttRgRTP0iR761A+mOAxo3Vdk8GoVUU2MI/VACe +WTYOIIwBwv1VK0j5O07hWyKL4ieoaMseJqplJOslfsAFb8pY7bvCsaN9tkhYhuHY +VfctyAvMEN0MWZO/g9vDsA== +-----END ENCRYPTED PRIVATE KEY----- diff --git a/near-rt-ric-simulator/test/EXT_SRV/certificate/pass b/near-rt-ric-simulator/test/EXT_SRV/certificate/pass new file mode 100644 index 0000000..9daeafb --- /dev/null +++ b/near-rt-ric-simulator/test/EXT_SRV/certificate/pass @@ -0,0 +1 @@ +test diff --git a/near-rt-ric-simulator/test/EXT_SRV/nginx.conf b/near-rt-ric-simulator/test/EXT_SRV/nginx.conf new file mode 100644 index 0000000..7b3e620 --- /dev/null +++ b/near-rt-ric-simulator/test/EXT_SRV/nginx.conf @@ -0,0 +1,93 @@ +# user www-data; +worker_processes auto; +pid /run/nginx.pid; +include /etc/nginx/modules-enabled/*.conf; + +env ALLOW_HTTP; + +events { + worker_connections 768; + # multi_accept on; +} + +http { + + ## + # Basic Settings + ## + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + # server_tokens off; + + # server_names_hash_bucket_size 64; + # server_name_in_redirect off; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + perl_set $allow_http 'sub { return $ENV{"ALLOW_HTTP"}; }'; + + server { # simple reverse-proxy + listen 8085; + listen [::]:8085; + server_name localhost; + if ($allow_http != true) { + return 444; + } + + # serve dynamic requests + location / { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass http://localhost:2222; + } + } + + server { # simple reverse-proxy + listen 8185 ssl; + listen [::]:8185 ssl; + server_name localhost; + ssl_certificate /usr/src/app/cert/cert.crt; + ssl_certificate_key /usr/src/app/cert/key.crt; + ssl_password_file /usr/src/app/cert/pass; + + # serve dynamic requests + location / { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass http://localhost:2222; + } + } + ## + # SSL Settings + ## + + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE + ssl_prefer_server_ciphers on; + + ## + # Logging Settings + ## + + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log; + + ## + # Gzip Settings + ## + + gzip on; + + # gzip_vary on; + # gzip_proxied any; + # gzip_comp_level 6; + # gzip_buffers 16 8k; + # gzip_http_version 1.1; + # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; +} \ No newline at end of file diff --git a/near-rt-ric-simulator/test/EXT_SRV/src/main.py b/near-rt-ric-simulator/test/EXT_SRV/src/main.py new file mode 100644 index 0000000..4323d10 --- /dev/null +++ b/near-rt-ric-simulator/test/EXT_SRV/src/main.py @@ -0,0 +1,82 @@ +# ============LICENSE_START=============================================== +# Copyright (C) 2022 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 +import sys +import requests + + +from flask import request, Response, Flask, json +from var_declaration import a1_policy_instances, forced_settings, app +from maincommon import check_apipath + +#Constants +TEXT_PLAIN='text/plain' + +check_apipath() + +# app is created in var_declarations + +import payload_logging # app var need to be initialized + +#Check alive function +@app.route('/', methods=['GET']) +def test(): + return Response("OK", 200, mimetype=TEXT_PLAIN) + +#Delete all created instances and status +@app.route('/serveradmin/deleteinstances', methods=['POST']) +def delete_instances(): + a1_policy_instances.clear() + return Response("All a1 policy instances deleted", 200, mimetype=TEXT_PLAIN) + +#Set|Reset force response to be returned from external server +#/a1policy/forceresponse?code= +@app.route('/serveradmin/forceresponse', methods=['POST']) +def forceresponse(): + + query_param=request.args.get('code') + forced_settings['code']=query_param + + if (query_param is None): + return Response("Force response code has been resetted for all external server responses", 200, mimetype=TEXT_PLAIN) + else: + return Response("Force response code: " + str(forced_settings['code']) + " set for all external server response until it is resetted", 200, mimetype=TEXT_PLAIN) + +#Set|Reset force delay response, in seconds, for all external server responses +#/a1policy/forcedelay?delay= +@app.route('/serveradmin/forcedelay', methods=['POST']) +def forcedelay(): + + query_param=request.args.get('delay') + forced_settings['delay']=query_param + + if (query_param is None): + return Response("Force delay has been resetted for all external server responses ", 200, mimetype=TEXT_PLAIN) + else: + return Response("Force delay: " + str(forced_settings['delay']) + " sec set for all external server responses until it is resetted ", 200, mimetype=TEXT_PLAIN) + +port_number = 2222 +if len(sys.argv) >= 2: + if isinstance(sys.argv[1], int): + port_number = sys.argv[1] + +#Import base RestFUL API functions from Open API +app.add_api('EXT_SRV_api.yaml') + +if __name__ == '__main__': + app.run(port=port_number, host="127.0.0.1", threaded=False) diff --git a/near-rt-ric-simulator/test/EXT_SRV/src/maincommon.py b/near-rt-ric-simulator/test/EXT_SRV/src/maincommon.py new file mode 100644 index 0000000..9dd0a0f --- /dev/null +++ b/near-rt-ric-simulator/test/EXT_SRV/src/maincommon.py @@ -0,0 +1,34 @@ +# ============LICENSE_START=============================================== +# Copyright (C) 2021 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 os +import sys +from pathlib import Path +from flask import Response +import socket +import ssl + +#Must exist +apipath=os.environ['APIPATH'] +#May exist +remote_hosts_logging=os.getenv('REMOTE_HOSTS_LOGGING') + +# Make sure the api path for the interface yaml file is set, otherwise exit +def check_apipath(): + if (apipath is None): + print("Env APIPATH not set. Exiting....") + sys.exit(1) diff --git a/near-rt-ric-simulator/test/EXT_SRV/src/payload_logging.py b/near-rt-ric-simulator/test/EXT_SRV/src/payload_logging.py new file mode 100644 index 0000000..9457d04 --- /dev/null +++ b/near-rt-ric-simulator/test/EXT_SRV/src/payload_logging.py @@ -0,0 +1,60 @@ +# ============LICENSE_START=============================================== +# Copyright (C) 2022 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================================================= +# + +from var_declaration import app +from flask import Flask, request, Response + +#Constants +TEXT_PLAIN='text/plain' + +#Vars +payload_log=True + +#Function to activate/deactivate http header and payload logging +@app.route('/payload_logging/', methods=['POST', 'PUT']) +def set_payload_logging(state): + global payload_log + if (state == "on"): + payload_log=True + elif (state == "off"): + payload_log=False + else: + return Response("Unknown state: "+state+" - use 'on' or 'off'", 400, mimetype=TEXT_PLAIN) + + return Response("Payload and header logging set to: "+state, 200, mimetype=TEXT_PLAIN) + +# Generic function to log http header and payload - called before the request +@app.app.before_request +def log_request_info(): + if (payload_log is True): + print('') + print('-----Request-----') + print('Req Headers: ', request.headers) + print('Req Body: ', request.get_data()) + +# Generic function to log http header and payload - called after the response +@app.app.after_request +def log_response_info(response): + if (payload_log is True): + print('-----Response-----') + print('Resp Headers: ', response.headers) + print('Resp Body: ', response.get_data()) + return response + +# Helper function to check loggin state +def is_payload_logging(): + return payload_log diff --git a/near-rt-ric-simulator/test/EXT_SRV/src/server.py b/near-rt-ric-simulator/test/EXT_SRV/src/server.py new file mode 100644 index 0000000..77286be --- /dev/null +++ b/near-rt-ric-simulator/test/EXT_SRV/src/server.py @@ -0,0 +1,164 @@ +# ============LICENSE_START=============================================== +# Copyright (C) 2022 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 flask import Flask, escape, request, Response, make_response +from jsonschema import validate +from var_declaration import a1_policy_instances, forced_settings + + +#Constsants +APPL_JSON='application/json' +APPL_PROB_JSON='application/problem+json' + +#Python implementation of EXT_SRV_api.yaml - Open API - + +# API Function: Get all a1 policy ids +def get_all_a1_policies(): + + if ((r := check_modified_response()) is not None): + return r + + res = list(a1_policy_instances) + return (res, 200) + +# API Function: Get A1 policy +def get_a1_policy(a1policyId): + + if ((r := check_modified_response()) is not None): + return r + + a1_policy_id=str(a1policyId) + + policykeys=a1_policy_instances.keys() + if (a1_policy_id not in policykeys): + pjson=create_problem_json(None, "The A1 policy requested does not exist.", 404, None, a1_policy_id) + return Response(json.dumps(pjson), 404, mimetype=APPL_PROB_JSON) + + return Response(json.dumps(a1_policy_instances[a1_policy_id]), 200, mimetype=APPL_JSON) + +# API Function: Create or update a a1policy +def put_a1_policy(a1policyId): + + if ((r := check_modified_response()) is not None): + return r + + a1_policy_id=str(a1policyId) + + try: + data = request.data + data = json.loads(data) + except Exception: + pjson=create_problem_json(None, "The a1policy is corrupt or missing.", 400, None, a1_policy_id) + return Response(json.dumps(pjson), 400, mimetype=APPL_PROB_JSON) + + policykeys=a1_policy_instances.keys() + + retcode=201 + if a1_policy_id in policykeys: + retcode=200 + + a1_policy_instances[a1_policy_id]=data + + if (retcode == 200): + return Response(json.dumps(data), 200, mimetype=APPL_JSON) + else: + headers={} + headers['Location']='/a1policy/' + a1_policy_id + return Response(json.dumps(data), 201, headers=headers, mimetype=APPL_JSON) + +# API Function: Delete a a1policy +def delete_a1_policy(a1policyId): + + if ((r := check_modified_response()) is not None): + return r + + a1_policy_id=str(a1policyId) + + policykeys=a1_policy_instances.keys() + if (a1_policy_id not in policykeys): + pjson=create_problem_json(None, "The a1policy does not exist.", 404, None, a1_policy_id) + return Response(json.dumps(pjson), 404, mimetype=APPL_PROB_JSON) + + del a1_policy_instances[a1_policy_id] + return Response('', 204, 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']) + 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/test/EXT_SRV/src/start.sh b/near-rt-ric-simulator/test/EXT_SRV/src/start.sh new file mode 100644 index 0000000..052a8e4 --- /dev/null +++ b/near-rt-ric-simulator/test/EXT_SRV/src/start.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +# ============LICENSE_START=============================================== +# Copyright (C) 2022 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================================================= +# + +#Set path to open api +export APIPATH=$PWD/api +echo "APIPATH set to: "$APIPATH + +cd src + +#start nginx +nginx -c /usr/src/app/nginx.conf + +#start near-rt-ric-simulator +echo "Path to main.py: "$PWD +python -u main.py diff --git a/near-rt-ric-simulator/test/EXT_SRV/src/var_declaration.py b/near-rt-ric-simulator/test/EXT_SRV/src/var_declaration.py new file mode 100644 index 0000000..1f40ec1 --- /dev/null +++ b/near-rt-ric-simulator/test/EXT_SRV/src/var_declaration.py @@ -0,0 +1,27 @@ +# ============LICENSE_START=============================================== +# Copyright (C) 2022 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================================================= +# + +from maincommon import apipath +import connexion + +#Main app +app = connexion.App(__name__, specification_dir=apipath) + +a1_policy_instances = {} +forced_settings = {} +forced_settings['code']=None +forced_settings['delay']=None diff --git a/near-rt-ric-simulator/test/EXT_SRV_TEST/basic_test.sh b/near-rt-ric-simulator/test/EXT_SRV_TEST/basic_test.sh new file mode 100644 index 0000000..14490be --- /dev/null +++ b/near-rt-ric-simulator/test/EXT_SRV_TEST/basic_test.sh @@ -0,0 +1,146 @@ +#!/bin/bash + +# ============LICENSE_START=============================================== +# Copyright (C) 2022 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, except arg 'nonsecure|secure', as this script + +print_usage() { + echo "Usage: ./basic_test.sh nonsecure|secure " + exit 1 +} + +if [ $# -ne 1 ]; then + print_usage +fi +if [ "$1" != "nonsecure" ] && [ "$1" != "secure" ]; then + print_usage +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 +. ../common/elapse_time_curl.sh + +echo "=== Simulator hello world ===" +RESULT="OK" +do_curl GET / 200 + +echo "=== Reset simulator a1policy instances ===" +RESULT="All a1 policy instances deleted" +do_curl POST /serveradmin/deleteinstances 200 + +echo "=== Reset force delay ===" +RESULT="Force delay has been resetted for all external server responses" +do_curl POST /serveradmin/forcedelay 200 + +echo "=== Put an a1 policy: alpha ===" +res=$(cat jsonfiles/alpha_policy.json) +RESULT="json:$res" +do_curl PUT /a1policy/alpha 201 jsonfiles/alpha_policy.json + +echo "=== Get an a1 policy: alpha ===" +res=$(cat jsonfiles/alpha_policy.json) +RESULT="json:$res" +do_curl GET /a1policy/alpha 200 + +echo "=== Put an a1 policy alpha to update ===" +res=$(cat jsonfiles/alpha_policy.json) +RESULT="json:$res" +do_curl PUT /a1policy/alpha 200 jsonfiles/alpha_policy.json + +echo "=== API: Get a1 policy ids, shall contain a1policy alpha ===" +RESULT="json:[\"alpha\"]" +do_curl GET /a1policies 200 + +echo "=== Delete an a1 policy: alpha ===" +RESULT="" +do_curl DELETE /a1policy/alpha 204 + +echo "=== Get an a1 policy: alpha, A1 policy instance not found ===" +RESULT="json:{\"title\": \"The A1 policy requested does not exist.\", \"status\": 404, \"instance\": \"alpha\"}" +do_curl GET /a1policy/alpha 404 + +echo "=== API: Get a1 policies, shall be empty ===" +RESULT="json:[]" +do_curl GET /a1policies 200 + +echo "=== Set force delay 5 sec ===" +RESULT="Force delay: 5 sec set for all external server responses until it is resetted" +do_curl POST '/serveradmin/forcedelay?delay=5' 200 + +echo "=== API: Get a1 policies, should respond after 5 seconds later ===" +RESULT="json:[]" +do_curl GET /a1policies 200 + +echo "=== API: Get A1 policy ids, shall wait at least sec and then respond ===" +RESULT="json:[]" +do_elapsetime_curl GET /a1policies 200 5 + +echo "=== Reset force delay ===" +RESULT="Force delay has been resetted for all external server responses" +do_curl POST /serveradmin/forcedelay 200 + +echo "=== Put an a1 policy: beta ===" +res=$(cat jsonfiles/beta_policy.json) +RESULT="json:$res" +do_curl PUT /a1policy/beta 201 jsonfiles/beta_policy.json + +echo "=== Put an a1 policy: alpha ===" +res=$(cat jsonfiles/alpha_policy.json) +RESULT="json:$res" +do_curl PUT /a1policy/alpha 201 jsonfiles/alpha_policy.json + +echo "=== API: Get a1 policy ids, shall contain a1policy beta and alpha ===" +RESULT="json:[\"beta\", \"alpha\"]" +do_curl GET /a1policies 200 + +echo "=== Set force response code: 500 ===" +RESULT="Force response code: 500 set for all external server response until it is resetted" +do_curl POST '/serveradmin/forceresponse?code=500' 200 + +echo "=== API: Get a1 policies, shall return reponse code 500 ==" +res=$(cat jsonfiles/forced_response.json) +RESULT="json:$res" +do_curl GET /a1policies 500 + +echo "=== Reset force response code ===" +RESULT="Force response code has been resetted for all external server responses" +do_curl POST /serveradmin/forceresponse 200 + +echo "=== Delete an a1policy: alpha ===" +RESULT="" +do_curl DELETE /a1policy/alpha 204 + +echo "=== API: Get a1policy ids, shall contain a1 policy beta ===" +RESULT="json:[\"beta\"]" +do_curl GET /a1policies 200 + +echo "********************" +echo "*** All tests ok ***" +echo "********************" diff --git a/near-rt-ric-simulator/test/EXT_SRV_TEST/build_and_start.sh b/near-rt-ric-simulator/test/EXT_SRV_TEST/build_and_start.sh new file mode 100644 index 0000000..4deea51 --- /dev/null +++ b/near-rt-ric-simulator/test/EXT_SRV_TEST/build_and_start.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +# ============LICENSE_START=============================================== +# Copyright (C) 2022 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 +# Make sure to run the simulator with the same arg as this script + +print_usage() { + echo "Usage: ./build_and_start.sh " + exit 1 +} + +if [ $# -ge 1 ]; then + print_usage +fi + +echo "Building external server image..." +cd ../EXT_SRV/ + +#Build the image +docker build -t external_server . + +docker stop externalserversimulator > /dev/null 2>&1 +docker rm -f externalserversimulator > /dev/null 2>&1 + +echo "Starting external server for A1 simulator callouts..." +echo "PWD path: "$PWD + +#Run the container in interactive mode, unsecure port 8085, secure port 8185 +docker run --rm -it -p 8085:8085 -p 8185:8185 -e ALLOW_HTTP=true --volume "$PWD/certificate:/usr/src/app/cert" --name externalserversimulator external_server diff --git a/near-rt-ric-simulator/test/EXT_SRV_TEST/jsonfiles/alpha_policy.json b/near-rt-ric-simulator/test/EXT_SRV_TEST/jsonfiles/alpha_policy.json new file mode 100644 index 0000000..66c2b63 --- /dev/null +++ b/near-rt-ric-simulator/test/EXT_SRV_TEST/jsonfiles/alpha_policy.json @@ -0,0 +1,11 @@ +{ + + "title": "A1 policy external server", + "description": "A1 policies notifying external server", + "type": "object", + "properties": { + "a1policyType": "alpha_test_policy", + "url" : "http://www.com" + } + +} diff --git a/near-rt-ric-simulator/test/EXT_SRV_TEST/jsonfiles/beta_policy.json b/near-rt-ric-simulator/test/EXT_SRV_TEST/jsonfiles/beta_policy.json new file mode 100644 index 0000000..a61c7fc --- /dev/null +++ b/near-rt-ric-simulator/test/EXT_SRV_TEST/jsonfiles/beta_policy.json @@ -0,0 +1,11 @@ +{ + + "title": "A1 policy external server", + "description": "A1 policies notifying external server", + "type": "object", + "properties": { + "a1policyType": "beta_test_policy", + "url" : "http://www.com" + } + +} diff --git a/near-rt-ric-simulator/test/EXT_SRV_TEST/jsonfiles/forced_response.json b/near-rt-ric-simulator/test/EXT_SRV_TEST/jsonfiles/forced_response.json new file mode 100644 index 0000000..7fb5ff2 --- /dev/null +++ b/near-rt-ric-simulator/test/EXT_SRV_TEST/jsonfiles/forced_response.json @@ -0,0 +1,5 @@ +{ + "title": "Unknown", + "status": "500", + "detail": "Not implemented response code" +} diff --git a/near-rt-ric-simulator/test/common/elapse_time_curl.sh b/near-rt-ric-simulator/test/common/elapse_time_curl.sh new file mode 100644 index 0000000..618ad42 --- /dev/null +++ b/near-rt-ric-simulator/test/common/elapse_time_curl.sh @@ -0,0 +1,93 @@ +#!/bin/bash + +# ============LICENSE_START=============================================== +# Copyright (C) 2022 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================================================= +# + +# Function to execute curl and compare + print result + +# Note: Env var PORT must be set to the intended port number +# Notre Env var HTTPX must be set to either 'http' or 'https' + +#args: [file] +#Expects the env $RESULT to contain the expected RESULT. +#If json, the RESULT shall begin with 'json:'. +#Any json parameter with unknown value shall be given as "????" to skip checking the value. +do_elapsetime_curl() { + if [ $# -lt 4 ]; then + echo "Need 4 or more parameters, [file]: "$@ + echo "Exiting test script....." + exit 1 + fi + + #capture total elapsetime via ~%{time_total} + curlstr="curl -X "$1" -skw %{http_code}~%{time_total} $HTTPX://localhost:"${PORT}${2}" -H accept:*/*" + if [ $# -gt 4 ]; then + curlstr=$curlstr" -H Content-Type:application/json --data-binary @"$4 + fi + echo " CMD (${BASH_LINENO[0]}):"$curlstr + res=$($curlstr) + + #target delay time for a single request + delay_time=$4 + + #extract time_total and get rid of its decimals points + left=$(echo $res | cut -d'~' -f1) + right=$(echo $res | cut -d'~' -f2) + elapsedtime=$(echo $right | cut -d'.' -f1) + + res=$left + status=${res:${#res}-3} + body=${res:0:${#res}-3} + + if [ $status -ne $3 ]; then + echo " Error status :"$status" Expected status: "$3 + echo " Body :"$body + echo "Exiting test script....." + exit 1 + elif [ $elapsedtime -lt $delay_time ]; then + echo " Elapsed time :"$elapsedtime" Expected delay time:"$delay_time "seconds" + echo "Exiting test script....." + exit 1 + else + echo " Delay OK :"$elapsedtime" (Expected)" + echo " Body :"$body + if [ "$RESULT" == "*" ]; then + echo " Body contents not checked" + elif [[ "$RESULT" == "json:"* ]]; then + result=${RESULT:5:${#RESULT}} #Remove 'json:' from the result string + res=$(python ../common/compare_json.py "$result" "$body") + if [ $res -eq 0 ]; then + echo " Expected json body :"$result + echo " Body as expected" + else + echo " Expected json body :"$result + echo "Exiting....." + exit 1 + fi + else + body="$(echo $body | tr -d '\n' )" + if [ "$RESULT" == "$body" ]; then + echo " Expected body :"$RESULT + echo " Body as expected" + else + echo " Expected body :"$RESULT + echo "Exiting....." + exit 1 + fi + fi + fi +} -- 2.16.6