Added payload logging and configurable duplicate check 97/6797/1
authorBjornMagnussonXA <bjorn.magnusson@est.tech>
Thu, 30 Sep 2021 06:43:45 +0000 (08:43 +0200)
committerBjornMagnussonXA <bjorn.magnusson@est.tech>
Thu, 30 Sep 2021 06:44:16 +0000 (08:44 +0200)
Issue-ID: NONRTRIC-605

Signed-off-by: BjornMagnussonXA <bjorn.magnusson@est.tech>
Change-Id: Idca5bacc4512a3b4ca6a2cddc42b6d45825f5ed1

26 files changed:
near-rt-ric-simulator/Dockerfile
near-rt-ric-simulator/README.md
near-rt-ric-simulator/container-tag.yaml
near-rt-ric-simulator/src/OSC_2.1.0/a1.py
near-rt-ric-simulator/src/OSC_2.1.0/main.py
near-rt-ric-simulator/src/OSC_2.1.0/var_declaration.py
near-rt-ric-simulator/src/STD_1.1.3/a1.py
near-rt-ric-simulator/src/STD_1.1.3/main.py
near-rt-ric-simulator/src/STD_1.1.3/var_declaration.py
near-rt-ric-simulator/src/STD_2.0.0/a1.py
near-rt-ric-simulator/src/STD_2.0.0/main.py
near-rt-ric-simulator/src/STD_2.0.0/var_declaration.py
near-rt-ric-simulator/src/common/maincommon.py
near-rt-ric-simulator/src/common/payload_logging.py [new file with mode: 0644]
near-rt-ric-simulator/src/common/utils.py
near-rt-ric-simulator/test/OSC_2.1.0/basic_test.sh
near-rt-ric-simulator/test/OSC_2.1.0/build_and_start.sh
near-rt-ric-simulator/test/STD_1.1.3/basic_test.sh
near-rt-ric-simulator/test/STD_1.1.3/build_and_start.sh
near-rt-ric-simulator/test/STD_2.0.0/basic_test.sh
near-rt-ric-simulator/test/STD_2.0.0/build_and_start.sh
near-rt-ric-simulator/test/STD_2.0.0/jsonfiles/std_2.json [new file with mode: 0644]
near-rt-ric-simulator/tests/test_osc_2_1_0.py
near-rt-ric-simulator/tests/test_std_1_1_3.py
near-rt-ric-simulator/tests/test_std_2_0_0.py
near-rt-ric-simulator/tests/unittest_setup.py

index b079d73..8b08972 100644 (file)
@@ -1,5 +1,5 @@
 #  ============LICENSE_START===============================================
-#  Copyright (C) 2020 Nordix Foundation. All rights reserved.
+#  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.
 
 FROM python:3.8-slim-buster
 
-WORKDIR /usr/src/app
-
 RUN pip install connexion[swagger-ui]
 
-#install nginx
-RUN apt-get update
-RUN apt-get install -y nginx=1.14.*
-RUN apt-get install -y nginx-extras
+#install nginx and curl
+RUN apt-get update && apt-get install -y nginx=1.14.* nginx-extras curl
 
-#install curl
-RUN apt-get install -y curl
+WORKDIR /usr/src/app
 
-COPY src src
 COPY api api
 COPY nginx.conf nginx.conf
 COPY certificate /usr/src/app/cert
+COPY src src
 
 RUN chmod +x src/start.sh
 CMD src/start.sh ${A1_VERSION}
index b3c35d2..ff8cf49 100644 (file)
@@ -75,6 +75,9 @@ URIs for admin operations:
 |  POST, force delayed response of all A1 operations | http://localhost:8085/forcedelay?delay=&lt;seconds&gt; |
 |  PUT, set status and optional reason, delete and timestamp | http://localhost:8085/status?status=&lt;status&gt;&amp;reason=&lt;reason&gt;[&amp;deleted=&lt;boolean&gt;][&amp;created\_at=&lt;timestamp&gt;]  |
 |  GET a counter  <br> (counter-name: 'num\_instances', 'num\_types', 'interface' or 'remote\_hosts') | http://localhost:8085/counter/&lt;counter-name&gt; |
+|  Turn on http header and payload logging | http://localhost:8085payload_logging/on |
+|  Turn off http header and payload logging | http://localhost:8085payload_logging/off |
+
 
 
 # Supported operations in simulator A1 Standard 1.1.3
@@ -105,6 +108,8 @@ URIs for admin operations:
 |  PUT, set status and optional reason | http://localhost:8085/status?status=&lt;status&gt;[&amp;reason=&lt;reason&gt;] |
 |  POST, send status for policy | http://localhost:8085/sendstatus?policyid=&lt;policyid&gt; |
 |  GET a counter <br> (counter-name: 'num\_instances', 'num\_types'(always 0), 'interface' or 'remote\_hosts') | http://localhost:8085/counter/&lt;counter-name&gt; |
+|  Turn on http header and payload logging | http://localhost:8085payload_logging/on |
+|  Turn off http header and payload logging | http://localhost:8085payload_logging/off |
 
 # Supported operations in simulator A1 Standard 2.0.0
 
@@ -140,12 +145,17 @@ URIs for admin operations:
 |  POST, send status for policy | http://localhost:8085/sendstatus?policyid=&lt;policyid&gt; |
 |  POST, deliver data | http://localhost:8085/datadelivery |
 |  GET a counter <br> (counter-name: 'num\_instances', 'num\_types'(always 0), 'interface', 'remote\_hosts' or 'datadelivery') | http://localhost:8085/counter/&lt;counter-name&gt; |
-
+|  Turn on http header and payload logging | http://localhost:8085payload_logging/on |
+|  Turn off http header and payload logging | http://localhost:8085payload_logging/off |
 
 
 # Configuring the simulator
 An env variable, A1\_VERSION need to be passed to the container at start to select the desired interface version. The variable shall be set to one of the version-ids shown in the table in the first section. For example A1\_VERSIION=STD\_1.1.3.
+
 An env variable, REMOTE_HOSTS_LOGGING, can be set (any value is ok) and the the counter remote\_hosts will log the host names of all remote hosts that has accessed the A1 URIs. If host names cannot be resolved, the ip address of the remote host is logged instead. This logging is default off so must be configured to be enabled. If not configured, the counter remote\_hosts will return a fixed text indicating that host name logging is not enabled. Use this feature with caution, remote host lookup may take time in certain environments.
+
+And optional env variable, DUPLICATE_CHECK, can be set to '1' to turn on duplicate check of policiy json. A duplicate policy is when the policy json is exactly same as for a different policy id of the same type.  This function is default set off if the variable is not set at all or set to '0'.
+
 The simulator can also run using the https protocol. The enable https, a valid certificate and key need to provided. There is self-signed certificate available in the certificate dir and that dir shall be mounted to the container to make it available
 
 By default, this image has default certificates under /usr/src/app/cert
@@ -155,14 +165,16 @@ file "generate_cert_and_key.sh" is a shell script to generate certificate and ke
 file "pass" stores the password when you run the shell script
 
 Start the a1-interface container without specifing external certificates:
-'docker run -it -p 8085:8085 -p 8185:8185 -e A1\_VERSION=STD\_1.1.3 -e REMOTE_HOSTS_LOGGING=1 a1test'
+
+'docker run --rm -it -p 8085:8085 -p 8185:8185 -e A1\_VERSION=STD\_1.1.3 -e REMOTE_HOSTS_LOGGING=1 -e DUPLICATE_CHECK=0 a1test'
 
 It will listen to https 8185 port(using default certificates) by default.
 Http can be enabled on port 8085 using an environment variable "ALLOW_HTTP".
 If this environment variable is left out or set to false, the nginx server will send
 "444 Connection Closed Without Response" when making a call using http.
 Example command to enable http:
-'docker run -it -p 8085:8085 -p 8185:8185 -e A1\_VERSION=OSC\_2.1.0 -e ALLOW_HTTP=true a1test'
+
+'docker run -it -p 8085:8085 -p 8185:8185 -e A1\_VERSION=OSC\_2.1.0 -e ALLOW_HTTP=true -e DUPLICATE_CHECK=0 a1test'
 
 This certificates/key can be overriden by mounting a volume when using "docker run" or "docker-compose"
 In 'docker run', use field:
@@ -171,10 +183,17 @@ In 'docker-compose.yml', use field:
 volumes:
       - ./certificate:/usr/src/app/cert:ro
 
-In docker run the full command could look like this:<br> '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 /PATH_TO_CERT_DIR/certificate:/usr/src/app/cert a1test'
+In docker run the full command could look like this:<br>
+'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 -e DUPLICATE_CHECK=0 --volume /PATH_TO_CERT_DIR/certificate:/usr/src/app/cert a1test'
+
 http port 8085 and https port 8185
+
 The variable for A1 version is set with the '-e' flag.
+
 With logging of remote host enabled "-e REMOTE_HOSTS_LOGGING=1 "
+
+With policy json duplicate check set to off (0)
+
 With certificate dir mounted  "--volume /PATH_TO_CERT_DIR/certificate:/usr/src/app/cert"
 
 # Updating the openapi specs
@@ -193,11 +212,17 @@ Go to the test folder of the selected version, 'test/&lt;version&gt;/.
 
 Note that test can be performed both using the nonsecure http port and the secure https port.
 
-Build and start the simulator container using: ./build\_and\_start.sh
+Build and start the simulator container using:
+
+./build\_and\_start.sh duplicate-check|ignore-duplicate
+
+
 This will build and start the container in interactive mode. The built container only resides in the local docker repository.
 Note, the default port is 8085 for http and 8185 for https. When running the simulator as a container, the defualt ports can be re-mapped to any port on the localhost.
 
-In a second terminal, go to the same folder and run the basic test script, basic\_test.sh nonsecure|secure or commands.sh nonsecure|secure depending on version.
+In a second terminal, go to the same folder and run the basic test script, basic\_test.sh nonsecure|secure or commands.sh nonsecure|secure duplicate-check|ignore-duplicate
+
+Note that the arg for duplicate check must match in both scripts.
 This script runs a number of tests towards the simulator to make sure it works properply.
 
 # Basic test and code coverage
@@ -207,16 +232,17 @@ Only http is tested as the internal flask server is only using http (https is pa
 
 Navigate to 'near-rt-ric-simulator/tests'. Choose the version to test and use that file for test.
 
-Use 'python3 -m pytest <filename>' to run unit test only with no coverage check
+Use 'python3 -m pytest \<filename>' to run unit test only with no coverage check
+
+Or use 'coverage run  -m pytest \<filename>' to run unit test and produce coverage data.
 
-Or use 'coverage run  -m pytest <filename>' to run unit test and produce coverage data.
 List coverage data by 'coverage report -m --include=../../*' - the include flag makes the list to only contain coverage data from the simulator python file.
 
 To use the 'coverage' cmd, coverage need to be installed use 'pip install coverage'
 
 ## License
 
-Copyright (C) 2019 Nordix Foundation.
+Copyright (C) 2021 Nordix Foundation.
 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
index 6ec59ff..b343e30 100644 (file)
@@ -1,5 +1,5 @@
 #  ============LICENSE_START===============================================
-#  Copyright (C) 2020 Nordix Foundation. All rights reserved.
+#  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.
@@ -25,11 +25,20 @@ from flask import Flask, request, Response
 from jsonschema import validate
 from var_declaration import policy_instances, policy_types, policy_status, policy_fingerprint, forced_settings, hosts_set
 from utils import calcFingerprint
-from maincommon import extract_host_name
+from maincommon import extract_host_name, is_duplicate_check
+from payload_logging import is_payload_logging
 
 #Constsants
 APPL_JSON='application/json'
 
+
+#Helper funtion to log http reponse
+def log_resp_text(msg):
+  global payload_log
+  if (is_payload_logging()):
+    print("-----Error description-----")
+    print(str(msg))
+
 # API Function: Health check
 def get_healthcheck():
 
@@ -63,6 +72,7 @@ def get_policy_type(policy_type_id):
   policy_type_id=str(policy_type_id)
 
   if (policy_type_id not in policy_types.keys()):
+    log_resp_text("Policy type id not found")
     return (None, 404)
 
   return Response(json.dumps(policy_types[policy_type_id]), 200, mimetype=APPL_JSON)
@@ -78,9 +88,11 @@ def delete_policy_type(policy_type_id):
   policy_type_id=str(policy_type_id)
 
   if (policy_type_id not in policy_instances.keys()):
+    log_resp_text("Policy type not found")
     return (None, 404)
 
   if (len(policy_instances[policy_type_id]) > 0):
+    log_resp_text("Policy type cannot be removed, instances exists")
     return (None, 400)
 
   del policy_instances[policy_type_id]
@@ -106,15 +118,18 @@ def create_policy_type(policy_type_id):
 
   if (policy_type_id in policy_instances.keys()):
     if (len(policy_instances[policy_type_id]) > 0):
+      log_resp_text("Policy type id already exists")
       return (None, 400)
 
   try:
     data = request.data
     data = json.loads(data)
   except Exception:
+    log_resp_text("Policy type validation failure")
     return (None, 400)
 
   if (('name' not in data.keys()) or ('description' not in data.keys()) or ('policy_type_id' not in data.keys()) or ('create_schema' not in data.keys())):
+    log_resp_text("Parameters missing in policy type")
     return (None, 400)
 
   if (policy_type_id not in policy_instances.keys()):
@@ -136,6 +151,7 @@ def get_all_policy_identities(policy_type_id):
   policy_type_id=str(policy_type_id)
 
   if (policy_type_id not in policy_instances.keys()):
+    log_resp_text("Policy type id not found")
     return (None, 404)
   return (list(policy_instances[policy_type_id].keys()), 200)
 
@@ -150,9 +166,11 @@ def get_policy_instance(policy_type_id, policy_instance_id):
   policy_type_id=str(policy_type_id)
 
   if (policy_type_id not in policy_instances.keys()):
+    log_resp_text("Policy type id not found")
     return (None, 404)
 
   if (policy_instance_id not in policy_instances[policy_type_id].keys()):
+    log_resp_text("Policy instance id not found")
     return (None, 404)
 
   return Response(json.dumps(policy_instances[policy_type_id][policy_instance_id]), 200, mimetype=APPL_JSON)
@@ -168,12 +186,18 @@ def delete_policy_instance(policy_type_id, policy_instance_id):
   policy_type_id=str(policy_type_id)
 
   if (policy_type_id not in policy_instances.keys()):
+    log_resp_text("Policy type id not found")
     return (None, 404)
 
   if (policy_instance_id not in policy_instances[policy_type_id].keys()):
+    log_resp_text("Policy instance id not found")
     return (None, 404)
 
-  fp_previous=calcFingerprint(policy_instances[policy_type_id][policy_instance_id])
+  if (is_duplicate_check()):
+    fp_previous=calcFingerprint(policy_instances[policy_type_id][policy_instance_id], policy_type_id)
+  else:
+    fp_previous=policy_instance_id
+
   del policy_fingerprint[fp_previous]
   del policy_instances[policy_type_id][policy_instance_id]
   del policy_status[policy_instance_id]
@@ -191,31 +215,43 @@ def create_or_replace_policy_instance(policy_type_id, policy_instance_id):
   policy_type_id=str(policy_type_id)
 
   if (policy_type_id not in policy_instances.keys()):
+    log_resp_text("Policy type id not found")
     return (None, 404)
 
   try:
     data = request.data
     data = json.loads(data)
   except Exception:
+    log_resp_text("Policy json error")
     return (None, 400)
 
   try:
     validate(instance=data, schema=policy_types[policy_type_id]['create_schema'])
   except Exception:
+    log_resp_text("Policy validation error")
     return (None, 400)
 
   fp_previous=None
   if policy_instance_id in policy_instances[policy_type_id].keys():
-    retcode=200
-    fp_previous=calcFingerprint(policy_instances[policy_type_id][policy_instance_id])
+    if (is_duplicate_check()):
+      fp_previous=calcFingerprint(policy_instances[policy_type_id][policy_instance_id], policy_type_id)
+    else:
+      fp_previous=policy_instance_id
+
   else:
     if (policy_instance_id in policy_fingerprint.values()):
+      log_resp_text("Policy id already exist for other type")
       return (None, 400)
 
-  fp=calcFingerprint(data)
-  if (fp in policy_fingerprint.keys()):
+  if (is_duplicate_check()):
+    fp=calcFingerprint(data, policy_type_id)
+  else:
+    fp=policy_instance_id
+
+  if ((fp in policy_fingerprint.keys()) and is_duplicate_check()):
     p_id=policy_fingerprint[fp]
     if (p_id != policy_instance_id):
+      log_resp_text("Policy json duplicate of other instance")
       return (None, 400)
 
   if (fp_previous is not None):
@@ -242,9 +278,11 @@ def get_policy_instance_status(policy_type_id, policy_instance_id):
 
   policy_type_id=str(policy_type_id)
   if (policy_type_id not in policy_instances.keys()):
+    log_resp_text("Policy type id not found")
     return (None, 404)
 
   if (policy_instance_id not in policy_instances[policy_type_id].keys()):
+    log_resp_text("Policy instance id not found")
     return (None, 404)
 
   return Response(json.dumps(policy_status[policy_instance_id]), 200, mimetype=APPL_JSON)
@@ -267,7 +305,6 @@ def do_delay():
       time.sleep(val)
     except Exception:
       return
-  return
 
 # Helper: Check if response shall be delayed or a forced response shall be sent
 def check_modified_response():
index e0766d8..18bc03b 100644 (file)
@@ -1,5 +1,5 @@
 #  ============LICENSE_START===============================================
-#  Copyright (C) 2020 Nordix Foundation. All rights reserved.
+#  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.
@@ -24,7 +24,7 @@ import requests
 from pathlib import Path
 from flask import Flask, escape, request, Response, jsonify
 from jsonschema import validate
-from var_declaration import policy_instances, policy_types, policy_status, policy_fingerprint, forced_settings, hosts_set
+from var_declaration import policy_instances, policy_types, policy_status, policy_fingerprint, forced_settings, hosts_set, app
 from maincommon import check_apipath, apipath, get_supported_interfaces_response, extract_host_name
 from time import sleep
 
@@ -33,7 +33,9 @@ TEXT_PLAIN='text/plain'
 
 check_apipath()
 
-app = connexion.FlaskApp(__name__, specification_dir=apipath)
+# app is created in var_declarations
+
+import payload_logging   # app var need to be initialized
 
 #Check alive function
 @app.route('/', methods=['GET'])
index 5fe0469..f4ff6ac 100644 (file)
@@ -1,5 +1,5 @@
 #  ============LICENSE_START===============================================
-#  Copyright (C) 2020 Nordix Foundation. All rights reserved.
+#  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.
 #  ============LICENSE_END=================================================
 #
 
+from maincommon import apipath
+import connexion
+
+#Main app
+app = connexion.FlaskApp(__name__, specification_dir=apipath)
+
 policy_types={}
 policy_instances={}
 policy_status={}
index d7169b1..23f405a 100644 (file)
@@ -1,5 +1,5 @@
 #  ============LICENSE_START===============================================
-#  Copyright (C) 2020 Nordix Foundation. All rights reserved.
+#  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.
@@ -26,7 +26,7 @@ from connexion import NoContent
 from flask import Flask, escape, request, Response, make_response
 from var_declaration import policy_instances, 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
+from maincommon import check_apipath, apipath, get_supported_interfaces_response, extract_host_name, is_duplicate_check
 
 #Constsants
 APPL_JSON='application/json'
@@ -61,9 +61,16 @@ def put_policy(policyId):
   retcode=201
   if policyId in policy_instances.keys():
     retcode=200
-    fp_previous=calcFingerprint(policy_instances[policyId])
+    if (is_duplicate_check()):
+      fp_previous=calcFingerprint(policy_instances[policyId])
+    else:
+      fp_previous=policyId
+
+  if (is_duplicate_check()):
+    fp=calcFingerprint(data)
+  else:
+    fp=policyId
 
-  fp=calcFingerprint(data)
   if (fp in policy_fingerprint.keys()):
     p_id=policy_fingerprint[fp]
     if (p_id != policyId):
@@ -113,7 +120,11 @@ def delete_policy(policyId):
     return r
 
   if policyId in policy_instances.keys():
-    fp_previous=calcFingerprint(policy_instances[policyId])
+    if (is_duplicate_check()):
+      fp_previous=calcFingerprint(policy_instances[policyId])
+    else:
+      fp_previous=policyId
+
     policy_fingerprint.pop(fp_previous)
     policy_instances.pop(policyId)
     policy_status.pop(policyId)
index 5742791..7db215a 100644 (file)
@@ -1,5 +1,5 @@
 #  ============LICENSE_START===============================================
-#  Copyright (C) 2020 Nordix Foundation. All rights reserved.
+#  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.
@@ -25,7 +25,7 @@ import requests
 from pathlib import Path
 from flask import Flask, escape, request, Response
 from jsonschema import validate
-from var_declaration import policy_instances, policy_status, callbacks, forced_settings, policy_fingerprint, hosts_set
+from var_declaration import policy_instances, policy_status, callbacks, forced_settings, policy_fingerprint, hosts_set, app
 from maincommon import check_apipath, apipath, get_supported_interfaces_response, extract_host_name
 
 #Constants
@@ -33,7 +33,9 @@ TEXT_PLAIN='text/plain'
 
 check_apipath()
 
-app = connexion.App(__name__, specification_dir=apipath)
+# app is created in var_declarations
+
+import payload_logging   # app var need to be initialized
 
 #Check alive function
 @app.route('/', methods=['GET'])
@@ -127,7 +129,7 @@ def sendstatus():
   cb=callbacks[policyid]
   try:
     resp=requests.post(cb,json=json.dumps(ps), verify=False) # NOSONAR
-  except:
+  except Exception:
     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)
index 06b0031..2fe9257 100644 (file)
@@ -1,5 +1,5 @@
 #  ============LICENSE_START===============================================
-#  Copyright (C) 2020 Nordix Foundation. All rights reserved.
+#  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.
 #  limitations under the License.
 #  ============LICENSE_END=================================================
 #
+
+import connexion
+from maincommon import apipath
+
+app = connexion.App(__name__, specification_dir=apipath)
+
 policy_instances = {}
 policy_status = {}
 callbacks = {}
index c4aa4ca..2dc7b55 100644 (file)
@@ -1,5 +1,5 @@
 #  ============LICENSE_START===============================================
-#  Copyright (C) 2020 Nordix Foundation. All rights reserved.
+#  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.
@@ -27,7 +27,7 @@ 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
+from maincommon import check_apipath, apipath, get_supported_interfaces_response, extract_host_name, is_duplicate_check
 
 #Constsants
 APPL_JSON='application/json'
@@ -107,13 +107,21 @@ def put_policy(policyTypeId, policyId):
   retcode=201
   if policy_id in policy_instances[policy_type_id].keys():
     retcode=200
-    fp_previous=calcFingerprint(policy_instances[policy_type_id][policy_id])
+    if (is_duplicate_check()):
+      fp_previous=calcFingerprint(policy_instances[policy_type_id][policy_id], policy_type_id)
+    else:
+      fp_previous=policy_id
   else:
     if (policy_id in policy_fingerprint.values()):
-      return (None, 400)
+      pjson=create_problem_json(None, "The policy id already exist for other policy type.", 400, None, policy_id)
+      return Response(json.dumps(pjson), 400, mimetype=APPL_PROB_JSON)
+
+  if (is_duplicate_check()):
+    fp=calcFingerprint(data, policy_type_id)
+  else:
+    fp=policy_id
 
-  fp=calcFingerprint(data)
-  if (fp in policy_fingerprint.keys()):
+  if ((fp in policy_fingerprint.keys()) and is_duplicate_check()):
     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)
@@ -183,7 +191,11 @@ def delete_policy(policyTypeId, policyId):
     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])
+  if (is_duplicate_check()):
+    fp_previous=calcFingerprint(policy_instances[policy_type_id][policy_id], policy_type_id)
+  else:
+    fp_previous=policy_id
+
   policy_fingerprint.pop(fp_previous)
   policy_instances[policy_type_id].pop(policy_id)
   policy_status.pop(policy_id)
index dcf835e..16e4a31 100644 (file)
@@ -1,5 +1,5 @@
 #  ============LICENSE_START===============================================
-#  Copyright (C) 2020 Nordix Foundation. All rights reserved.
+#  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.
@@ -25,7 +25,7 @@ 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 var_declaration import policy_instances, policy_types, policy_status, callbacks, forced_settings, policy_fingerprint, hosts_set, data_delivery_counter, app
 from maincommon import check_apipath, apipath, get_supported_interfaces_response, extract_host_name
 
 #Constants
@@ -33,7 +33,9 @@ TEXT_PLAIN='text/plain'
 
 check_apipath()
 
-app = connexion.App(__name__, specification_dir=apipath)
+# app is created in var_declarations
+
+import payload_logging   # app var need to be initialized
 
 #Check alive function
 @app.route('/', methods=['GET'])
@@ -61,9 +63,9 @@ def delete_instances():
   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():
+  global data_delivery_counter
 
   policy_instances.clear()
   policy_types.clear()
@@ -72,6 +74,7 @@ def delete_all():
   forced_settings['code']=None
   forced_settings['delay']=None
   policy_fingerprint.clear()
+  data_delivery_counter=0
   return Response("All policy instances and types deleted", 200, mimetype=TEXT_PLAIN)
 
 #Load a policy type
@@ -188,9 +191,8 @@ def sendstatus():
   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:
+  except Exception:
     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)
index 5136404..3bc4aa5 100644 (file)
@@ -1,5 +1,5 @@
 #  ============LICENSE_START===============================================
-#  Copyright (C) 2020 Nordix Foundation. All rights reserved.
+#  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.
 #  ============LICENSE_END=================================================
 #
 
+from maincommon import apipath
+import connexion
+
+#Main app
+app = connexion.App(__name__, specification_dir=apipath)
+
 policy_types={}
 policy_instances = {}
 policy_status = {}
index 7dc8024..131bf0d 100644 (file)
@@ -1,5 +1,5 @@
 #  ============LICENSE_START===============================================
-#  Copyright (C) 2020 Nordix Foundation. All rights reserved.
+#  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.
@@ -26,6 +26,7 @@ import ssl
 apipath=os.environ['APIPATH']
 #May exist
 remote_hosts_logging=os.getenv('REMOTE_HOSTS_LOGGING')
+duplicate_check=os.getenv('DUPLICATE_CHECK')
 
 # Make sure the api path for the interface yaml file is set, otherwise exit
 def check_apipath():
@@ -60,3 +61,13 @@ def extract_host_name(hosts_set, request):
             hosts_set.add(host_ip)
     else:
         hosts_set.add("logging_of_remote_host_names_not_enabled")
+
+# Function to check if duplicate check shall be made
+# True = check for duplicates
+# False = ignore duplicates
+def is_duplicate_check():
+    global duplicate_check
+
+    if ((duplicate_check is not None) and (duplicate_check == "1")):
+        return True
+    return False
diff --git a/near-rt-ric-simulator/src/common/payload_logging.py b/near-rt-ric-simulator/src/common/payload_logging.py
new file mode 100644 (file)
index 0000000..3316511
--- /dev/null
@@ -0,0 +1,60 @@
+#  ============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=================================================
+#
+
+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/<state>', 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
\ No newline at end of file
index 1ed2a7e..f0df448 100644 (file)
@@ -1,5 +1,5 @@
 #  ============LICENSE_START===============================================
-#  Copyright (C) 2020 Nordix Foundation. All rights reserved.
+#  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.
 #  ============LICENSE_END=================================================
 #
 
-#Calculate a fingerprint from sorted items of a dict
-def calcFingerprint(p):
+#Calculate a fingerprint from sorted items of a dict, appending an optional id
+def calcFingerprint(p, pid=None):
   m=''
+  ext=''
+  if (pid is not None):
+    ext=pid
   if (p is dict):
     for i in sorted (p.keys()):
       m = m+str(i)+calcFingerprint(p[i])
   else:
-    return str(p)
-  return m
\ No newline at end of file
+    return str(p)+ext
+  return m+ext
\ No newline at end of file
index bc2413d..2f70295 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/bash
 
 #  ============LICENSE_START===============================================
-#  Copyright (C) 2020 Nordix Foundation. All rights reserved.
+#  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.
 #
 
 # 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"
+# 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 duplicate-check|ignore-duplicate "
     exit 1
+}
+
+if [ $# -ne 2 ]; then
+    print_usage
 fi
 if [ "$1" != "nonsecure" ] && [ "$1" != "secure" ]; then
-    echo "Usage: ./basic_test.sh nonsecure|secure"
-    exit 1
+    print_usage
+fi
+if [ "$2" == "duplicate-check" ]; then
+    DUP_CHECK=1
+elif [ "$2" == "ignore-duplicate" ]; then
+    DUP_CHECK=0
+else
+    print_usage
 fi
 
 if [ $1 == "nonsecure" ]; then
@@ -118,9 +129,19 @@ echo "=== API: Get instances for type 1, shall contain pi1 ==="
 RESULT="json:[ \"pi1\" ]"
 do_curl GET '/a1-p/policytypes/1/policies' 200
 
-echo "=== API: Create policy instance pi2 (copy of pi1) of type: 1. Shall fail ==="
-RESULT=""
-do_curl PUT '/a1-p/policytypes/1/policies/pi2' 400 jsonfiles/pi1.json
+if [ $DUP_CHECK == 1 ]; then
+    echo "=== API: Create policy instance pi2 (copy of pi1) of type: 1. Shall fail ==="
+    RESULT=""
+    do_curl PUT '/a1-p/policytypes/1/policies/pi2' 400 jsonfiles/pi1.json
+else
+    echo "=== API: Create policy instance pi2 (copy of pi1) of type: 1. Shall succeed ==="
+    RESULT=""
+    do_curl PUT '/a1-p/policytypes/1/policies/pi2' 202 jsonfiles/pi1.json
+
+    echo "=== Delete policy instance: pi2 ==="
+    RESULT=""
+    do_curl DELETE '/a1-p/policytypes/1/policies/pi2' 202
+fi
 
 echo "=== Set force response code 401. ==="
 RESULT="*"
@@ -174,7 +195,7 @@ echo "=== API: Get instances for type 2, shall be empty ==="
 RESULT="json:[]"
 do_curl GET '/a1-p/policytypes/2/policies' 200
 
-echo "=== API: Create policy instance pi1 of type: 2, shall fail==="
+echo "=== API: Create duplicate policy instance id pi1 of type: 2 (pi1 exist for type 1), shall fail==="
 RESULT=""
 do_curl PUT '/a1-p/policytypes/2/policies/pi1' 400 jsonfiles/pi1.json
 
@@ -198,9 +219,44 @@ echo "=== API: Get instances for type 2, shall contain pi2 ==="
 RESULT="json:[ \"pi2\" ]"
 do_curl GET '/a1-p/policytypes/2/policies' 200
 
-echo "=== API: Create policy instance pi11 (copy of pi1) of type: 1. Shall fail ==="
-RESULT=""
-do_curl PUT '/a1-p/policytypes/1/policies/pi11' 400 jsonfiles/pi1.json
+if [ $DUP_CHECK == 1 ]; then
+    echo "=== API: Create policy instance pi11 (copy of pi1) of type: 1. Shall fail ==="
+    RESULT=""
+    do_curl PUT '/a1-p/policytypes/1/policies/pi11' 400 jsonfiles/pi1.json
+else
+    echo "=== API: Create policy instance pi11 (copy of pi1) of type: 1. Shall succeed ==="
+    RESULT=""
+    do_curl PUT '/a1-p/policytypes/1/policies/pi11' 202 jsonfiles/pi1.json
+
+    echo "=== Delete policy instance: pi11 ==="
+    RESULT=""
+    do_curl DELETE '/a1-p/policytypes/1/policies/pi11' 202
+fi
+
+if [ $DUP_CHECK == 1 ]; then
+    echo "=== API: Create policy instance pi3 (copy of pi1) of type: 2. Shall fail ==="
+    RESULT=""
+    do_curl PUT '/a1-p/policytypes/1/policies/pi3' 400 jsonfiles/pi1.json
+else
+    echo "=== API: Create policy instance pi3 (copy of pi1) of type: 1. Shall succeed ==="
+    RESULT=""
+    do_curl PUT '/a1-p/policytypes/1/policies/pi3' 202 jsonfiles/pi1.json
+
+    echo "=== Delete policy instance: pi3 ==="
+    RESULT=""
+    do_curl DELETE '/a1-p/policytypes/1/policies/pi3' 202
+fi
+
+
+echo "=== API: Get instances for type 1, shall contain pi1 ==="
+RESULT="json:[ \"pi1\" ]"
+do_curl GET '/a1-p/policytypes/1/policies' jsonfiles/200
+
+echo "=== API: Get instances for type 2, shall contain pi2 ==="
+RESULT="json:[ \"pi2\" ]"
+do_curl GET '/a1-p/policytypes/2/policies' 200
+
+
 
 echo "=== Set force response code 401. ==="
 RESULT="*"
index f376971..db27d49 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/bash
 
 #  ============LICENSE_START===============================================
-#  Copyright (C) 2020 Nordix Foundation. All rights reserved.
+#  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.
 #
 
 # 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 duplicate-check|ignore-duplicate "
+    exit 1
+}
+
+if [ $# -ne 1 ]; then
+    print_usage
+fi
+if [ $1 == "duplicate-check" ]; then
+    DUP_CHECK=1
+elif  [ $1 == "ignore-duplicate" ]; then
+    DUP_CHECK=0
+else
+    print_usage
+fi
 
 echo "Building image"
 cd ../../
@@ -28,7 +45,7 @@ docker build -t a1test .
 docker stop a1OscSimulator > /dev/null 2>&1
 docker rm -f a1OscSimulator > /dev/null 2>&1
 
-echo "Starting $1 mode"
+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=OSC_2.1.0 -e ALLOW_HTTP=true -e REMOTE_HOSTS_LOGGING=1 --volume "$PWD/certificate:/usr/src/app/cert" --name a1OscSimulator a1test
+docker run --rm -it -p 8085:8085 -p 8185:8185 -e A1_VERSION=OSC_2.1.0 -e ALLOW_HTTP=true -e REMOTE_HOSTS_LOGGING=1 -e DUPLICATE_CHECK=$DUP_CHECK --volume "$PWD/certificate:/usr/src/app/cert" --name a1OscSimulator a1test
 
index 3a828d2..af7093f 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/bash
 
 #  ============LICENSE_START===============================================
-#  Copyright (C) 2020 Nordix Foundation. All rights reserved.
+#  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.
 #
 
 # 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"
+# 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 duplicate-check|ignore-duplicate "
     exit 1
+}
+
+if [ $# -ne 2 ]; then
+    print_usage
 fi
 if [ "$1" != "nonsecure" ] && [ "$1" != "secure" ]; then
-    echo "Usage: ./basic_test.sh nonsecure|secure"
-    exit 1
+    print_usage
+fi
+if [ "$2" == "duplicate-check" ]; then
+    DUP_CHECK=1
+elif [ "$2" == "ignore-duplicate" ]; then
+    DUP_CHECK=0
+else
+    print_usage
 fi
 
 if [ $1 == "nonsecure" ]; then
@@ -75,9 +86,19 @@ echo "=== API: Get policy instances, shall contain pi1=="
 RESULT="json:[ \"pi1\" ]"
 do_curl GET /A1-P/v1/policies 200
 
-echo "=== API: Create policy instance pi2 (copy of pi1). Shall fail ==="
-RESULT="json:{\"title\": \"The policy json already exists.\", \"status\": 400, \"instance\": \"pi2\"}"
-do_curl PUT /A1-P/v1/policies/pi2 400 jsonfiles/pi1_updated.json
+if [ $DUP_CHECK == 1 ]; then
+    echo "=== API: Create policy instance pi2 (copy of pi1). Shall fail ==="
+    RESULT="json:{\"title\": \"The policy json already exists.\", \"status\": 400, \"instance\": \"pi2\"}"
+    do_curl PUT /A1-P/v1/policies/pi2 400 jsonfiles/pi1_updated.json
+else
+    echo "=== API: Create policy instance pi2 (copy of pi1). Shall succeed ==="
+    RESULT="json:{\"scope\": {\"ueId\": \"ue1\", \"groupId\": \"group1\", \"sliceId\": \"slice1\", \"qosId\": \"qos1\", \"cellId\": \"cell1\"}, \"statement\": {\"priorityLevel\": 5}}"
+    do_curl PUT /A1-P/v1/policies/pi2 201 jsonfiles/pi1.json
+
+    echo "=== API: DELETE policy instance pi2 ==="
+    RESULT=""
+    do_curl DELETE /A1-P/v1/policies/pi2 204
+fi
 
 echo "=== Set force response code 409. ==="
 RESULT="*"
index 1d56487..1ccd232 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/bash
 
 #  ============LICENSE_START===============================================
-#  Copyright (C) 2020 Nordix Foundation. All rights reserved.
+#  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.
 #
 
 # 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 duplicate-check|ignore-duplicate "
+    exit 1
+}
+
+if [ $# -ne 1 ]; then
+    print_usage
+fi
+if [ $1 == "duplicate-check" ]; then
+    DUP_CHECK=1
+elif  [ $1 == "ignore-duplicate" ]; then
+    DUP_CHECK=0
+else
+    print_usage
+fi
 
 echo "Building image"
 cd ../../
@@ -30,4 +47,4 @@ 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
+docker run --rm -it -p 8085:8085 -p 8185:8185 -e A1_VERSION=STD_1.1.3 -e ALLOW_HTTP=true -e REMOTE_HOSTS_LOGGING=1 -e DUPLICATE_CHECK=$DUP_CHECK  --volume "$PWD/certificate:/usr/src/app/cert" --name a1StdSimulator a1test
index 576bd5e..084a368 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/bash
 
 #  ============LICENSE_START===============================================
-#  Copyright (C) 2020 Nordix Foundation. All rights reserved.
+#  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.
 #
 
 # 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"
+# 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 duplicate-check|ignore-duplicate "
     exit 1
+}
+
+if [ $# -ne 2 ]; then
+    print_usage
 fi
 if [ "$1" != "nonsecure" ] && [ "$1" != "secure" ]; then
-    echo "Usage: ./basic_test.sh nonsecure|secure"
-    exit 1
+    print_usage
+fi
+if [ "$2" == "duplicate-check" ]; then
+    DUP_CHECK=1
+elif [ "$2" == "ignore-duplicate" ]; then
+    DUP_CHECK=0
+else
+    print_usage
 fi
 
 if [ $1 == "nonsecure" ]; then
@@ -148,17 +159,43 @@ 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==="
+echo "=== API: Duplicate policy instance json,  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
+if [ $DUP_CHECK == 1 ]; then
+    #Fail with dupl check
+    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
+else
+    #OK without dupl check
+    res=$(cat jsonfiles/pi1_updated.json)
+    RESULT="json:$res"
+    do_curl PUT /A1-P/v2/policytypes/STD_1/policies/pi2 201 jsonfiles/pi1_updated.json
+
+    echo "=== API: DELETE policy instance pi2 ==="
+    RESULT=""
+    do_curl DELETE /A1-P/v2/policytypes/STD_1/policies/pi2 204
+fi
 
 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"
+echo "=== Put a policy type: STD_2 ==="
+RESULT="Policy type STD_2 is OK."
+do_curl PUT  '/policytype?id=STD_2' 201 jsonfiles/std_2.json
+
+
+echo "=== API: Duplicate policy instance id pi1 of type: STD_2==="
+res=$(cat jsonfiles/pi1_updated.json)
+RESULT="json:{\"title\": \"The policy id already exist for other policy type.\", \"status\": 400, \"instance\": \"pi1\"}"
+do_curl PUT /A1-P/v2/policytypes/STD_2/policies/pi1 400 jsonfiles/pi1_updated.json
+
+echo "=== API: Get policy type ids, shall contain type STD_1  and STD_2 =="
+RESULT="json:[ \"STD_1\", \"STD_2\" ]"
+do_curl GET /A1-P/v2/policytypes 200
+
+echo "=== Get counter: types (shall be 2)==="
+RESULT="2"
 do_curl GET /counter/num_types 200
 
 echo "=== Get counter: intstance ==="
@@ -192,8 +229,8 @@ 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"
+echo "=== Get counter: types (shall be 2)==="
+RESULT="2"
 do_curl GET /counter/num_types 200
 
 echo "=== Get counter: intstance ==="
@@ -271,8 +308,8 @@ echo "=== Get counter: intstance ==="
 RESULT="1"
 do_curl GET /counter/num_instances 200
 
-echo "=== Get counter: types (shall be 0)==="
-RESULT="1"
+echo "=== Get counter: types (shall be 2)==="
+RESULT="2"
 do_curl GET /counter/num_types 200
 
 echo "=== Get counter: interface ==="
index 2cba8c1..a58004a 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/bash
 
 #  ============LICENSE_START===============================================
-#  Copyright (C) 2020 Nordix Foundation. All rights reserved.
+#  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.
 #
 
 # 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 duplicate-check|ignore-duplicate "
+    exit 1
+}
+
+if [ $# -ne 1 ]; then
+    print_usage
+fi
+if [ $1 == "duplicate-check" ]; then
+    DUP_CHECK=1
+elif  [ $1 == "ignore-duplicate" ]; then
+    DUP_CHECK=0
+else
+    print_usage
+fi
 
 echo "Building image"
 cd ../../
@@ -30,4 +47,4 @@ 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
+docker run --rm -it -p 8085:8085 -p 8185:8185 -e A1_VERSION=STD_2.0.0 -e ALLOW_HTTP=true -e REMOTE_HOSTS_LOGGING=1 -e DUPLICATE_CHECK=$DUP_CHECK --volume "$PWD/certificate:/usr/src/app/cert" --name a1StdSimulator a1test
diff --git a/near-rt-ric-simulator/test/STD_2.0.0/jsonfiles/std_2.json b/near-rt-ric-simulator/test/STD_2.0.0/jsonfiles/std_2.json
new file mode 100644 (file)
index 0000000..b485fd0
--- /dev/null
@@ -0,0 +1,56 @@
+{
+  "policySchema": {
+    "$schema": "http://json-schema.org/draft-07/schema#",
+    "title": "STD_2_0.2.0",
+    "description": "STD 2 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_2_0.2.0",
+    "description": "STD 2 policy type status",
+    "type": "object",
+    "properties": {
+      "enforceStatus": {
+        "type": "string"
+      },
+      "enforceReason": {
+        "type": "string"
+      },
+      "additionalProperties": false,
+      "required": [
+        "enforceStatus"
+      ]
+    }
+  }
+}
\ No newline at end of file
index 9d70ed0..deff757 100644 (file)
@@ -1,5 +1,5 @@
 #  ============LICENSE_START===============================================
-#  Copyright (C) 2020 Nordix Foundation. All rights reserved.
+#  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.
@@ -156,11 +156,15 @@ def test_apis(client):
     res=compare(data_policies_get, result)
     assert res == True
 
-    # API: Create policy instance pi2 (copy of pi1) of type: 1. Shall fail
+    # API: Create policy instance pi2 (copy of pi1) of type: 1.
     with open(testdata+'pi1.json') as json_file:
         policy_2 = json.load(json_file)
         response=client.put(SERVER_URL+'a1-p/policytypes/1/policies/pi2', headers=header, data=json.dumps(policy_2))
-        assert response.status_code == 400
+        assert response.status_code == 202
+
+    # API: DELETE policy instance pi1
+    response=client.delete(SERVER_URL+'a1-p/policytypes/1/policies/pi2')
+    assert response.status_code == 202
 
     # Set force response code 401
     response=client.post(SERVER_URL+'forceresponse?code=401')
@@ -266,7 +270,7 @@ def test_apis(client):
     # API: Create policy instance pi2 of type: 2. Missing param, shall fail
     with open(testdata+'pi2_missing_param.json') as json_file:
         policy_2 = json.load(json_file)
-        response=client.put(SERVER_URL+'a1-p/policytypes/2/policies/pi1', headers=header, data=json.dumps(policy_2))
+        response=client.put(SERVER_URL+'a1-p/policytypes/2/policies/pi2', headers=header, data=json.dumps(policy_2))
         assert response.status_code == 400
 
     # API: Create policy instance pi2 of type: 2
@@ -296,12 +300,6 @@ def test_apis(client):
     res=compare(data_policies_get, result)
     assert res == True
 
-    # API: Create policy instance pi11 (copy of pi1) of type: 1. Shall fail
-    with open(testdata+'pi1.json') as json_file:
-        policy_1 = json.load(json_file)
-        response=client.put(SERVER_URL+'a1-p/policytypes/1/policies/pi11', headers=header, data=json.dumps(policy_1))
-        assert response.status_code == 400
-
     # Set force response code 409. ==="
     response=client.post(SERVER_URL+'forceresponse?code=401')
     assert response.status_code == 200
index 721d7a6..7599b4a 100644 (file)
@@ -1,5 +1,5 @@
 #  ============LICENSE_START===============================================
-#  Copyright (C) 2020 Nordix Foundation. All rights reserved.
+#  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.
@@ -110,18 +110,17 @@ def test_apis(client):
     res=compare(data_policy_get, result)
     assert res == True
 
-    # API: Create policy instance pi2 (copy of pi1). Shall fail
-    data_create_errror_pi1 = {
-        "title" : "The policy json already exists.",
-        "status" : 400,
-        "instance" : "pi2"
-    }
-    response=client.put(SERVER_URL+'A1-P/v1/policies/pi2', headers=header, data=json.dumps(data_pi1_updated))
-    assert response.status_code == 400
+    # API: Create policy instance pi3 (copy of pi1).
+    response=client.put(SERVER_URL+'A1-P/v1/policies/pi3', headers=header, data=json.dumps(data_pi1))
+    assert response.status_code == 201
     result=json.loads(response.data)
-    res=compare(data_create_errror_pi1, result)
+    res=compare(data_pi1, result)
     assert res == True
 
+    # API: DELETE policy instance pi1
+    response=client.delete(SERVER_URL+'A1-P/v1/policies/pi3')
+    assert response.status_code == 204
+
     # Set force response code 409. ==="
     response=client.post(SERVER_URL+'forceresponse?code=409')
     assert response.status_code == 200
index d63d4c3..2a01d83 100644 (file)
@@ -1,5 +1,5 @@
 #  ============LICENSE_START===============================================
-#  Copyright (C) 2020 Nordix Foundation. All rights reserved.
+#  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.
@@ -211,15 +211,20 @@ def test_apis(client):
         res=compare(json_payload, result)
         assert res == True
 
-    # API: Duplicate policy instance pi2 of type: STD_1
+    # # API: Duplicate policy instance pi2 of type: STD_1 - and delete it
+
     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
+        assert response.status_code == 201
         result=json.loads(response.data)
-        res=compare(data_response, result)
+        res=compare(json_payload, result)
         assert res == True
+    data_response = b""
+    response=client.delete(SERVER_URL+'A1-P/v2/policytypes/STD_1/policies/pi2')
+    assert response.status_code == 204
+    assert data_response == response.data
+
 
     # API: Get policy instances, shall contain pi1
     data_response = ["pi1"]
index 0dbbd22..9ffd009 100644 (file)
@@ -40,6 +40,7 @@ def setup_env(interface_version):
     #Env var to setup version and host logging
     os.environ['APIPATH'] = cwd+"../api/"+interface_version
     os.environ['REMOTE_HOSTS_LOGGING'] = "ON"
+    os.environ['DUPLICATE_CHECK'] = "0"
 
     # Paths need to run the sim, including needed source file dirs
     sys.path.append(os.path.abspath(cwd+'../src/common'))