From 3d457a05e0d180faec09285561bca1023654332f Mon Sep 17 00:00:00 2001 From: Niranjana Date: Wed, 12 Aug 2020 13:33:22 +0530 Subject: [PATCH] Add CSIT for son-handler Issue-ID: DCAEGEN2-1433 Signed-off-by: Niranjana Change-Id: Id7ea296ebef70964f5e8b751969595320b49d00a --- .../testsuites/config/dmaap/MsgRtrApi.properties | 172 +++++++++++++++++++++ .../testsuites/config/sonhms/config_all.json | 134 ++++++++++++++++ .../testsuites/docker-compose.yaml | 94 +++++++++++ .../testsuites/setup.sh | 61 ++++++++ .../testsuites/teardown.sh | 9 ++ .../testsuites/testplan.txt | 3 + .../sonhandler/Dockerfile | 15 ++ .../sonhandler/configdb-oof-sim.py | 98 ++++++++++++ .../sonhandler/sim-data/cell_data.json | 13 ++ .../sonhandler/sim-data/cell_list.json | 60 +++++++ .../sonhandler/sim-data/oof_async_response.json | 14 ++ .../sonhandler/sim-data/oof_syn_response.json | 6 + .../sonhandler/sim-data/pci_value.json | 4 + .../testcases/data/expected_payload_fm.json | 1 + .../testcases/data/expected_payload_pm.json | 1 + .../testcases/data/fault_notification.json | 35 +++++ .../testcases/data/negative_ack_from_policy.json | 10 ++ .../testcases/data/performance_notification.json | 42 +++++ .../testcases/sonhandler-test.robot | 95 ++++++++++++ 19 files changed, 867 insertions(+) create mode 100644 plans/dcaegen2-services-son-handler/testsuites/config/dmaap/MsgRtrApi.properties create mode 100644 plans/dcaegen2-services-son-handler/testsuites/config/sonhms/config_all.json create mode 100644 plans/dcaegen2-services-son-handler/testsuites/docker-compose.yaml create mode 100644 plans/dcaegen2-services-son-handler/testsuites/setup.sh create mode 100644 plans/dcaegen2-services-son-handler/testsuites/teardown.sh create mode 100644 plans/dcaegen2-services-son-handler/testsuites/testplan.txt create mode 100644 scripts/dcaegen2-services-son-handler/sonhandler/Dockerfile create mode 100644 scripts/dcaegen2-services-son-handler/sonhandler/configdb-oof-sim.py create mode 100644 scripts/dcaegen2-services-son-handler/sonhandler/sim-data/cell_data.json create mode 100644 scripts/dcaegen2-services-son-handler/sonhandler/sim-data/cell_list.json create mode 100644 scripts/dcaegen2-services-son-handler/sonhandler/sim-data/oof_async_response.json create mode 100644 scripts/dcaegen2-services-son-handler/sonhandler/sim-data/oof_syn_response.json create mode 100644 scripts/dcaegen2-services-son-handler/sonhandler/sim-data/pci_value.json create mode 100644 tests/dcaegen2-services-son-handler/testcases/data/expected_payload_fm.json create mode 100644 tests/dcaegen2-services-son-handler/testcases/data/expected_payload_pm.json create mode 100644 tests/dcaegen2-services-son-handler/testcases/data/fault_notification.json create mode 100644 tests/dcaegen2-services-son-handler/testcases/data/negative_ack_from_policy.json create mode 100644 tests/dcaegen2-services-son-handler/testcases/data/performance_notification.json create mode 100644 tests/dcaegen2-services-son-handler/testcases/sonhandler-test.robot diff --git a/plans/dcaegen2-services-son-handler/testsuites/config/dmaap/MsgRtrApi.properties b/plans/dcaegen2-services-son-handler/testsuites/config/dmaap/MsgRtrApi.properties new file mode 100644 index 00000000..712cbcb1 --- /dev/null +++ b/plans/dcaegen2-services-son-handler/testsuites/config/dmaap/MsgRtrApi.properties @@ -0,0 +1,172 @@ +# LICENSE_START======================================================= +# org.onap.dmaap +# ================================================================================ +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# Copyright (C) 2020 Wipro Limited. +# ================================================================================ +# 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========================================================= +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +# +############################################################################### +############################################################################### +## +## Cambria API Server config +## +## - Default values are shown as commented settings. +## + +############################################################################### +## +## HTTP service +## +## - 3904 is standard as of 7/29/14. +# +## Zookeeper Connection +## +## Both Cambria and Kafka make use of Zookeeper. +## +#config.zk.servers=172.18.1.1 +config.zk.servers=zookeeper:2181 +#config.zk.root=/fe3c/cambria/config + + +############################################################################### +## +## Kafka Connection +## +## Items below are passed through to Kafka's producer and consumer +## configurations (after removing "kafka.") +## if you want to change request.required.acks it can take this one value +#kafka.metadata.broker.list=localhost:9092,localhost:9093 +kafka.metadata.broker.list=kafka:9092 +##kafka.request.required.acks=-1 +#kafka.client.zookeeper=${config.zk.servers} +consumer.timeout.ms=100 +zookeeper.connection.timeout.ms=6000 +zookeeper.session.timeout.ms=20000 +zookeeper.sync.time.ms=2000 +auto.commit.interval.ms=1000 +fetch.message.max.bytes =1000000 +auto.commit.enable=false + +#(backoff*retries > zksessiontimeout) +kafka.rebalance.backoff.ms=10000 +kafka.rebalance.max.retries=6 + + +############################################################################### +## +## Secured Config +## +## Some data stored in the config system is sensitive -- API keys and secrets, +## for example. to protect it, we use an encryption layer for this section +## of the config. +## +## The key is a base64 encode AES key. This must be created/configured for +## each installation. +#cambria.secureConfig.key= +## +## The initialization vector is a 16 byte value specific to the secured store. +## This must be created/configured for each installation. +#cambria.secureConfig.iv= + +## Southfield Sandbox +cambria.secureConfig.key=b/7ouTn9FfEw2PQwL0ov/Q== +cambria.secureConfig.iv=wR9xP5k5vbz/xD0LmtqQLw== +authentication.adminSecret=fe3cCompound +#cambria.secureConfig.key[pc569h]=YT3XPyxEmKCTLI2NK+Sjbw== +#cambria.secureConfig.iv[pc569h]=rMm2jhR3yVnU+u2V9Ugu3Q== + + +############################################################################### +## +## Consumer Caching +## +## Kafka expects live connections from the consumer to the broker, which +## obviously doesn't work over connectionless HTTP requests. The Cambria +## server proxies HTTP requests into Kafka consumer sessions that are kept +## around for later re-use. Not doing so is costly for setup per request, +## which would substantially impact a high volume consumer's performance. +## +## This complicates Cambria server failover, because we often need server +## A to close its connection before server B brings up the replacement. +## + +## The consumer cache is normally enabled. +#cambria.consumer.cache.enabled=true + +## Cached consumers are cleaned up after a period of disuse. The server inspects +## consumers every sweepFreqSeconds and will clean up any connections that are +## dormant for touchFreqMs. +#cambria.consumer.cache.sweepFreqSeconds=15 +cambria.consumer.cache.touchFreqMs=120000 +##stickforallconsumerrequests=false +## The cache is managed through ZK. The default value for the ZK connection +## string is the same as config.zk.servers. +#cambria.consumer.cache.zkConnect=${config.zk.servers} + +## +## Shared cache information is associated with this node's name. The default +## name is the hostname plus the HTTP service port this host runs on. (The +## hostname is determined via InetAddress.getLocalHost ().getCanonicalHostName(), +## which is not always adequate.) You can set this value explicitly here. +## +#cambria.api.node.identifier= + +#cambria.rateLimit.maxEmptyPollsPerMinute=30 +#cambria.rateLimitActual.delay.ms=10 + +############################################################################### +## +## Metrics Reporting +## +## This server can report its metrics periodically on a topic. +## +#metrics.send.cambria.enabled=true +#metrics.send.cambria.topic=cambria.apinode.metrics #msgrtr.apinode.metrics.dmaap +#metrics.send.cambria.sendEverySeconds=60 + +cambria.consumer.cache.zkBasePath=/fe3c/cambria/consumerCache +consumer.timeout=17 +default.partitions=3 +default.replicas=3 +############################################################################## +#100mb +maxcontentlength=10000 + + +############################################################################## +#AAF Properties +msgRtr.namespace.aaf=org.onap.dmaap.mr.topic +msgRtr.topicfactory.aaf=org.onap.dmaap.mr.topicFactory|:org.onap.dmaap.mr.topic: +enforced.topic.name.AAF=org.onap +forceAAF=false +transidUEBtopicreqd=false +defaultNSforUEB=org.onap.dmaap.mr +############################################################################## +#Mirror Maker Agent +msgRtr.mirrormakeradmin.aaf=com.onap.dmaap.mr.dev.mirrormaker|*|admin +msgRtr.mirrormakeruser.aaf=com.onap.dmaap.mr.dev.mirrormaker|*|user +msgRtr.mirrormakeruser.aaf.create=com.onap.dmaap.mr.dev.topicFactory|:com.onap.dmaap.mr.dev.topic: +msgRtr.mirrormaker.timeout=15000 +msgRtr.mirrormaker.topic=com.onap.dmaap.mr.prod.mm.agent +msgRtr.mirrormaker.consumergroup=mmagentserver +msgRtr.mirrormaker.consumerid=1 + +kafka.max.poll.interval.ms=300000 +kafka.heartbeat.interval.ms=60000 +kafka.session.timeout.ms=240000 +kafka.max.poll.records=1000 + + diff --git a/plans/dcaegen2-services-son-handler/testsuites/config/sonhms/config_all.json b/plans/dcaegen2-services-son-handler/testsuites/config/sonhms/config_all.json new file mode 100644 index 00000000..8372142d --- /dev/null +++ b/plans/dcaegen2-services-son-handler/testsuites/config/sonhms/config_all.json @@ -0,0 +1,134 @@ +{ + "config": { + "sonhandler.badCountThreshold": 1, + "streams_subscribes": { + "performance_management_topic": { + "aaf_password": null, + "type": "message-router", + "dmaap_info": { + "topic_url": "https://message-router.onap.svc.cluster.local:3905/events/unauthenticated.VES_MEASUREMENT_OUTPUT", + "client_role": "son-subscriber", + "location": "onap", + "client_id": "sdnr-son-1" + }, + "aaf_username": null + }, + "fault_management_topic": { + "aaf_password": null, + "type": "message-router", + "dmaap_info": { + "topic_url": "https://message-router.onap.svc.cluster.local:3905/events/unauthenticated.SEC_FAULT_OUTPUT", + "client_role": "son-subscriber", + "location": "onap", + "client_id": "sdnr-son-1" + }, + "aaf_username": null + }, + "nbr_list_change_topic": { + "aaf_password": null, + "type": "message-router", + "dmaap_info": { + "topic_url": "https://message-router.onap.svc.cluster.local:3905/events/PCI-NOTIF-TOPIC-NGHBR-LIST-CHANGE-INFO", + "client_role": "son-subscriber", + "location": "onap", + "client_id": "sdnr-son-1" + }, + "aaf_username": null + }, + "dcae_cl_response_topic": { + "aaf_password": null, + "type": "message-router", + "dmaap_info": { + "topic_url": "https://message-router.onap.svc.cluster.local:3905/events/DCAE_CL_RSP", + "client_role": "son-subscriber", + "location": "onap", + "client_id": "sdnr-son-1" + }, + "aaf_username": null + } + }, + "postgres.port": "5432", + "sonhandler.pciOptimizer": "pci", + "sonhandler.maximumClusters": 5, + "sonhandler.numSolutions": 5, + "sonhandler.poorCountThreshold": 1, + "sonhandler.minCollision": 5, + "streams_publishes": { + "CL_topic": { + "aaf_password": null, + "type": "message-router", + "dmaap_info": { + "topic_url": "https://message-router.onap.svc.cluster.local:3905/events/unauthenticated.DCAE_CL_OUTPUT", + "client_role": "son-subscriber", + "location": "onap", + "client_id": "sdnr-son-1" + }, + "aaf_username": null + } + }, + "sonhandler.namespace": "onap", + "sonhandler.oof.endpoint": "/api/oof/v1/pci", + "postgres.password": "postgres", + "sonhandler.minConfusion": 5, + "sonhandler.sourceId": "SONHMS", + "postgres.username": "sonhms_admin", + "postgres.host": "postgres", + "sonhandler.policyRespTimer": 10, + "sonhandler.dmaap.server": [ + "dmaap" + ], + "sonhandler.poorThreshold": 70, + "sonhandler.oofTriggerCountTimer": 30, + "cbsPollingInterval": 60, + "sonhandler.cg": "sonhms-cg", + "sonhandler.pollingInterval": 20, + "sonhandler.badThreshold": 50, + "sonhandler.bufferTime": 60, + "sonhandler.cid": "sonhms-cid", + "sonhandler.configDb.service": "http://configdb_oof_sim:5000", + "sonhandler.oofTriggerCountThreshold": 5, + "sonhandler.oof.service": "http://configdb_oof_sim:5000", + "sonhandler.pciAnrOptimizer": "pci_anr", + "sonhandler.policyNegativeAckThreshold": 1, + "sonhandler.policyFixedPciTimeInterval": 10000, + "sonhandler.pollingTimeout": 60, + "sonhandler.nfNamingCode": "RansimAgent", + "service_calls": { + "sdnr-getpnfname": [], + "sdnr-getpci": [], + "sdnr-getnbrlist": [], + "sdnr-getcelllist": [], + "oof-req": [], + "policy-req": [] + } + }, + "policies": { + "event": { + "action": "gathered", + "timestamp": "2019-09-18T14:57:55.320Z", + "update_id": "dbb88da8-8df1-489d-b51d-8d5cbbfbcd99", + "policies_count": 1 + }, + "items": [ + { + "policyName": "com.Config_PCIMS_CONFIG_POLICY.1.xml", + "name": "com.Config_PCIMS_CONFIG_POLICY", + "config": { + "PCI_SDNR_TARGET_NAME": "SDNR", + "PCI_OPTMIZATION_ALGO_CATEGORY_IN_OOF": "OOF-PCI-OPTIMIZATION", + "PCI_NEIGHBOR_CHANGE_CLUSTER_TIMEOUT_IN_SECS": 60, + "PCI_MODCONFIGANR_POLICY_NAME": "ControlLoop-vSONH-7d4baf04-8875-4d1f-946d-06b874048b61", + "PCI_MODCONFIG_POLICY_NAME": "ControlLoop-vPCI-fb41f388-a5f2-11e8-98d0-529269fb1459" + }, + "type_version": "1.0.0", + "version": "1.0.0", + "policyVersion": "1", + "type": "onap.policies.monitoring.docker.sonhandler.app", + "metadata": { + "policy-id": "com.Config_PCIMS_CONFIG_POLICY", + "policy-version": "1" + } + } + ] + } +} diff --git a/plans/dcaegen2-services-son-handler/testsuites/docker-compose.yaml b/plans/dcaegen2-services-son-handler/testsuites/docker-compose.yaml new file mode 100644 index 00000000..43784399 --- /dev/null +++ b/plans/dcaegen2-services-son-handler/testsuites/docker-compose.yaml @@ -0,0 +1,94 @@ +# ============LICENSE_START======================================================= +# son-handler +# ================================================================================ +# Copyright (C) 2020 Wipro Limited. +# ============================================================================== +# 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========================================================= + +version: '3.3' +networks: + sonhms-default: + driver: bridge + driver_opts: + com.docker.network.driver.mtu: 1400 + +services: + zookeeper: + image: wurstmeister/zookeeper + container_name: zookeeper + ports: + - "2181:2181" + networks: + - sonhms-default + kafka: + image: wurstmeister/kafka + container_name: kafka + ports: + - "9092:9092" + environment: + KAFKA_ADVERTISED_HOST_NAME: "kafka" + KAFKA_AUTO_CREATE_TOPICS_ENABLE: 'true' + KAFKA_ZOOKEEPER_CONNECT: "zookeeper:2181" + KAFKA_ADVERTISED_LISTENERS: "PLAINTEXT://kafka:9092" + volumes: + - /var/run/docker.sock:/var/run/docker.sock + depends_on: + - zookeeper + networks: + - sonhms-default + dmaap: + image: nexus3.onap.org:10001/onap/dmaap/dmaap-mr:1.1.8 + container_name: dmaap + ports: + - "3904:3904" + - "3905:3905" + volumes: + - ./config/dmaap/MsgRtrApi.properties:/appl/dmaapMR1/bundleconfig/etc/appprops/MsgRtrApi.properties + depends_on: + - zookeeper + - kafka + networks: + - sonhms-default + postgres: + image: 'postgres:12-alpine' + container_name: sonhms-postgres + hostname: postgres + environment: + - POSTGRES_USER=sonhms_admin + - POSTGRES_PASSWORD=postgres + - POSTGRES_DB=sonhms + ports: + - 5432 + healthcheck: + test: ["CMD", "nc", "-z", "localhost", "5432"] + interval: 30s + timeout: 10s + retries: 5 + networks: + - sonhms-default + sonhms: + image: "nexus3.onap.org:10003/onap/org.onap.dcaegen2.services.son-handler:2.1.1-20200730T023738Z" + container_name: sonhms.onap + hostname: sonhms + environment: + - STANDALONE=true + - CONFIG_FILE=/etc/config_all.json + ports: + - "8080:8080" + volumes: + - ./config/sonhms/config_all.json:/etc/config_all.json + depends_on: + - postgres + networks: + - sonhms-default diff --git a/plans/dcaegen2-services-son-handler/testsuites/setup.sh b/plans/dcaegen2-services-son-handler/testsuites/setup.sh new file mode 100644 index 00000000..6f895a1e --- /dev/null +++ b/plans/dcaegen2-services-son-handler/testsuites/setup.sh @@ -0,0 +1,61 @@ +#!/bin/bash + +docker login -u docker -p docker nexus3.onap.org:10001 + +TEST_PLANS_DIR=$WORKSPACE/plans/dcaegen2-services-son-handler/testsuites +TEST_SCRIPTS_DIR=$WORKSPACE/scripts/dcaegen2-services-son-handler/sonhandler +TEST_ROBOT_DIR=$WORKSPACE/tests/dcaegen2-services-son-handler/testcases + +docker-compose up -d + +ZOOKEEPER_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' zookeeper) +KAFKA_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' kafka) +DMAAP_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' dmaap) +SONHMS_POSTGRES_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' sonhms-postgres) +SONHMS_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' sonhms.onap) + +echo "Waiting for dmaap to come up ..." +for i in {1..10}; do + dmaap_state=$(curl --write-out '%{http_code}' --silent --output /dev/null $DMAAP_IP:3904/topics) + if [ $dmaap_state == "200" ] + then + break + else + sleep 60 + fi +done + +#create topics +curl --header "Content-type: application/json" \ +--request POST \ +--data '{"topicName": "DCAE_CL_RSP"}' \ +http://$DMAAP_IP:3904/events/DCAE_CL_RSP + +curl --header "Content-type: application/json" \ +--request POST \ +--data '{"topicName": "unauthenticated.SEC_FAULT_OUTPUT"}' \ +http://$DMAAP_IP:3904/events/unauthenticated.SEC_FAULT_OUTPUT + +curl --header "Content-type: application/json" \ +--request POST \ +--data '{"topicName": "unauthenticated.VES_MEASUREMENT_OUTPUT"}' \ +http://$DMAAP_IP:3904/events/unauthenticated.VES_MEASUREMENT_OUTPUT + +curl --header "Content-type: application/json" \ +--request POST \ +--data '{"topicName": "unauthenticated.DCAE_CL_OUTPUT"}' \ +http://$DMAAP_IP:3904/events/unauthenticated.DCAE_CL_OUTPUT +echo "topics created" + +#build configdb-oof-sim image +cd $TEST_SCRIPTS_DIR +docker build -t configdb_oof_sim . + +#run configdb-oof-sim +docker run -d --name configdb_oof_sim --network=testsuites_sonhms-default -p "5000:5000" configdb_oof_sim:latest; +sleep 60 +CONFIGDB_OOF_SIM_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' configdb_oof_sim) +echo "CONFIGDB_OOF_SIM_IP=${CONFIGDB_OOF_SIM_IP}" + + +ROBOT_VARIABLES="-v ZOOKEEPER_IP:${ZOOKEEPER_IP} -v KAFKA_IP:${KAFKA_IP} -v DMAAP_IP:${DMAAP_IP} -v SONHMS_POSTGRES_IP:${SONHMS_POSTGRES_IP} -v SONHMS_IP:${SONHMS_IP} -v CONFIGDB_OOF_SIM_IP:${CONFIGDB_OOF_SIM_IP} -v TEST_ROBOT_DIR:${TEST_ROBOT_DIR}" diff --git a/plans/dcaegen2-services-son-handler/testsuites/teardown.sh b/plans/dcaegen2-services-son-handler/testsuites/teardown.sh new file mode 100644 index 00000000..7db3d2f6 --- /dev/null +++ b/plans/dcaegen2-services-son-handler/testsuites/teardown.sh @@ -0,0 +1,9 @@ +#!/bin/bash +echo "Starting teardown script" +TEST_PLANS_DIR=$WORKSPACE/plans/dcaegen2-services-son-handler/testsuites +mkdir -p $WORKSPACE/archives + +docker container stop configdb_oof_sim +docker container rm configdb_oof_sim +docker-compose -f $TEST_PLANS_DIR/docker-compose.yaml logs > $WORKSPACE/archives/sonhandler-docker-compose.log +docker-compose -f $TEST_PLANS_DIR/docker-compose.yaml down -v diff --git a/plans/dcaegen2-services-son-handler/testsuites/testplan.txt b/plans/dcaegen2-services-son-handler/testsuites/testplan.txt new file mode 100644 index 00000000..2f8b7606 --- /dev/null +++ b/plans/dcaegen2-services-son-handler/testsuites/testplan.txt @@ -0,0 +1,3 @@ +# Test suites are relative paths under [integration/csit.git]/tests/. +# Place the suites in run order. +dcaegen2-services-son-handler/testcases diff --git a/scripts/dcaegen2-services-son-handler/sonhandler/Dockerfile b/scripts/dcaegen2-services-son-handler/sonhandler/Dockerfile new file mode 100644 index 00000000..688a2fe0 --- /dev/null +++ b/scripts/dcaegen2-services-son-handler/sonhandler/Dockerfile @@ -0,0 +1,15 @@ +FROM python:alpine3.7 + +ADD configdb-oof-sim.py / + +ADD ./sim-data / + +RUN pip install Flask + +RUN pip install requests + +EXPOSE 5000 + +CMD ["flask", "run", "--host", "0.0.0.0"] + +CMD [ "python", "./configdb-oof-sim.py" ] diff --git a/scripts/dcaegen2-services-son-handler/sonhandler/configdb-oof-sim.py b/scripts/dcaegen2-services-son-handler/sonhandler/configdb-oof-sim.py new file mode 100644 index 00000000..7a51c951 --- /dev/null +++ b/scripts/dcaegen2-services-son-handler/sonhandler/configdb-oof-sim.py @@ -0,0 +1,98 @@ +import flask +import json +from flask import request +import requests +import threading +import time + +app = flask.Flask(__name__) +app.config["DEBUG"] = True + + +def get_neighbour_cell_list_for_cell_id(): + with open('cell_list.json') as cell_list: + data = json.load(cell_list) + if not data: + return {"Error": "Unable to read file"}, 503 + return data, None + +def get_pci_for_cell_id(): + with open('pci_value.json') as pci_value: + data = json.load(pci_value) + if not data: + return {"Error": "Unable to read file"}, 503 + return data, None + +def get_cell_data_for_cell_id(): + with open('cell_data.json') as cell_data: + data = json.load(cell_data) + if not data: + return {"Error": "Unable to read file"}, 503 + return data, None + +def get_oof_sync_response(): + with open('oof_syn_response.json') as syncRes: + data = json.load(syncRes) + if not data: + return {"Error": "Unale to read file"}, 503 + return data, None + +def get_oof_async_response(callback_url, transaction_id): + time.sleep(10) + with open('oof_async_response.json') as asyncRes: + data = json.load(asyncRes) + data['transactionId'] = transaction_id + if not data: + return {"Error": "Unable to read file"}, 503 + res = requests.post(callback_url, json=data) + print('response from server:',res.text) + return res + +@app.route("/api/sdnc-config-db/v3/getNbrList//", methods=["GET"]) +def get_neighbour_list(cell_id, ts): + data, status = get_neighbour_cell_list_for_cell_id() + if not status: + return data + return data, 503 + +@app.route("/api/sdnc-config-db/v3/getPCI//", methods=["GET"]) +def get_pci(cell_id, ts): + data, status = get_pci_for_cell_id() + if not status: + return data + return data, 503 +@app.route("/api/sdnc-config-db/v3/getPnfId//", methods=["GET"]) +def get_pnf_id(cell_id, ts): + data, status = get_pci_for_cell_id() + data['value'] = 'ncserver5' + if not status: + return data + return data, 503 + +@app.route("/api/sdnc-config-db/v3/getCell/", methods=["GET"]) +def get_cell_data(cell_id): + data, status = get_cell_data_for_cell_id() + if not status: + return data + return data, 503 + +@app.route("/api/oof/v1/pci",methods=["POST"]) +def oof_optimizatio_result(): + content = request.get_json() + callback_url = content['requestInfo']['callbackUrl'] + transaction_id = content['requestInfo']['transactionId'] + try: + task = threading.Thread(target=get_oof_async_response, args=(callback_url,transaction_id,)) + task.daemon = True + task.start() + except: + print("Error: Unable to start thread") + + data, status = get_oof_sync_response() + + if not status: + return data, 202 + return data, 503 + + +app.run(host='0.0.0.0') diff --git a/scripts/dcaegen2-services-son-handler/sonhandler/sim-data/cell_data.json b/scripts/dcaegen2-services-son-handler/sonhandler/sim-data/cell_data.json new file mode 100644 index 00000000..0e4e73f4 --- /dev/null +++ b/scripts/dcaegen2-services-son-handler/sonhandler/sim-data/cell_data.json @@ -0,0 +1,13 @@ +{ + "neighbor": ["Chn0066", "Chn0067", "Chn0068", "Chn0069", "Chn0070", "Chn0072", "Chn0073", "Chn0074", "Chn0075", "Chn0076", "Chn0077", "Chn0078", "Chn0079", "Chn0080"], + "Cell": { + "networkId": "ran-1", + "nodeId": "Chn0071", + "physicalCellId": 1, + "pnfId": "ncserver5", + "sectorNumber": null, + "latitude": "27.55626304907802", + "longitude": "-58.48690415723466", + "notes": "NA" + } +} \ No newline at end of file diff --git a/scripts/dcaegen2-services-son-handler/sonhandler/sim-data/cell_list.json b/scripts/dcaegen2-services-son-handler/sonhandler/sim-data/cell_list.json new file mode 100644 index 00000000..4f961ae2 --- /dev/null +++ b/scripts/dcaegen2-services-son-handler/sonhandler/sim-data/cell_list.json @@ -0,0 +1,60 @@ +{ + "cellId": "Chn0071", + "nbrList": [{ + "targetCellId": "Chn0066", + "pciValue": 0, + "ho": true + }, { + "targetCellId": "Chn0067", + "pciValue": 1, + "ho": true + }, { + "targetCellId": "Chn0068", + "pciValue": 2, + "ho": true + }, { + "targetCellId": "Chn0069", + "pciValue": 3, + "ho": true + }, { + "targetCellId": "Chn0070", + "pciValue": 4, + "ho": true + }, { + "targetCellId": "Chn0072", + "pciValue": 6, + "ho": true + }, { + "targetCellId": "Chn0073", + "pciValue": 7, + "ho": true + }, { + "targetCellId": "Chn0074", + "pciValue": 8, + "ho": true + }, { + "targetCellId": "Chn0075", + "pciValue": 9, + "ho": true + }, { + "targetCellId": "Chn0076", + "pciValue": 10, + "ho": true + }, { + "targetCellId": "Chn0077", + "pciValue": 11, + "ho": true + }, { + "targetCellId": "Chn0078", + "pciValue": 12, + "ho": true + }, { + "targetCellId": "Chn0079", + "pciValue": 13, + "ho": true + }, { + "targetCellId": "Chn0080", + "pciValue": 14, + "ho": true + }] +} \ No newline at end of file diff --git a/scripts/dcaegen2-services-son-handler/sonhandler/sim-data/oof_async_response.json b/scripts/dcaegen2-services-son-handler/sonhandler/sim-data/oof_async_response.json new file mode 100644 index 00000000..99f54cb4 --- /dev/null +++ b/scripts/dcaegen2-services-son-handler/sonhandler/sim-data/oof_async_response.json @@ -0,0 +1,14 @@ +{ + "transactionId": "fff33db3-8fc9-4e29-89ff-7419c85900bd", + "requestId": "742b9e6a-aa55-487e-9d71-a4a5e05b3981", + "requestStatus": "completed", + "statusMessage": "success", + "solutions": { + "networkId": "ran-1", + "pciSolutions": [{ + "cellId": "Chn0071", + "pci": "5" + }], + "anrSolutions": [] + } +} \ No newline at end of file diff --git a/scripts/dcaegen2-services-son-handler/sonhandler/sim-data/oof_syn_response.json b/scripts/dcaegen2-services-son-handler/sonhandler/sim-data/oof_syn_response.json new file mode 100644 index 00000000..c9260bbc --- /dev/null +++ b/scripts/dcaegen2-services-son-handler/sonhandler/sim-data/oof_syn_response.json @@ -0,0 +1,6 @@ +{ + "requestId": "742b9e6a-aa55-487e-9d71-a4a5e05b3981", + "transactionId": "fff33db3-8fc9-4e29-89ff-7419c85900bd", + "requestStatus": "accepted", + "statusMessage": "" +} \ No newline at end of file diff --git a/scripts/dcaegen2-services-son-handler/sonhandler/sim-data/pci_value.json b/scripts/dcaegen2-services-son-handler/sonhandler/sim-data/pci_value.json new file mode 100644 index 00000000..6b6d4475 --- /dev/null +++ b/scripts/dcaegen2-services-son-handler/sonhandler/sim-data/pci_value.json @@ -0,0 +1,4 @@ +{ + "attributeName": "PCIvalue", + "value": "5" +} \ No newline at end of file diff --git a/tests/dcaegen2-services-son-handler/testcases/data/expected_payload_fm.json b/tests/dcaegen2-services-son-handler/testcases/data/expected_payload_fm.json new file mode 100644 index 00000000..d542a7dd --- /dev/null +++ b/tests/dcaegen2-services-son-handler/testcases/data/expected_payload_fm.json @@ -0,0 +1 @@ +{"Configurations":[{"data":{"FAPService":{"alias":"Chn0071","X0005b9Lte":{"phyCellIdInUse":5,"pnfName":"ncserver5"},"CellConfig":{"LTE":{"RAN":{"Common":{"CellIdentity":"Chn0071"}}}}}}}]} diff --git a/tests/dcaegen2-services-son-handler/testcases/data/expected_payload_pm.json b/tests/dcaegen2-services-son-handler/testcases/data/expected_payload_pm.json new file mode 100644 index 00000000..2a56f2cc --- /dev/null +++ b/tests/dcaegen2-services-son-handler/testcases/data/expected_payload_pm.json @@ -0,0 +1 @@ +{"Configurations":[{"data":{"FAPService":{"alias":"Chn0002","CellConfig":{"LTE":{"RAN":{"Common":{"CellIdentity":"Chn0002"},"NeighborListInUse":{"LTECell":[{"PNFName":"ncserver1","PLMNID":"plmnid1","CID":"Chn0004","PhyCellID":0,"Blacklisted":"true"},{"PNFName":"ncserver1","CID":"Chn0001","PhyCellID":0,"Blacklisted":"true"}],"LTECellNumberOfEntries":"2"}}}}}}}]} diff --git a/tests/dcaegen2-services-son-handler/testcases/data/fault_notification.json b/tests/dcaegen2-services-son-handler/testcases/data/fault_notification.json new file mode 100644 index 00000000..e5a327ad --- /dev/null +++ b/tests/dcaegen2-services-son-handler/testcases/data/fault_notification.json @@ -0,0 +1,35 @@ +{ + "event": { + "commonEventHeader": { + "version": "4.0.1", + "vesEventListenerVersion": "7.0.1", + "domain": "fault", + "eventName": "Fault_RansimAgent-Wipro_RanPCIProblem", + "eventId": "fault000001", + "sequence": 1, + "priority": "High", + "reportingEntityId": "de305d54-75b4-431b-adb2-eb6b9e546014", + "reportingEntityName": "ncserver5", + "sourceId": "cc305d54-75b4-431b-adb2-eb6b9e541234", + "sourceName": "Chn0071", + "startEpochMicrosec": 1451772223000000, + "lastEpochMicrosec": 1451772403000000, + "timeZoneOffset": "UTC-05:30", + "nfNamingCode": "RansimAgent", + "nfVendorName": "Wipro" + }, + "faultFields": { + "faultFieldsVersion": "4.0", + "alarmCondition": "RanPciCollisionConfusionOccurred", + "eventSourceType": "other", + "specificProblem": "Collision", + "eventSeverity": "CRITICAL", + "vfStatus": "Active", + "alarmAdditionalInformation": { + "networkId": "ran-1", + "collisions": "1", + "confusions": "0" + } + } + } +} \ No newline at end of file diff --git a/tests/dcaegen2-services-son-handler/testcases/data/negative_ack_from_policy.json b/tests/dcaegen2-services-son-handler/testcases/data/negative_ack_from_policy.json new file mode 100644 index 00000000..8988f1cd --- /dev/null +++ b/tests/dcaegen2-services-son-handler/testcases/data/negative_ack_from_policy.json @@ -0,0 +1,10 @@ +{ + "requestID": "d9a6d3de-c7b9-4dc7-bbb3-54953c62f7a9", + "closedLoopControlName": "ControlLoop-vPCI-fb41f388-a5f2-11e8-98d0-529269fb1459", + "version": "1.0.2", + "target": "DCAE", + "from": "SDNR", + "policyName": "PCI", + "policyVersion": "1.0.2", + "payload": " { \"Configurations\":[{ \"Status\": { \"Code\": 400, \"Value\": \"FAILURE\" }, \"data\":{\"FAPService\":{\"alias\":\"Chn0071\",\"X0005b9Lte\":{\"phyCellIdInUse\":5,\"pnfName\":\"ncserver5\"},\"CellConfig\":{\"LTE\":{\"RAN\":{\"Common\":{\"CellIdentity\":\"Chn0071\"}}}}}}} ]}" +} diff --git a/tests/dcaegen2-services-son-handler/testcases/data/performance_notification.json b/tests/dcaegen2-services-son-handler/testcases/data/performance_notification.json new file mode 100644 index 00000000..7721163a --- /dev/null +++ b/tests/dcaegen2-services-son-handler/testcases/data/performance_notification.json @@ -0,0 +1,42 @@ +{ + "event": { + "commonEventHeader": { + "version": "4.0", + "domain": "measurement", + "eventName": "Measurement_RansimAgent-Wipro_HandoffMetric", + "eventId": "measurement000002", + "sequence": 0, + "priority": "Normal", + "reportingEntityId": "cc305d54-75b4-431b-adb2-eb6b9e544567", + "reportingEntityName": "ncserver1", + "sourceId": "de305d54-75b4-431b-adb2-eb6b9e546456", + "sourceName": "Chn0002", + "startEpochMicrosec": 1551772223000000, + "lastEpochMicrosec": 1551790542000000, + "nfNamingCode": "RansimAgent", + "nfVendorName": "Wipro", + "vesEventListenerVersion": "7.0.1", + "timeZoneOffset": "UTC-05:30" + }, + "measurementFields": { + "measurementInterval": 180, + "measurementFieldsVersion": "4.0", + "additionalMeasurements": [{ + "hashMap": { + "networkId": "plmnid1", + "InterEnbOutAtt_X2HO": "300", + "InterEnbOutSucc_X2HO": "90" + }, + "name": "Chn0004" + }, + { + "hashMap": { + "InterEnbOutAtt_X2HO": "250", + "InterEnbOutSucc_X2HO": "70" + }, + "name": "Chn0001" + } + ] + } + } +} \ No newline at end of file diff --git a/tests/dcaegen2-services-son-handler/testcases/sonhandler-test.robot b/tests/dcaegen2-services-son-handler/testcases/sonhandler-test.robot new file mode 100644 index 00000000..6e93ffb9 --- /dev/null +++ b/tests/dcaegen2-services-son-handler/testcases/sonhandler-test.robot @@ -0,0 +1,95 @@ +*** Settings *** +Library Collections +Library Process +Library RequestsLibrary +Library String +Library OperatingSystem + +Suite Teardown Delete All Sessions + +*** Variables *** +${SON_HANDLER_BASE_URL} http://${SONHMS_IP}:8080 +${HEALTHCHECK_ENDPOINT} /healthcheck +${DMAAP_URL} http://${DMAAP_IP}:3904/events +${unauthenticated.DCAE_CL_OUTPUT} /unauthenticated.DCAE_CL_OUTPUT/23/23 +${POST_DMAAP_EVENT_FOR_FM_NOTIF_URL} http://${DMAAP_IP}:3904/events/unauthenticated.SEC_FAULT_OUTPUT +${POST_DMAAP_EVENT_FOR_PM_NOTIF_URL} http://${DMAAP_IP}:3904/events/unauthenticated.VES_MEASUREMENT_OUTPUT +${POST_DMAAP_EVENT_FOR_POLICY_RESPONSE} http://${DMAAP_IP}:3904/events/DCAE_CL_RSP + +*** Test Cases *** + +HealthCheck + + Create Session sonhms ${SON_HANDLER_BASE_URL} + ${resp}= Get Request sonhms ${HEALTHCHECK_ENDPOINT} + Should Be Equal As Strings ${resp.status_code} 200 + + +Post fm notification to dmaap + Create Session dmaap ${DMAAP_URL} + ${headers}= Create Dictionary Content-Type application/json + ${data}= Get File ${TEST_ROBOT_DIR}/data/fault_notification.json + ${response}= Evaluate requests.post('${POST_DMAAP_EVENT_FOR_FM_NOTIF_URL}', data=$data) + Should Be Equal As Strings ${response.status_code} 200 + + +Verify fm notification trigger in sonhms + Create Session dmaap ${DMAAP_URL} + FOR ${i} IN RANGE 10 + ${result}= Get Request dmaap ${unauthenticated.DCAE_CL_OUTPUT} + Exit For Loop If ${result.json()} != @{EMPTY} + Log Waiting for sonhms to handle trigger... console=${True} + Sleep 30s + END + ${expected_payload}= Get File ${TEST_ROBOT_DIR}/data/expected_payload_fm.json + ${result}= Convert To String ${result.content} + ${result_string}= Get Substring ${result} 2 -2 + ${actual_data}= Evaluate json.loads("""${result_string}""") json + ${actual_payload}= Set Variable ${actual_data['payload']} + Should Be True """${actual_payload}""".strip() == """${expected_payload}""".strip() + + +Post pm notification to dmaap + ${data}= Get File ${TEST_ROBOT_DIR}/data/performance_notification.json + ${response}= Evaluate requests.post('${POST_DMAAP_EVENT_FOR_PM_NOTIF_URL}', data=$data) + Should Be Equal As Strings ${response.status_code} 200 + + +Verify pm notification trigger in sonhms + Create Session dmaap ${DMAAP_URL} + FOR ${i} IN RANGE 5 + ${result}= Get Request dmaap ${unauthenticated.DCAE_CL_OUTPUT} + Exit For Loop If ${result.json()} != @{EMPTY} + Log Waiting for sonhms to handle trigger... console=${True} + Sleep 30s + END + ${expected_payload}= Get File ${TEST_ROBOT_DIR}/data/expected_payload_pm.json + ${result}= Convert To String ${result.content} + ${result_string}= Get Substring ${result} 2 -2 + ${actual_data}= Evaluate json.loads("""${result_string}""") json + ${actual_payload}= Set Variable ${actual_data['payload']} + Should Be True """${actual_payload}""".strip() == """${expected_payload}""".strip() + + +Post policy negative acknowledgement to dmaap + ${data}= Get File ${TEST_ROBOT_DIR}/data/negative_ack_from_policy.json + FOR ${i} IN RANGE 3 + ${response}= Evaluate requests.post('${POST_DMAAP_EVENT_FOR_POLICY_RESPONSE}', data=$data) + END + Should Be Equal As Strings ${response.status_code} 200 + + +Oof trigger for fixed Pci cells + Create Session dmaap ${DMAAP_URL} + FOR ${i} IN RANGE 15 + ${result}= Get Request dmaap ${unauthenticated.DCAE_CL_OUTPUT} + Exit For Loop If ${result.json()} != @{EMPTY} + Log Waiting for sonhms to handle trigger... console=${True} + Sleep 30s + END + ${expected_payload}= Get File ${TEST_ROBOT_DIR}/data/expected_payload_fm.json + ${result}= Convert To String ${result.content} + ${result_string}= Get Substring ${result} 2 -2 + ${actual_data}= Evaluate json.loads("""${result_string}""") json + ${actual_payload}= Set Variable ${actual_data['payload']} + Should Be True """${actual_payload}""".strip() == """${expected_payload}""".strip() -- 2.16.6