diff options
-rw-r--r-- | .gitignore | 5 | ||||
-rw-r--r-- | Changelog.md | 3 | ||||
-rw-r--r-- | miss_htbt_service/config.json | 1 | ||||
-rw-r--r-- | miss_htbt_service/db_monitoring.py | 43 | ||||
-rw-r--r-- | miss_htbt_service/htbtworker.py | 384 | ||||
-rw-r--r-- | miss_htbt_service/misshtbtd.py | 83 | ||||
-rw-r--r-- | miss_htbt_service/mod/htbt_exit.py (renamed from miss_htbt_service/mod/trapd_exit.py) | 6 | ||||
-rw-r--r-- | miss_htbt_service/mod/htbt_get_cbs_config.py (renamed from miss_htbt_service/mod/trapd_get_cbs_config.py) | 10 | ||||
-rw-r--r-- | miss_htbt_service/mod/htbt_http_session.py (renamed from miss_htbt_service/mod/trapd_http_session.py) | 4 | ||||
-rw-r--r-- | miss_htbt_service/mod/htbt_io.py (renamed from miss_htbt_service/mod/trapd_io.py) | 2 | ||||
-rw-r--r-- | miss_htbt_service/mod/htbt_runtime_pid.py (renamed from miss_htbt_service/mod/trapd_runtime_pid.py) | 4 | ||||
-rw-r--r-- | miss_htbt_service/mod/htbt_settings.py (renamed from miss_htbt_service/mod/trapd_settings.py) | 2 | ||||
-rw-r--r-- | miss_htbt_service/mod/htbt_vnf_table.py (renamed from miss_htbt_service/mod/trapd_vnf_table.py) | 18 | ||||
-rw-r--r-- | pom.xml | 4 | ||||
-rw-r--r-- | setup.py | 4 | ||||
-rw-r--r-- | tests/hbproperties-test.yaml | 11 | ||||
-rw-r--r-- | tests/test-config.json | 1 | ||||
-rw-r--r-- | tests/test4.json | 1 | ||||
-rw-r--r-- | tests/test_db_monitoring.py | 75 | ||||
-rw-r--r-- | tests/test_get_logger.py | 6 | ||||
-rw-r--r-- | tests/test_htbt_exit.py (renamed from tests/test_trapd_exit.py) | 8 | ||||
-rw-r--r-- | tests/test_htbt_get_cbs_config.py (renamed from tests/test_trapd_get_cbs_config.py) | 45 | ||||
-rw-r--r-- | tests/test_htbt_http_session.py (renamed from tests/test_trapd_http_session.py) | 6 | ||||
-rw-r--r-- | tests/test_htbt_runtime_pid.py (renamed from tests/test_trapd_runtime_pid.py) | 14 | ||||
-rw-r--r-- | tests/test_htbt_settings.py (renamed from tests/test_trapd_settings.py) | 4 | ||||
-rw-r--r-- | tests/test_htbt_vnf_table.py (renamed from tests/test_trapd_vnf_table.py) | 45 | ||||
-rw-r--r-- | tests/test_htbtworker.py | 163 | ||||
-rw-r--r-- | tests/test_misshtbtd.py | 215 | ||||
-rw-r--r-- | tox.ini | 3 | ||||
-rw-r--r-- | version.properties | 2 |
30 files changed, 830 insertions, 342 deletions
@@ -11,3 +11,8 @@ xunit-results.xml miss_htbt_service.egg-info target/ .idea/ +.project +.pydevproject +hb_db_monitoring_logs.txt +hb_misshtbtd_logs.txt +hb_htbtworker_logs.txt diff --git a/Changelog.md b/Changelog.md index 9d98d9c..bd2b18f 100644 --- a/Changelog.md +++ b/Changelog.md @@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [2.6.0] - 2022/11/17 +- [DCAEGEN2-2953] Code refactoring + ## [2.5.0] - 2022/10/25 - [DCAEGEN2-2952] Handle exception when MR is unavailable - [DCAEGEN2-3297] Fix Black tool compatibility issue blocking docker build diff --git a/miss_htbt_service/config.json b/miss_htbt_service/config.json new file mode 100644 index 0000000..e853f6a --- /dev/null +++ b/miss_htbt_service/config.json @@ -0,0 +1 @@ +{"pg_ipAddress": "10.0.4.1", "pg_userName": "postgres", "pg_dbName": "postgres", "streams_subscribes": {"ves-heartbeat": {"type": "message_router", "dmaap_info": {"topic_url": "http://10.12.5.252:3904/events/unauthenticated.SEC_HEARTBEAT_INPUT"}}}, "consumerID": "1", "CBS_polling_interval": "300", "pg_passwd": "postgres", "streams_publishes": {"dcae_cl_out": {"type": "message_router", "dmaap_info": {"topic_url": "http://10.12.5.252:3904/events/unauthenticated.DCAE_CL_OUTPUT"}}}, "pg_portNum": "5432", "CBS_polling_allowed": "True", "groupID": "groupID", "heartbeat_config": "{\"vnfs\": [{\"eventName\": \"Heartbeat_vDNS\",\"heartbeatcountmissed\": 3,\"heartbeatinterval\": 60,\"closedLoopControlName\": \"ControlLoopEvent1\",\t\"policyVersion\": \"1.0.0.5\",\t\"policyName\":\"vFireWall\",\"policyScope\": \"resource=sampleResource,type=sampletype,CLName=sampleCLName\",\"target_type\": \"VNF\",\t\"target\": \"genVnfName\",\t\"version\": \"1.0\"}, {\"eventName\": \"Heartbeat_vFW\",\"heartbeatcountmissed\": 3,\t\"heartbeatinterval\": 60,\"closedLoopControlName\": \"ControlLoopEvent1\",\"policyVersion\": \"1.0.0.5\",\"policyName\": \"vFireWall\",\"policyScope\": \"resource=sampleResource,type=sampletype,CLName=sampleCLName\",\t\"target_type\":\"VNF\",\t\"target\": \"genVnfName\",\t\"version\": \"1.0\"}, {\"eventName\": \"Heartbeat_xx\",\"heartbeatcountmissed\": 3,\t\"heartbeatinterval\": 60,\"closedLoopControlName\": \"ControlLoopEvent1\",\"policyVersion\": \"1.0.0.5\",\"policyName\": \"vFireWall\",\t\"policyScope\": \"resource=sampleResource,type=sampletype,CLName=sampleCLName\",\"target_type\": \"VNF\",\"target\": \"genVnfName\",\"version\": \"1.0\"}]}"} diff --git a/miss_htbt_service/db_monitoring.py b/miss_htbt_service/db_monitoring.py index eac8a91..cbd8f24 100644 --- a/miss_htbt_service/db_monitoring.py +++ b/miss_htbt_service/db_monitoring.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # ============LICENSE_START======================================================= -# Copyright (c) 2018-2022 AT&T Intellectual Property. All rights reserved. +# Copyright (c) 2018-2023 AT&T Intellectual Property. All rights reserved. # Copyright (c) 2019 Pantheon.tech. All rights reserved. # Copyright (c) 2020 Deutsche Telekom. All rights reserved. # Copyright (c) 2021 Fujitsu Ltd. @@ -30,6 +30,7 @@ import os import socket import time import requests +import psycopg2 import htbtworker as pm import misshtbtd as db import get_logger @@ -159,10 +160,6 @@ def db_monitoring(current_pid, json_file, user_name, password, ip_address, port_ while True: time.sleep(20) - env_pytest = os.getenv("pytest", "") - if env_pytest == "test": - break - try: with open(json_file, "r") as outfile: cfg = json.load(outfile) @@ -177,9 +174,9 @@ def db_monitoring(current_pid, json_file, user_name, password, ip_address, port_ ) source_name = socket.gethostname() source_name = source_name + "-" + str(os.getenv("SERVICE_NAME", "")) - connection_db = pm.postgres_db_open(user_name, password, ip_address, port_num, db_name) + connection_db = pm.postgres_db_open() cur = connection_db.cursor() - if int(current_pid) == int(hbc_pid) and source_name == hbc_src_name and hbc_state == "RUNNING": + if int(current_pid) == int(hbc_pid) and source_name == hbc_src_name and hbc_state == "RUNNING": # pragma: no cover _logger.info("DBM: Active DB Monitoring Instance") cur.execute("SELECT event_name FROM vnf_table_1") vnf_list = [item[0] for item in cur.fetchall()] @@ -224,7 +221,7 @@ def db_monitoring(current_pid, json_file, user_name, password, ip_address, port_ epoc_time_sec = row[0][0] src_name = row[0][1] cl_flag = row[0][2] - if (epoc_time - epoc_time_sec) > comparision_time and cl_flag == 0: + if (epoc_time - epoc_time_sec) > comparision_time and cl_flag == 0: # pragma: no cover sendControlLoopEvent( "ONSET", pol_url, @@ -244,7 +241,7 @@ def db_monitoring(current_pid, json_file, user_name, password, ip_address, port_ (cl_flag, event_name, (source_name_key + 1)), ) connection_db.commit() - elif (epoc_time - epoc_time_sec) < comparision_time and cl_flag == 1: + elif (epoc_time - epoc_time_sec) < comparision_time and cl_flag == 1: # pragma: no cover sendControlLoopEvent( "ABATED", pol_url, @@ -277,17 +274,21 @@ def db_monitoring(current_pid, json_file, user_name, password, ip_address, port_ """ else: # pragma: no cover msg = "DBM:Inactive instance or hb_common state is not RUNNING" - _logger.info(msg) - pm.commit_and_close_db(connection_db) + _logger.info(msg) + try: + connection_db.commit() # <--- makes sure the change is shown in the database + connection_db.close() + return True + except psycopg2.DatabaseError as e: + msg = "COMMON:Error %s" % e + _logger.error(msg) + return False cur.close() break - -if __name__ == "__main__": +def db_monitoring_wrapper (current_pid, jsfile, number_of_iterations=-1): get_logger.configure_logger("db_monitoring") _logger.info("DBM: DBM Process started") - current_pid = sys.argv[1] - jsfile = sys.argv[2] ( ip_address, port_num, @@ -299,8 +300,12 @@ if __name__ == "__main__": ) = db.read_hb_properties(jsfile) msg = "DBM:Parent process ID and json file name", current_pid, jsfile _logger.info(msg) - while True: + while number_of_iterations != 0: + number_of_iterations -= 1 db_monitoring(current_pid, jsfile, user_name, password, ip_address, port_num, db_name) - env_pytest = os.getenv("pytest", "") - if env_pytest == "test": - break + + +if __name__ == "__main__": + current_pid = sys.argv[1] + jsfile = sys.argv[2] + db_monitoring_wrapper (current_pid,jsfile) diff --git a/miss_htbt_service/htbtworker.py b/miss_htbt_service/htbtworker.py index 6765266..3328973 100644 --- a/miss_htbt_service/htbtworker.py +++ b/miss_htbt_service/htbtworker.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # ============LICENSE_START======================================================= -# Copyright (c) 2018-2022 AT&T Intellectual Property. All rights reserved. +# Copyright (c) 2018-2023 AT&T Intellectual Property. All rights reserved. # Copyright (c) 2019 Pantheon.tech. All rights reserved. # Copyright (c) 2020 Deutsche Telekom. All rights reserved. # Copyright (c) 2021 Fujitsu Ltd. @@ -17,11 +17,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============LICENSE_END========================================================= -# -# Author Prakash Hosangady(ph553f@att.com) -# Simple Microservice -# Tracks Heartbeat messages on input topic in DMaaP -# and poppulate the information in postgres DB + import logging import psycopg2 @@ -31,55 +27,45 @@ import os.path as path import json import sys import time + import misshtbtd as db import get_logger _logger = logging.getLogger(__name__) +configjsonfile = "../etc/config.json" -def read_json_file(i, prefix="../../tests"): - if i == 0: - with open(path.abspath(path.join(__file__, f"{prefix}/test1.json")), "r") as outfile: - cfg = json.load(outfile) - elif i == 1: - with open(path.abspath(path.join(__file__, f"{prefix}/test2.json")), "r") as outfile: - cfg = json.load(outfile) - elif i == 2: - with open(path.abspath(path.join(__file__, f"{prefix}/test3.json")), "r") as outfile: - cfg = json.load(outfile) - return cfg - - -def process_msg(jsfile, user_name, password, ip_address, port_num, db_name): +def process_msg(cfgjsonfile, number_of_iterations=-1): + """ + Function to poll events from MR continuously + and determine if matching configuration to be + tracked for missed HB function + """ + global mr_url - i = 0 + global configjsonfile + configjsonfile = cfgjsonfile sleep_duration = 20 - while True: + reconfig_Flag = False + while number_of_iterations != 0: + number_of_iterations -= 1 time.sleep(sleep_duration) - with open(jsfile, "r") as outfile: + print ("*** CFG json file info " + configjsonfile) + with open(configjsonfile, "r") as outfile: cfg = json.load(outfile) + + print ("*** CFG info " + str(cfg)) mr_url = str(cfg["streams_subscribes"]["ves-heartbeat"]["dmaap_info"]["topic_url"]) + + username = str(cfg["pg_userName"]) + password = str(cfg["pg_passwd"]) + db_host = str(cfg["pg_ipAddress"]) + db_port = cfg["pg_portNum"] + database_name = str(cfg["pg_dbName"]) + + reconfig_Flag = check_process_reconfiguration (username, password, db_host, db_port, database_name) + eventname_list = get_eventnamelist () - while True: - hbc_pid, hbc_state, hbc_src_name, hbc_time = db.read_hb_common( - user_name, password, ip_address, port_num, db_name - ) - if hbc_state == "RECONFIGURATION": - _logger.info("HBT:Waiting for hb_common state to become RUNNING") - time.sleep(10) - else: - break - - if os.getenv("pytest", "") == "test": - eventname_list = ["Heartbeat_vDNS", "Heartbeat_vFW", "Heartbeat_xx"] - connection_db = 0 - else: - connection_db = postgres_db_open(user_name, password, ip_address, port_num, db_name) - cur = connection_db.cursor() - cur.execute("SELECT event_name FROM vnf_table_1") - eventname_list = [item[0] for item in cur.fetchall()] - msg = "\n\nHBT:eventnameList values ", eventname_list - _logger.info(msg) if "groupID" not in os.environ or "consumerID" not in os.environ: get_url = mr_url + "/DefaultGroup/1?timeout=15000" else: @@ -87,105 +73,60 @@ def process_msg(jsfile, user_name, password, ip_address, port_num, db_name): msg = "HBT:Getting :" + get_url _logger.info(msg) - if os.getenv("pytest", "") == "test": - jsonobj = read_json_file(i) - jobj = [] - jobj.append(jsonobj) - i = i + 1 - msg = "HBT:newly received test message", jobj - _logger.info(msg) - if i >= 3: - i = 0 - break - else: + try: + res = requests.get(get_url) + except Exception as e: + # message-router may be down temporarily. continue polling loop to try again + _logger.error("HBT: Failed to fetch messages from DMaaP. get_url=%s", get_url, exc_info=e) + time.sleep(1) + continue + _logger.info("HBT: %s", res.text) + input_string = res.text + # If mrstatus in message body indicates some information, not json msg. + if "mrstatus" in input_string: + continue + jlist = input_string.split("\n") + print (jlist) + # Process the DMaaP input message retrieved + error = False + jobj = [] + for line in jlist: try: - res = requests.get(get_url) - except Exception as e: - # message-router may be down temporarily. continue polling loop to try again - _logger.error("HBT: Failed to fetch messages from DMaaP. get_url=%s", get_url, exc_info=e) - time.sleep(1) - continue - _logger.info("HBT: %s", res.text) - input_string = res.text - # If mrstatus in message body indicates some information, not json msg. - if "mrstatus" in input_string: - continue - jlist = input_string.split("\n") - # Process the DMaaP input message retreived - error = False - for line in jlist: - try: - jobj = json.loads(line) - except ValueError: - msg = "HBT:Decoding JSON has failed" - _logger.error(msg) - error = True - break - if error: - continue - if len(jobj) == 0: - continue - for item in jobj: - try: - if os.getenv("pytest", "") == "test": - jitem = jsonobj - else: - jitem = json.loads(item) - srcname = jitem["event"]["commonEventHeader"]["sourceName"] - lastepo = jitem["event"]["commonEventHeader"]["lastEpochMicrosec"] - # if lastEpochMicrosec looks like microsec, align it with millisec - if lastepo > 1000000000000000: - lastepo = int(lastepo / 1000) - seqnum = jitem["event"]["commonEventHeader"]["sequence"] - event_name = jitem["event"]["commonEventHeader"]["eventName"] - except Exception as err: - msg = "HBT message process error - ", err + jobj = json.loads(line) + except ValueError: + msg = "HBT:Decoding JSON has failed" _logger.error(msg) - continue + error = True + break + if error: + continue + if len(jobj) == 0: + continue + + _logger.info("HBT jobj Array : %s", jobj) + for item in jobj: + srcname, lastepo, seqnum, event_name = parse_event(item) msg = "HBT:Newly received HB event values ::", event_name, lastepo, srcname _logger.info(msg) - if db_table_creation_check(connection_db, "vnf_table_2") is False: - msg = "HBT:Creating vnf_table_2" - _logger.info(msg) - cur.execute( - """ - CREATE TABLE vnf_table_2 ( - EVENT_NAME varchar, - SOURCE_NAME_KEY integer, - PRIMARY KEY(EVENT_NAME, SOURCE_NAME_KEY), - LAST_EPO_TIME BIGINT, - SOURCE_NAME varchar, - CL_FLAG integer - )""" - ) - else: - msg = "HBT:vnf_table_2 is already there" - _logger.info(msg) + + check_and_create_vnf2_table () + if event_name in eventname_list: # pragma: no cover - if os.getenv("pytest", "") == "test": - break - cur.execute("SELECT source_name_count FROM vnf_table_1 WHERE event_name = %s", (event_name,)) + cur = sql_executor("SELECT source_name_count FROM vnf_table_1 WHERE event_name = %s", event_name) row = cur.fetchone() source_name_count = row[0] source_name_key = source_name_count + 1 cl_flag = 0 if source_name_count == 0: # pragma: no cover _logger.info("HBT: Insert entry into vnf_table_2, source_name='%s'", srcname) - cur.execute( - "INSERT INTO vnf_table_2 VALUES(%s,%s,%s,%s,%s)", - (event_name, source_name_key, lastepo, srcname, cl_flag), - ) - cur.execute( - "UPDATE vnf_table_1 SET SOURCE_NAME_COUNT = %s where EVENT_NAME = %s", - (source_name_key, event_name), - ) - else: # pragma: no cover + new_vnf_entry(event_name, source_name_key, lastepo, srcname, cl_flag) + else: # pragma: no cover msg = "HBT:event name, source_name & source_name_count are", event_name, srcname, source_name_count _logger.info(msg) for source_name_key in range(source_name_count): - cur.execute( + cur = sql_executor( "SELECT source_name FROM vnf_table_2 WHERE event_name = %s AND " "source_name_key = %s", - (event_name, (source_name_key + 1)), + event_name, (source_name_key + 1) ) row = cur.fetchall() if len(row) == 0: @@ -194,10 +135,10 @@ def process_msg(jsfile, user_name, password, ip_address, port_num, db_name): if db_srcname == srcname: msg = "HBT: Update vnf_table_2 : ", source_name_key, row _logger.info(msg) - cur.execute( + sql_executor( "UPDATE vnf_table_2 SET LAST_EPO_TIME = %s, SOURCE_NAME = %s " "WHERE EVENT_NAME = %s AND SOURCE_NAME_KEY = %s", - (lastepo, srcname, event_name, (source_name_key + 1)), + lastepo, srcname, event_name, (source_name_key + 1) ) source_name_key = source_name_count break @@ -208,63 +149,152 @@ def process_msg(jsfile, user_name, password, ip_address, port_num, db_name): if source_name_count == (source_name_key + 1): source_name_key = source_name_count + 1 _logger.info("HBT: Insert entry into vnf_table_2, source_name='%s'", srcname) - cur.execute( - "INSERT INTO vnf_table_2 VALUES(%s,%s,%s,%s,%s)", - (event_name, source_name_key, lastepo, srcname, cl_flag), - ) - cur.execute( - "UPDATE vnf_table_1 SET SOURCE_NAME_COUNT = %s WHERE EVENT_NAME = %s", - (source_name_key, event_name), - ) + new_vnf_entry(event_name, source_name_key, lastepo, srcname, cl_flag) else: - _logger.info("HBT:eventName is not being monitored, Igonoring JSON message") - commit_db(connection_db) - commit_and_close_db(connection_db) - if os.getenv("pytest", "") != "test": - cur.close() + _logger.info("HBT:eventName is not being monitored, Ignoring JSON message") + msg = "HBT: Looping to check for new events from DMAAP" + print ("HBT: Looping to check for new events from DMAAP") + _logger.info(msg) +def new_vnf_entry (event_name, source_name_key, lastepo, srcname, cl_flag): + """ + Wrapper function to update event to tracking tables + """ + + sql_executor( + "INSERT INTO vnf_table_2 VALUES(%s,%s,%s,%s,%s)", + event_name, source_name_key, lastepo, srcname, cl_flag + ) + sql_executor( + "UPDATE vnf_table_1 SET SOURCE_NAME_COUNT = %s WHERE EVENT_NAME = %s", + source_name_key, event_name + ) -def postgres_db_open(username, password, host, port, database_name): - if os.getenv("pytest", "") == "test": - return True - connection = psycopg2.connect(database=database_name, user=username, password=password, host=host, port=port) - return connection +def parse_event (jsonstring): + """ + Function to parse incoming event as json object + and parse out required attributes + """ + _logger.info("HBT jsonstring: %s", jsonstring) + #convert string to object + jitem = json.loads(jsonstring) + + try: + srcname = jitem["event"]["commonEventHeader"]["sourceName"] + lastepo = jitem["event"]["commonEventHeader"]["lastEpochMicrosec"] + # if lastEpochMicrosec looks like microsec, align it with millisec + if lastepo > 1000000000000000: + lastepo = int(lastepo / 1000) + seqnum = jitem["event"]["commonEventHeader"]["sequence"] + event_name = jitem["event"]["commonEventHeader"]["eventName"] + msg = "HBT:Newly received HB event values ::", event_name, lastepo, srcname + _logger.info(msg) + return (srcname,lastepo,seqnum,event_name) + except Exception as err: + msg = "HBT message process error - ", err + _logger.error(msg) +def get_eventnamelist (): + """ + Function to fetch active monitored eventname list + """ + cur = sql_executor("SELECT event_name FROM vnf_table_1",) + eventname_list = [item[0] for item in cur.fetchall()] + msg = "\n\nHBT:eventnameList values ", eventname_list + _logger.info(msg) + return eventname_list -def db_table_creation_check(connection_db, table_name): - if os.getenv("pytest", "") == "test": - return True +def check_and_create_vnf2_table (): + """ + Check and create vnf_table_2 used for tracking HB entries + """ try: - cur = connection_db.cursor() - cur.execute("SELECT * FROM information_schema.tables WHERE table_name = %s", (table_name,)) + table_exist = False + cur = sql_executor("SELECT * FROM information_schema.tables WHERE table_name = %s", "vnf_table_2") database_names = cur.fetchone() if database_names is not None: - if table_name in database_names: - return True + if "vnf_table_2" in database_names: + table_exist = True + + if table_exist == False: + msg = "HBT:Creating vnf_table_2" + _logger.info(msg) + sql_executor( + """ + CREATE TABLE vnf_table_2 ( + EVENT_NAME varchar, + SOURCE_NAME_KEY integer, + PRIMARY KEY(EVENT_NAME, SOURCE_NAME_KEY), + LAST_EPO_TIME BIGINT, + SOURCE_NAME varchar, + CL_FLAG integer + )""" + ,) else: - return False - except psycopg2.DatabaseError as e: - msg = "COMMON:Error %s" % e - _logger.error(msg) - finally: - cur.close() - - -def commit_db(connection_db): - if os.getenv("pytest", "") == "test": - return True - try: - connection_db.commit() # <--- makes sure the change is shown in the database + msg = "HBT:vnf_table_2 is already there" + _logger.info(msg) return True except psycopg2.DatabaseError as e: msg = "COMMON:Error %s" % e _logger.error(msg) return False + +def check_process_reconfiguration(username, password, host, port, database_name): + """ + Verify if DB configuration in progress + """ + while True: + hbc_pid, hbc_state, hbc_src_name, hbc_time = db.read_hb_common( + username, password, host, port, database_name + ) + if hbc_state == "RECONFIGURATION": + _logger.info("HBT: RECONFIGURATION in-progress. Waiting for hb_common state to become RUNNING") + time.sleep(10) + else: + _logger.info("HBT: hb_common state is RUNNING") + break + return False + +def postgres_db_open(): + """ + Wrapper function for returning DB connection object + """ + + global configjsonfile + + ( + ip_address, + port_num, + user_name, + password, + db_name, + cbs_polling_required, + cbs_polling_interval, + ) = db.read_hb_properties(configjsonfile) + connection = psycopg2.connect(database=db_name, user=user_name, password=password, host=ip_address, port=port_num) + return connection + + +def sql_executor (query, *values): + """ + wrapper method for DB operation + """ + _logger.info("HBT query: %s values: %s", query, values) + + connection_db = postgres_db_open() + cur = connection_db.cursor() + cur.execute(query, values) + update_commands = ["CREATE", "INSERT", "UPDATE"] + if any (x in query for x in update_commands): + try: + connection_db.commit() # <--- makes sure the change is shown in the database + except psycopg2.DatabaseError as e: + msg = "COMMON:Error %s" % e + _logger.error(msg) + return cur def commit_and_close_db(connection_db): - if os.getenv("pytest", "") == "test": - return True try: connection_db.commit() # <--- makes sure the change is shown in the database connection_db.close() @@ -277,18 +307,10 @@ def commit_and_close_db(connection_db): if __name__ == "__main__": get_logger.configure_logger("htbtworker") - jsfile = sys.argv[1] + configjsonfile = sys.argv[1] msg = "HBT:HeartBeat thread Created" _logger.info("HBT:HeartBeat thread Created") - msg = "HBT:The config file name passed is -%s", jsfile + msg = "HBT:The config file name passed is -%s", configjsonfile _logger.info(msg) - ( - ip_address, - port_num, - user_name, - password, - db_name, - cbs_polling_required, - cbs_polling_interval, - ) = db.read_hb_properties(jsfile) - process_msg(jsfile, user_name, password, ip_address, port_num, db_name) + process_msg(configjsonfile) + diff --git a/miss_htbt_service/misshtbtd.py b/miss_htbt_service/misshtbtd.py index fd1a09c..23d4835 100644 --- a/miss_htbt_service/misshtbtd.py +++ b/miss_htbt_service/misshtbtd.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # ============LICENSE_START======================================================= -# Copyright (c) 2017-2022 AT&T Intellectual Property. All rights reserved. +# Copyright (c) 2017-2023 AT&T Intellectual Property. All rights reserved. # Copyright (c) 2019 Pantheon.tech. All rights reserved. # Copyright (c) 2020 Deutsche Telekom. All rights reserved. # Copyright (c) 2021 Samsung Electronics. All rights reserved. @@ -40,14 +40,15 @@ import yaml import socket import os.path as path import tempfile +import psycopg2 from pathlib import Path import check_health import htbtworker as heartbeat import get_logger import cbs_polling -from mod import trapd_settings as tds -from mod.trapd_get_cbs_config import get_cbs_config +from mod import htbt_settings as tds +from mod.htbt_get_cbs_config import get_cbs_config hb_properties_file = path.abspath(path.join(__file__, "../config/hbproperties.yaml")) _logger = logging.getLogger(__name__) @@ -83,14 +84,7 @@ def create_database(update_db, jsfile, ip_address, port_num, user_name, password def read_hb_common(user_name, password, ip_address, port_num, db_name): - env_pytest = os.getenv("pytest", "") - if env_pytest == "test": - hbc_pid = 10 - hbc_src_name = "srvc_name" - hbc_time = 1584595881 - hbc_state = "RUNNING" - return hbc_pid, hbc_state, hbc_src_name, hbc_time - connection_db = heartbeat.postgres_db_open(user_name, password, ip_address, port_num, db_name) + connection_db = heartbeat.postgres_db_open() cur = connection_db.cursor() cur.execute("SELECT process_id, source_name, last_accessed_time, current_state FROM hb_common") rows = cur.fetchall() @@ -98,7 +92,6 @@ def read_hb_common(user_name, password, ip_address, port_num, db_name): hbc_src_name = rows[0][1] hbc_time = rows[0][2] hbc_state = rows[0][3] - heartbeat.commit_and_close_db(connection_db) cur.close() return hbc_pid, hbc_state, hbc_src_name, hbc_time @@ -109,9 +102,9 @@ def create_update_hb_common(update_flg, process_id, state, user_name, password, source_name = source_name + "-" + os.getenv("SERVICE_NAME", "") env_pytest = os.getenv("pytest", "") if env_pytest != "test": - connection_db = heartbeat.postgres_db_open(user_name, password, ip_address, port_num, db_name) + connection_db = heartbeat.postgres_db_open() cur = connection_db.cursor() - if heartbeat.db_table_creation_check(connection_db, "hb_common") is False: + if db_table_creation_check(connection_db, "hb_common") is False: cur.execute( """ CREATE TABLE hb_common ( @@ -133,18 +126,33 @@ def create_update_hb_common(update_flg, process_id, state, user_name, password, heartbeat.commit_and_close_db(connection_db) cur.close() - +def db_table_creation_check(connection_db, table_name): + cur = connection_db.cursor() + try: + cur.execute("SELECT * FROM information_schema.tables WHERE table_name = %s", (table_name,)) + database_names = cur.fetchone() + if database_names is not None: + if table_name in database_names: + return True + else: + return False + except psycopg2.DatabaseError as e: + msg = "COMMON:Error %s" % e + _logger.error(msg) + finally: + cur.close() + def create_update_vnf_table_1(jsfile, update_db, connection_db): with open(jsfile, "r") as outfile: cfg = json.load(outfile) hbcfg = cfg["heartbeat_config"] jhbcfg = json.loads(hbcfg) + cur = connection_db.cursor() env_pytest = os.getenv("pytest", "") if env_pytest == "test": vnf_list = ["Heartbeat_vDNS", "Heartbeat_vFW", "Heartbeat_xx"] else: - cur = connection_db.cursor() - if heartbeat.db_table_creation_check(connection_db, "vnf_table_1") is False: + if db_table_creation_check(connection_db, "vnf_table_1") is False: cur.execute( """ CREATE TABLE vnf_table_1 ( @@ -232,14 +240,14 @@ def create_update_vnf_table_1(jsfile, update_db, connection_db): def hb_worker_process(config_file_path): subprocess.call([ABSOLUTE_PATH1, config_file_path]) sys.stdout.flush() - _logger.info("MSHBT:Creaated Heartbeat worker process") + _logger.info("MSHBT:Created Heartbeat worker process") return def db_monitoring_process(current_pid, jsfile): subprocess.call([ABSOLUTE_PATH2, str(current_pid), jsfile]) sys.stdout.flush() - _logger.info("MSHBT:Creaated DB Monitoring process") + _logger.info("MSHBT:Created DB Monitoring process") return @@ -335,10 +343,10 @@ def create_update_db(update_db, jsfile, ip_address, port_num, user_name, passwor create_database(update_db, jsfile, ip_address, port_num, user_name, password, db_name) msg = "MSHBT: DB parameters -", ip_address, port_num, user_name, password, db_name _logger.info(msg) - connection_db = heartbeat.postgres_db_open(user_name, password, ip_address, port_num, db_name) + connection_db = heartbeat.postgres_db_open() cur = connection_db.cursor() if update_db == 0: - if heartbeat.db_table_creation_check(connection_db, "vnf_table_1") is False: + if db_table_creation_check(connection_db, "vnf_table_1") is False: create_update_vnf_table_1(jsfile, update_db, connection_db) else: create_update_vnf_table_1(jsfile, update_db, connection_db) @@ -367,6 +375,7 @@ def create_process(job_list, jsfile, pid_current): return job_list + def main(): get_logger.configure_logger("misshtbtd") pid_current = os.getpid() @@ -412,7 +421,7 @@ def main(): _logger.info("MSHBD:Current process id is %d", pid_current) _logger.info("MSHBD:Now be in a continuous loop") i = 0 - while True: + while True: # pragma: no cover hbc_pid, hbc_state, hbc_src_name, hbc_time = read_hb_common( user_name, password, ip_address, port_num, db_name ) @@ -432,16 +441,6 @@ def main(): _logger.info(msg) source_name = socket.gethostname() source_name = source_name + "-" + str(os.getenv("SERVICE_NAME", "")) - env_pytest = os.getenv("pytest", "") - if env_pytest == "test": - if i == 2: - hbc_pid = pid_current - source_name = hbc_src_name - hbc_state = "RECONFIGURATION" - elif i > 3: - hbc_pid = pid_current - source_name = hbc_src_name - hbc_state = "RUNNING" if time_difference < 60: if (int(hbc_pid) == int(pid_current)) and (source_name == hbc_src_name): msg = "MSHBD:config status is", hbc_state @@ -491,7 +490,7 @@ def main(): _logger.info("MSHBD:HB and DBM thread are waiting to become ACTIVE") else: jsfile = fetch_json_file() - msg = "MSHBD: Creating HB and DBM threads. The param pssed %d and %s", jsfile, pid_current + msg = "MSHBD: Creating HB and DBM threads. The param passed %d and %s", jsfile, pid_current _logger.info(msg) job_list = create_process(job_list, jsfile, pid_current) hbc_pid, hbc_state, hbc_src_name, hbc_time = read_hb_common( @@ -504,24 +503,6 @@ def main(): else: _logger.error("MSHBD:ERROR - Active instance is not updating hb_common in 60 sec - ERROR") time.sleep(25) - if os.getenv("pytest", "") == "test": - i = i + 1 - if i > 5: - _logger.info("Terminating main process for pytest") - cbs_polling_proc.terminate() - time.sleep(1) - cbs_polling_proc.join() - if len(job_list) > 0: - job_list[0].terminate() - time.sleep(1) - job_list[0].join() - job_list.remove(job_list[0]) - if len(job_list) > 0: - job_list[0].terminate() - time.sleep(1) - job_list[0].join() - job_list.remove(job_list[0]) - break except Exception as e: msg = "MSHBD:Exception as %s" % (str(traceback.format_exc())) diff --git a/miss_htbt_service/mod/trapd_exit.py b/miss_htbt_service/mod/htbt_exit.py index 7791b31..3779e15 100644 --- a/miss_htbt_service/mod/trapd_exit.py +++ b/miss_htbt_service/mod/htbt_exit.py @@ -1,5 +1,5 @@ # ============LICENSE_START======================================================= -# Copyright (c) 2017-2022 AT&T Intellectual Property. All rights reserved. +# Copyright (c) 2017-2023 AT&T Intellectual Property. All rights reserved. # Copyright (c) 2019 Pantheon.tech. All rights reserved. # Copyright (c) 2020 Deutsche Telekom. All rights reserved. # ================================================================================ @@ -17,7 +17,7 @@ # ============LICENSE_END========================================================= """ -trapc_exit_snmptrapd is responsible for removing any existing runtime PID +htbt_exit is responsible for removing any existing runtime PID file, and exiting with the provided (param 1) exit code """ @@ -25,7 +25,7 @@ __docformat__ = "restructuredtext" import sys import os -from mod.trapd_runtime_pid import rm_pid +from mod.htbt_runtime_pid import rm_pid prog_name = os.path.basename(__file__) diff --git a/miss_htbt_service/mod/trapd_get_cbs_config.py b/miss_htbt_service/mod/htbt_get_cbs_config.py index 034b32b..613b46f 100644 --- a/miss_htbt_service/mod/trapd_get_cbs_config.py +++ b/miss_htbt_service/mod/htbt_get_cbs_config.py @@ -1,5 +1,5 @@ # ============LICENSE_START======================================================= -# Copyright (c) 2018-2022 AT&T Intellectual Property. All rights reserved. +# Copyright (c) 2018-2023 AT&T Intellectual Property. All rights reserved. # Copyright (c) 2019 Pantheon.tech. All rights reserved. # Copyright (c) 2020 Deutsche Telekom. All rights reserved. # Copyright (c) 2021 Samsung Electronics. All rights reserved. @@ -28,15 +28,15 @@ __docformat__ = "restructuredtext" import json import os from onap_dcae_cbs_docker_client.client import get_config -from mod import trapd_settings as tds -from mod.trapd_exit import cleanup, cleanup_and_exit -from mod.trapd_io import stdout_logger +from mod import htbt_settings as tds +from mod.htbt_exit import cleanup, cleanup_and_exit +from mod.htbt_io import stdout_logger prog_name = os.path.basename(__file__) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -# function: trapd_get_config_sim +# function: htbt_get_config_sim # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # diff --git a/miss_htbt_service/mod/trapd_http_session.py b/miss_htbt_service/mod/htbt_http_session.py index 17eb302..f0a409a 100644 --- a/miss_htbt_service/mod/trapd_http_session.py +++ b/miss_htbt_service/mod/htbt_http_session.py @@ -1,5 +1,5 @@ # ============LICENSE_START======================================================= -# Copyright (c) 2017-2022 AT&T Intellectual Property. All rights reserved. +# Copyright (c) 2017-2023 AT&T Intellectual Property. 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. @@ -15,7 +15,7 @@ # ============LICENSE_END========================================================= """ -trapd_http_session establishes an http session for future use in publishing +htbt_http_session establishes an http session for future use in publishing messages to the dmaap cluster. """ diff --git a/miss_htbt_service/mod/trapd_io.py b/miss_htbt_service/mod/htbt_io.py index 26445fc..3f16a7b 100644 --- a/miss_htbt_service/mod/trapd_io.py +++ b/miss_htbt_service/mod/htbt_io.py @@ -1,5 +1,5 @@ # ============LICENSE_START=======================================================) -# Copyright (c) 2018-2022 AT&T Intellectual Property. All rights reserved. +# Copyright (c) 2018-2023 AT&T Intellectual Property. All rights reserved. # Copyright (c) 2019 Pantheon.tech. All rights reserved. # Copyright (c) 2020 Deutsche Telekom. All rights reserved. # ================================================================================ diff --git a/miss_htbt_service/mod/trapd_runtime_pid.py b/miss_htbt_service/mod/htbt_runtime_pid.py index 823d29f..d086ed2 100644 --- a/miss_htbt_service/mod/trapd_runtime_pid.py +++ b/miss_htbt_service/mod/htbt_runtime_pid.py @@ -1,5 +1,5 @@ # ============LICENSE_START======================================================= -# Copyright (c) 2017-2022 AT&T Intellectual Property. All rights reserved. +# Copyright (c) 2017-2023 AT&T Intellectual Property. 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. @@ -15,7 +15,7 @@ # ============LICENSE_END========================================================= """ -trapd_runtime_pid maintains a 'PID file' (file that contains the +htbt_runtime_pid maintains a 'PID file' (file that contains the PID of currently running trap receiver) """ diff --git a/miss_htbt_service/mod/trapd_settings.py b/miss_htbt_service/mod/htbt_settings.py index 0f6a9a1..b5b58cc 100644 --- a/miss_htbt_service/mod/trapd_settings.py +++ b/miss_htbt_service/mod/htbt_settings.py @@ -1,5 +1,5 @@ # ============LICENSE_START=======================================================) -# Copyright (c) 2018-2022 AT&T Intellectual Property. All rights reserved. +# Copyright (c) 2018-2023 AT&T Intellectual Property. 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. diff --git a/miss_htbt_service/mod/trapd_vnf_table.py b/miss_htbt_service/mod/htbt_vnf_table.py index f9fecbb..3396e80 100644 --- a/miss_htbt_service/mod/trapd_vnf_table.py +++ b/miss_htbt_service/mod/htbt_vnf_table.py @@ -1,5 +1,5 @@ # ============LICENSE_START======================================================= -# Copyright (c) 2017-2022 AT&T Intellectual Property. All rights reserved. +# Copyright (c) 2017-2023 AT&T Intellectual Property. All rights reserved. # Copyright (c) 2019 Pantheon.tech. All rights reserved. # Copyright (c) 2020 Deutsche Telekom. All rights reserved. # Copyright (c) 2021 Samsung Electronics. All rights reserved. @@ -21,7 +21,7 @@ # Author Kiran Mandal (km386e) """ -trapd_vnf_table verifies the successful creation of DB Tables. +htbt_vnf_table verifies the successful creation of DB Tables. """ import logging import os @@ -57,9 +57,9 @@ def hb_properties(): def verify_DB_creation_1(user_name, password, ip_address, port_num, db_name): - connection_db = pm.postgres_db_open(user_name, password, ip_address, port_num, db_name) + connection_db = pm.postgres_db_open() try: - _db_status = pm.db_table_creation_check(connection_db, "vnf_table_1") + _db_status = db.db_table_creation_check(connection_db, "vnf_table_1") except Exception: return None @@ -68,20 +68,20 @@ def verify_DB_creation_1(user_name, password, ip_address, port_num, db_name): def verify_DB_creation_2(user_name, password, ip_address, port_num, db_name): - connection_db = pm.postgres_db_open(user_name, password, ip_address, port_num, db_name) + connection_db = pm.postgres_db_open() try: - _db_status = pm.db_table_creation_check(connection_db, "vnf_table_2") + _db_status = db.db_table_creation_check(connection_db, "vnf_table_2") except Exception: return None return _db_status -def verify_DB_creation_hb_common(user_name, password, ip_address, port_num, db_name): +def verify_DB_creation_hb_common(): - connection_db = pm.postgres_db_open(user_name, password, ip_address, port_num, db_name) + connection_db = pm.postgres_db_open() try: - _db_status = pm.db_table_creation_check(connection_db, "hb_common") + _db_status = db.db_table_creation_check(connection_db, "hb_common") except Exception: return None @@ -1,7 +1,7 @@ <?xml version="1.0"?> <!-- ============LICENSE_START======================================================= -Copyright (c) 2017-2022 AT&T Intellectual Property. All rights reserved. +Copyright (c) 2017-2023 AT&T Intellectual Property. All rights reserved. Copyright (c) 2021 Samsung Electronics. All rights reserved. ================================================================================ Licensed under the Apache License, Version 2.0 (the "License"); @@ -37,7 +37,7 @@ limitations under the License. <groupId>org.onap.dcaegen2.services</groupId> <artifactId>heartbeat</artifactId> <name>dcaegen2-services-heartbeat</name> - <version>2.5.0</version> + <version>2.6.0</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <sonar.sources>.</sonar.sources> @@ -1,5 +1,5 @@ # ============LICENSE_START======================================================= -# Copyright (c) 2017-2022 AT&T Intellectual Property. All rights reserved. +# Copyright (c) 2017-2023 AT&T Intellectual Property. All rights reserved. # Copyright (c) 2021 Samsung Electronics. All rights reserved. # ================================================================================ # Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,7 +20,7 @@ from setuptools import setup, find_packages setup( name="miss_htbt_service", description="Missing heartbeat microservice to communicate with policy-engine", - version="2.5.0", + version="2.6.0", # packages=find_packages(exclude=["tests.*", "tests"]), packages=find_packages(), install_requires=[ diff --git a/tests/hbproperties-test.yaml b/tests/hbproperties-test.yaml new file mode 100644 index 0000000..1dc649c --- /dev/null +++ b/tests/hbproperties-test.yaml @@ -0,0 +1,11 @@ +#Postgres database input +#pg_ipAddress: 127.0.0.1 +pg_ipAddress: 10.0.0.0 +pg_portNum: "1234" +pg_userName: postgres-test +pg_passwd: postgres-test +pg_dbName: postgres + +#Periodic polling of CBS config download +CBS_polling_allowed: "True" +CBS_polling_interval: "300" diff --git a/tests/test-config.json b/tests/test-config.json new file mode 100644 index 0000000..e853f6a --- /dev/null +++ b/tests/test-config.json @@ -0,0 +1 @@ +{"pg_ipAddress": "10.0.4.1", "pg_userName": "postgres", "pg_dbName": "postgres", "streams_subscribes": {"ves-heartbeat": {"type": "message_router", "dmaap_info": {"topic_url": "http://10.12.5.252:3904/events/unauthenticated.SEC_HEARTBEAT_INPUT"}}}, "consumerID": "1", "CBS_polling_interval": "300", "pg_passwd": "postgres", "streams_publishes": {"dcae_cl_out": {"type": "message_router", "dmaap_info": {"topic_url": "http://10.12.5.252:3904/events/unauthenticated.DCAE_CL_OUTPUT"}}}, "pg_portNum": "5432", "CBS_polling_allowed": "True", "groupID": "groupID", "heartbeat_config": "{\"vnfs\": [{\"eventName\": \"Heartbeat_vDNS\",\"heartbeatcountmissed\": 3,\"heartbeatinterval\": 60,\"closedLoopControlName\": \"ControlLoopEvent1\",\t\"policyVersion\": \"1.0.0.5\",\t\"policyName\":\"vFireWall\",\"policyScope\": \"resource=sampleResource,type=sampletype,CLName=sampleCLName\",\"target_type\": \"VNF\",\t\"target\": \"genVnfName\",\t\"version\": \"1.0\"}, {\"eventName\": \"Heartbeat_vFW\",\"heartbeatcountmissed\": 3,\t\"heartbeatinterval\": 60,\"closedLoopControlName\": \"ControlLoopEvent1\",\"policyVersion\": \"1.0.0.5\",\"policyName\": \"vFireWall\",\"policyScope\": \"resource=sampleResource,type=sampletype,CLName=sampleCLName\",\t\"target_type\":\"VNF\",\t\"target\": \"genVnfName\",\t\"version\": \"1.0\"}, {\"eventName\": \"Heartbeat_xx\",\"heartbeatcountmissed\": 3,\t\"heartbeatinterval\": 60,\"closedLoopControlName\": \"ControlLoopEvent1\",\"policyVersion\": \"1.0.0.5\",\"policyName\": \"vFireWall\",\t\"policyScope\": \"resource=sampleResource,type=sampletype,CLName=sampleCLName\",\"target_type\": \"VNF\",\"target\": \"genVnfName\",\"version\": \"1.0\"}]}"} diff --git a/tests/test4.json b/tests/test4.json new file mode 100644 index 0000000..b223497 --- /dev/null +++ b/tests/test4.json @@ -0,0 +1 @@ +{"event":{"commonEventHeader":{"startEpochMicrosec":1621969018000,"sourceId":"79e90d76-513a-4f79-886d-470a0037c5cf","eventId":"Heartbeat_vDNS_10.0.0.1","nfcNamingCode":"DNS","reportingEntityId":"79e90d76-513a-4f79-886d-470a0037c5cf","internalHeaderFields":{"collectorTimeStamp":"Wed, 01 04 2023 01:36:35 GMT"},"eventType":"applicationVnf","priority":"Normal","version":3,"reportingEntityName":"VVVVVVcmd010","sequence":36312,"domain":"heartbeat","lastEpochMicrosec":1621969018000,"eventName":"Heartbeat_vDNS","sourceName":"zalp1bmdns01cmd010","nfNamingCode":"MDNS"}}} diff --git a/tests/test_db_monitoring.py b/tests/test_db_monitoring.py new file mode 100644 index 0000000..b9a644e --- /dev/null +++ b/tests/test_db_monitoring.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 +# ============LICENSE_START======================================================= +# Copyright (c) 2023 AT&T Intellectual Property. All rights reserved. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END========================================================= + +import db_monitoring +import htbtworker +import logging +import requests +import tempfile +import os +import json +import unittest + +from unittest.mock import * +from _pytest.outcomes import skip + +_logger = logging.getLogger(__name__) +class Test_db_monitoring(unittest.TestCase): + + def setUp(self): + htbtworker.configjsonfile = (os.path.dirname(__file__))+"/test-config.json" + + @patch('requests.post') + def test_sendControlLoopEvent(self, mock1): + status = True + mock_resp = Mock() + mock_resp.configure_mock( + **{ + "status_code": 200 + } + ) + mock1.return_value = mock_resp + db_monitoring.sendControlLoopEvent("ONSET", "ABC","1.0","vFW","vFW","VNF","NODE","1234567890","VFW","1.0","DCAE") + self.assertEqual(status, True) + db_monitoring.sendControlLoopEvent("ONSET", "ABC","1.0","vFW","vFW","VM","NODE","1234567890","VFW","1.0","DCAE") + self.assertEqual(status, True) + db_monitoring.sendControlLoopEvent("ABATED", "ABC","1.0","vFW","vFW","VNF","NODE","1234567890","VFW","1.0","DCAE") + self.assertEqual(status, True) + db_monitoring.sendControlLoopEvent("ABATED", "ABC","1.0","vFW","vFW","VM","NODE","1234567890","VFW","1.0","DCAE") + self.assertEqual(status, True) + + @patch('misshtbtd.read_hb_common',return_value = ("1234","RUNNING", "XYZ", 1234)) + @patch('htbtworker.postgres_db_open') + def test_db_monitoring(self, mock1, mock2): + status = True + mock_cursor = Mock() + mock2.cursor.return_value = mock_cursor + db_monitoring.db_monitoring("111",htbtworker.configjsonfile ,"testuser","testpwd","10.0.0.0","1234","db_name") + self.assertEqual(status, True) + db_monitoring.db_monitoring("1234",htbtworker.configjsonfile ,"testuser","testpwd","10.0.0.0","1234","db_name") + self.assertEqual(status, True) + mock1.cursor.return_value = ("1234","RECONFIGURATION", "XYZ", 1234) + db_monitoring.db_monitoring("1234",htbtworker.configjsonfile ,"testuser","testpwd","10.0.0.0","1234","db_name") + self.assertEqual(status, True) + + def test_db_monitoring_wrapper(self): + status = True + db_monitoring.db_monitoring_wrapper("111", htbtworker.configjsonfile, number_of_iterations=0) + self.assertEqual(status, True) + +if __name__ == "__main__": # pragma: no cover + unittest.main() diff --git a/tests/test_get_logger.py b/tests/test_get_logger.py index a4ceea5..1096271 100644 --- a/tests/test_get_logger.py +++ b/tests/test_get_logger.py @@ -1,5 +1,5 @@ # ============LICENSE_START======================================================= -# Copyright (c) 2020-2021 AT&T Intellectual Property. All rights reserved. +# Copyright (c) 2020-2023 AT&T Intellectual Property. All rights reserved. # Copyright (c) 2021 Fujitsu Ltd. # ================================================================================ # Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,6 +24,8 @@ log = logging.getLogger(__name__) def test_configure_logger(): + # logpath = (os.path.dirname(__file__))+"hb_logs.txt" + # expected_log_path = Path(logpath) expected_log_path = Path("./hb_logs.txt") if expected_log_path.exists(): os.remove(expected_log_path) @@ -34,6 +36,8 @@ def test_configure_logger(): def test_configure_logger_with_name(): + # logpath = (os.path.dirname(__file__))+"hb_htbtworker_logs.txt" + # expected_log_path = Path(logpath) expected_log_path = Path("./hb_htbtworker_logs.txt") if expected_log_path.exists(): os.remove(expected_log_path) diff --git a/tests/test_trapd_exit.py b/tests/test_htbt_exit.py index 8803b29..f3698d5 100644 --- a/tests/test_trapd_exit.py +++ b/tests/test_htbt_exit.py @@ -1,5 +1,5 @@ # ============LICENSE_START======================================================= -# Copyright (c) 2017-2021 AT&T Intellectual Property. All rights reserved. +# Copyright (c) 2017-2023 AT&T Intellectual Property. All rights reserved. # Copyright (c) 2019 Pantheon.tech. All rights reserved. # Copyright (c) 2021 Fujitsu Ltd. # ================================================================================ @@ -18,7 +18,7 @@ import pytest import unittest -from miss_htbt_service.mod import trapd_exit +from miss_htbt_service.mod import htbt_exit pid_file = "/tmp/test_pid_file" pid_file_dne = "/tmp/test_pid_file_NOT" @@ -36,7 +36,7 @@ class test_cleanup_and_exit(unittest.TestCase): open(pid_file, "w") with pytest.raises(SystemExit) as pytest_wrapped_sys_exit: - result = trapd_exit.cleanup_and_exit(0, pid_file) + result = htbt_exit.cleanup_and_exit(0, pid_file) assert pytest_wrapped_sys_exit.type == SystemExit assert pytest_wrapped_sys_exit.value.code == 0 @@ -45,6 +45,6 @@ class test_cleanup_and_exit(unittest.TestCase): Test exit with missing PID file exits non-zero """ with pytest.raises(SystemExit) as pytest_wrapped_sys_exit: - result = trapd_exit.cleanup_and_exit(0, pid_file_dne) + result = htbt_exit.cleanup_and_exit(0, pid_file_dne) assert pytest_wrapped_sys_exit.type == SystemExit assert pytest_wrapped_sys_exit.value.code == 1 diff --git a/tests/test_trapd_get_cbs_config.py b/tests/test_htbt_get_cbs_config.py index 75e2055..99e347c 100644 --- a/tests/test_trapd_get_cbs_config.py +++ b/tests/test_htbt_get_cbs_config.py @@ -1,5 +1,5 @@ # ============LICENSE_START======================================================= -# Copyright (c) 2017-2022 AT&T Intellectual Property. All rights reserved. +# Copyright (c) 2017-2023 AT&T Intellectual Property. All rights reserved. # Copyright (c) 2019 Pantheon.tech. All rights reserved. # Copyright (c) 2021 Fujitsu Ltd. # ================================================================================ @@ -19,13 +19,17 @@ import pytest import unittest import os +import cbs_polling as cp +import time +import misshtbtd +from unittest.mock import * -from miss_htbt_service.mod import trapd_get_cbs_config +from miss_htbt_service.mod import htbt_get_cbs_config class test_get_cbs_config(unittest.TestCase): """ - Test the trapd_get_cbs_config mod + Test the htbt_get_cbs_config mod """ pytest_json_data = ( @@ -77,7 +81,7 @@ class test_get_cbs_config(unittest.TestCase): " ]" " }," ' "streams_publishes": {' - ' "ves_heartbeat": {' + ' "dcae_cl_out": {' ' "dmaap_info": {' ' "topic_url": "http://message-router:3904/events/unauthenticated.DCAE_CL_OUTPUT/"' " }," @@ -85,18 +89,24 @@ class test_get_cbs_config(unittest.TestCase): " }" " }," ' "streams_subscribes": {' - ' "ves_heartbeat": {' + ' "ves-heartbeat": {' ' "dmaap_info": {' ' "topic_url": "http://message-router:3904/events/unauthenticated.SEC_HEARTBEAT_INPUT/"' " }," ' "type": "message_router"' " }" - " }" + " }," + ' "pg_ipAddress": "10.0.4.1",' + ' "pg_userName": "postgres",' + ' "pg_dbName": "postgres",' + ' "pg_passwd": "postgres",' + ' "pg_portNum": "5432"' "}" ) - # create copy of snmptrapd.json for pytest - pytest_json_config = "/tmp/opt/app/miss_htbt_service/etc/config.json" + # create copy of snmphtbt.json for pytest + #pytest_json_config = "/tmp/opt/app/miss_htbt_service/etc/config.json" + pytest_json_config = "test-config.json" with open(pytest_json_config, "w") as outfile: outfile.write(pytest_json_data) @@ -107,7 +117,7 @@ class test_get_cbs_config(unittest.TestCase): """ with pytest.raises(Exception) as pytest_wrapped_sys_exit: - result = trapd_get_cbs_config.get_cbs_config() + result = htbt_get_cbs_config.get_cbs_config() assert pytest_wrapped_sys_exit.type == SystemExit def test_cbs_fallback_env_present(self): @@ -119,3 +129,20 @@ class test_get_cbs_config(unittest.TestCase): result = True print("result: %s" % result) self.assertEqual(result, True) + + @patch('misshtbtd.create_update_hb_common') + @patch('misshtbtd.read_hb_common') + def test_poll_cbs(self, mock1, mock2): + """ + TBD + """ + status = True + current_time = round(time.time()) + mock1.return_value = ('1', 'RUNNING', 'AA', current_time) + # configjsonfile = (os.path.dirname(__file__))+"/test-config.json" + configjsonfile = "test-config.json" + os.environ.update(CBS_HTBT_JSON=configjsonfile) + os.environ["pytest"] = "test" + cp.poll_cbs(1) + self.assertEqual(status, True) + diff --git a/tests/test_trapd_http_session.py b/tests/test_htbt_http_session.py index 070fc93..ed3a33a 100644 --- a/tests/test_trapd_http_session.py +++ b/tests/test_htbt_http_session.py @@ -1,5 +1,5 @@ # ============LICENSE_START======================================================= -# Copyright (c) 2017-2021 AT&T Intellectual Property. All rights reserved. +# Copyright (c) 2017-2023 AT&T Intellectual Property. All rights reserved. # Copyright (c) 2019 Pantheon.tech. All rights reserved. # Copyright (c) 2021 Fujitsu Ltd. # ================================================================================ @@ -17,7 +17,7 @@ # ============LICENSE_END========================================================= import unittest -from miss_htbt_service.mod import trapd_http_session +from miss_htbt_service.mod import htbt_http_session class test_init_session_obj(unittest.TestCase): @@ -29,6 +29,6 @@ class test_init_session_obj(unittest.TestCase): """ Test that attempt to create http session object works """ - result = trapd_http_session.init_session_obj() + result = htbt_http_session.init_session_obj() compare = str(result).startswith("<requests.sessions.Session object at") self.assertEqual(compare, True) diff --git a/tests/test_trapd_runtime_pid.py b/tests/test_htbt_runtime_pid.py index 47bc642..96379d9 100644 --- a/tests/test_trapd_runtime_pid.py +++ b/tests/test_htbt_runtime_pid.py @@ -1,5 +1,5 @@ # ============LICENSE_START======================================================= -# Copyright (c) 2017-2021 AT&T Intellectual Property. All rights reserved. +# Copyright (c) 2017-2023 AT&T Intellectual Property. All rights reserved. # Copyright (c) 2019 Pantheon.tech. All rights reserved. # Copyright (c) 2021 Fujitsu Ltd. # ================================================================================ @@ -17,7 +17,7 @@ # ============LICENSE_END========================================================= import unittest -from miss_htbt_service.mod import trapd_runtime_pid +from miss_htbt_service.mod import htbt_runtime_pid class test_save_pid(unittest.TestCase): @@ -29,14 +29,14 @@ class test_save_pid(unittest.TestCase): """ Test that attempt to create pid file in standard location works """ - result = trapd_runtime_pid.save_pid("/tmp/snmptrap_test_pid_file") + result = htbt_runtime_pid.save_pid("/tmp/snmptrap_test_pid_file") self.assertEqual(result, True) def test_missing_directory(self): """ Test that attempt to create pid file in missing dir fails """ - result = trapd_runtime_pid.save_pid("/bogus/directory/for/snmptrap_test_pid_file") + result = htbt_runtime_pid.save_pid("/bogus/directory/for/snmptrap_test_pid_file") self.assertEqual(result, False) @@ -50,14 +50,14 @@ class test_rm_pid(unittest.TestCase): Test that attempt to remove pid file in standard location works """ # must create it before removing it - result = trapd_runtime_pid.save_pid("/tmp/snmptrap_test_pid_file") + result = htbt_runtime_pid.save_pid("/tmp/snmptrap_test_pid_file") self.assertEqual(result, True) - result = trapd_runtime_pid.rm_pid("/tmp/snmptrap_test_pid_file") + result = htbt_runtime_pid.rm_pid("/tmp/snmptrap_test_pid_file") self.assertEqual(result, True) def test_missing_file(self): """ Test that attempt to rm non-existent pid file fails """ - result = trapd_runtime_pid.rm_pid("/tmp/snmptrap_test_pid_file_9999") + result = htbt_runtime_pid.rm_pid("/tmp/snmptrap_test_pid_file_9999") self.assertEqual(result, False) diff --git a/tests/test_trapd_settings.py b/tests/test_htbt_settings.py index 743fa68..3db86a1 100644 --- a/tests/test_trapd_settings.py +++ b/tests/test_htbt_settings.py @@ -1,5 +1,5 @@ # ============LICENSE_START======================================================= -# Copyright (c) 2017-2022 AT&T Intellectual Property. All rights reserved. +# Copyright (c) 2017-2023 AT&T Intellectual Property. All rights reserved. # Copyright (c) 2019 Pantheon.tech. All rights reserved. # Copyright (c) 2021 Fujitsu Ltd. # ================================================================================ @@ -18,7 +18,7 @@ import unittest -from miss_htbt_service.mod import trapd_settings as tds +from miss_htbt_service.mod import htbt_settings as tds pid_file = "/tmp/test_pid_file" pid_file_dne = "/tmp/test_pid_file_NOT" diff --git a/tests/test_trapd_vnf_table.py b/tests/test_htbt_vnf_table.py index 2e0f22a..4b6c3f1 100644 --- a/tests/test_trapd_vnf_table.py +++ b/tests/test_htbt_vnf_table.py @@ -1,5 +1,5 @@ # ============LICENSE_START======================================================= -# Copyright (c) 2017-2022 AT&T Intellectual Property. All rights reserved. +# Copyright (c) 2017-2023 AT&T Intellectual Property. All rights reserved. # Copyright (c) 2019 Pantheon.tech. All rights reserved. # Copyright (c) 2020 Deutsche Telekom. All rights reserved. # Copyright (c) 2021 Fujitsu Ltd. @@ -19,11 +19,13 @@ # # Author Prakask H (ph553f) """ -test_trapd_vnf_table contains test cases related to DB Tables and cbs polling. +test_htbt_vnf_table contains test cases related to DB Tables and cbs polling. """ import logging import unittest -from mod.trapd_vnf_table import ( +import os +from unittest.mock import * +from mod.htbt_vnf_table import ( verify_DB_creation_1, verify_DB_creation_2, verify_DB_creation_hb_common, @@ -50,28 +52,40 @@ class test_vnf_tables(unittest.TestCase): global ip_address, port_num, user_name, password, db_name, cbs_polling_required, cbs_polling_interval ip_address, port_num, user_name, password, db_name, cbs_polling_required, cbs_polling_interval = hb_properties() - def test_validate_vnf_table_1(self): + @patch('htbtworker.postgres_db_open') + @patch('misshtbtd.db_table_creation_check', return_value=True) + def test_validate_vnf_table_1(self, mock, mock1): result = verify_DB_creation_1(user_name, password, ip_address, port_num, db_name) self.assertEqual(result, True) - def test_validate_vnf_table_2(self): + @patch('htbtworker.postgres_db_open') + @patch('misshtbtd.db_table_creation_check', return_value=True) + def test_validate_vnf_table_2(self, mock, mock1): result = verify_DB_creation_2(user_name, password, ip_address, port_num, db_name) self.assertEqual(result, True) - def test_validate_hb_common(self): - result = verify_DB_creation_hb_common(user_name, password, ip_address, port_num, db_name) + @patch('htbtworker.postgres_db_open') + @patch('misshtbtd.db_table_creation_check', return_value=True) + def test_validate_hb_common(self, mock, mock1): + result = verify_DB_creation_hb_common() self.assertEqual(result, True) - - def test_cbspolling(self): + + @patch('cbs_polling.poll_cbs') + def test_cbspolling(self, mock): # Check if no exception thrown verify_cbspolling() - def test_fetch_json_file(self): + @patch('misshtbtd.fetch_json_file') + def test_fetch_json_file(self, mock1): + configjsonfile = (os.path.dirname(__file__))+"/test-config.json" + mock1.return_value = configjsonfile + result = verify_fetch_json_file() _logger.info(result) self.assertEqual(result, True) - def test_misshtbtdmain(self): + @patch('misshtbtd.main') + def test_misshtbtdmain(self, mock): result = verify_misshtbtdmain() _logger.info(result) self.assertEqual(result, True) @@ -81,7 +95,14 @@ class test_vnf_tables(unittest.TestCase): _logger.info(result) self.assertEqual(result, True) - def test_dbmonitoring(self): + @patch('misshtbtd.fetch_json_file') + @patch('misshtbtd.read_hb_common') + @patch('db_monitoring.db_monitoring') + def test_dbmonitoring(self, mock1, mock2, mock3): + configjsonfile = (os.path.dirname(__file__))+"/test-config.json" + mock1.return_value = configjsonfile + mock2.return_value = ("1234","RUNNING", "XYZ", 1234) + result = verify_dbmonitoring() _logger.info(result) self.assertEqual(result, True) diff --git a/tests/test_htbtworker.py b/tests/test_htbtworker.py index 78c9087..ee03ddb 100644 --- a/tests/test_htbtworker.py +++ b/tests/test_htbtworker.py @@ -1,5 +1,5 @@ # ============LICENSE_START======================================================= -# Copyright (c) 2020-2022 AT&T Intellectual Property. All rights reserved. +# Copyright (c) 2020-2023 AT&T Intellectual Property. 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. @@ -14,37 +14,152 @@ # limitations under the License. # ============LICENSE_END========================================================= -from miss_htbt_service import htbtworker +import htbtworker import os import tempfile -import json +import json +import unittest +from unittest.mock import * +from _pytest.outcomes import skip +class Test_htbtworker(unittest.TestCase): -def run_test(i): - """ - read_json_file() opens the file CWD/prefix/test{j}.json and returns the json value found there - """ - j = i + 1 - tdir = tempfile.TemporaryDirectory() - prefix = "../../../../../../../../../../../../.." - pdir = f"{prefix}{tdir.name}" - fname = f"{tdir.name}/test{j}.json" - with open(fname, "w") as fp: - json.dump({"test": i}, fp) - assert os.path.isfile(f"{tdir.name}/test{j}.json") - assert os.path.isfile(f"{pdir}/test{j}.json") - cfg = htbtworker.read_json_file(i, prefix=pdir) - assert cfg["test"] == i + def setUp(self): + htbtworker.configjsonfile = (os.path.dirname(__file__))+"/test-config.json" + @patch('requests.get') + @patch('htbtworker.check_process_reconfiguration', return_value=False) + @patch('htbtworker.get_eventnamelist') + @patch('htbtworker.sql_executor') + def test_process_msg(self, mock1, mock2, mock3, sqlmock1): + """ + Test to verify event processing using mock + TBD - Negative test + """ + + status = True + dmaap_data = [{"event":{"commonEventHeader":{"startEpochMicrosec":1544608845841,"sourceId":"VNFB_SRC5","eventId":"mvfs10","nfcNamingCode":"VNFB","timeZoneOffset":"UTC-05:30","reportingEntityId":"cc305d54-75b4-431b-adb2-eb6b9e541234","eventType":"platform","priority":"Normal","version":"4.0.2","reportingEntityName":"ibcx0001vm002oam001","sequence":1000,"domain":"heartbeat","lastEpochMicrosec":1544608845841,"eventName":"Heartbeat_vFW","vesEventListenerVersion":"7.0.2","sourceName":"SOURCE_NAME2","nfNamingCode":"VNFB"},"heartbeatFields":{"heartbeatInterval":20,"heartbeatFieldsVersion":"3.0"}}}] + + mock_resp = Mock() + mock_resp.configure_mock( + **{ + "text": json.dumps(dmaap_data) + } + ) + mock3.return_value = [("Heartbeat_vDNS", "Heartbeat_vFW")] + mock1.return_value = mock_resp -def test_read_json_file_0(): - run_test(0) + filename = "test-config.json" + htbtworker.process_msg(filename, number_of_iterations=1) + self.assertEqual(status, True) + + def test_parse_event(self): + """ + test_parse_event() opens the file test1.json and returns attributes + """ + filename = (os.path.dirname(__file__))+"/test1.json" + with open(filename,"r") as fp: + data = fp.read() + srcname,lastepo,seqnum,event_name = htbtworker.parse_event(data) + self.assertEqual(srcname, "SOURCE_NAME1") + self.assertEqual(event_name, "Heartbeat_vDNS") -def test_read_json_file_1(): - run_test(1) + filename = (os.path.dirname(__file__))+"/test4.json" + with open(filename,"r") as fp: + data = fp.read() + srcname,lastepo,seqnum,event_name = htbtworker.parse_event(data) + self.assertEqual(srcname, "zalp1bmdns01cmd010") + self.assertEqual(event_name, "Heartbeat_vDNS") -def test_read_json_file_2(): - run_test(2) + @patch('htbtworker.sql_executor') + def test_create_and_check_vnf2_table (self, mock_settings): + """ + Test to verify existence of given table + """ + mock_cursor = Mock() + mock_cursor.configure_mock( + **{ + "fetchone.return_value": [("vnf_table_2")] + } + ) + mock_settings.return_value = mock_cursor + status = htbtworker.check_and_create_vnf2_table () + self.assertEqual(status, True) + + with patch('htbtworker.sql_executor', new=Mock(side_effect=htbtworker.psycopg2.DatabaseError())): + status = htbtworker.check_and_create_vnf2_table () + self.assertEqual(False, status) + + @patch('htbtworker.sql_executor') + def test_new_vnf_entry (self, sql_mock): + """ + Check to verify if new node entry is made for tracking HB + """ + status = True + htbtworker.new_vnf_entry ("Heartbeat_vDNS", "TESTNODE", 1548313727714000, "TESTNODE", 1) + self.assertEqual(status, True) + + @patch('htbtworker.sql_executor') + def test_get_eventnamelist (self, sql_mock): + """ + Test to verify eventname list is returned from vnf_table_1 + TBD - List comparison + """ + eventname_list = [("Heartbeat_vDNS", "Heartbeat_vFW")] + mock_cursor = Mock() + mock_cursor.configure_mock( + **{ + "fetchall.return_value": eventname_list + } + ) + sql_mock.return_value = mock_cursor + return_list = htbtworker.get_eventnamelist () + self.assertIn("Heartbeat_vDNS", return_list) + + @patch('htbtworker.postgres_db_open') + def test_sql_executor (self, db_mock): + """ + Test sql executor wrapper method + """ + htbtworker.sql_executor ("SELECT * FROM information_schema.tables WHERE table_name = %s", "vnf_table_2") + htbtworker.sql_executor ("INSERT into information_schema.tables,") + connection_db = db_mock + with patch('htbtworker.postgres_db_open.commit', new=Mock(side_effect=htbtworker.psycopg2.DatabaseError())): + flag = htbtworker.commit_and_close_db(connection_db) + self.assertEqual(False, flag) + + @patch('psycopg2.connect') + def test_postgres_db_open (self, mock): + """ + Test wrapper for postgres db connection + """ + conn = htbtworker.postgres_db_open() + self.assertIsNotNone(conn) + + @patch('misshtbtd.read_hb_common') + def test_check_process_reconfiguration (self, mock): + """ + Test if DB is in reconfiguration state + """ + mock.return_value = ("1234","RUNNING", "XYZ", 1234) + flag = htbtworker.check_process_reconfiguration("test", "test","x.x.x.x", "1234", "test_db") + self.assertEqual(False, flag) + + @patch('htbtworker.postgres_db_open') + def test_commit_and_close_db (self, db_mock): + """ + Test commit and close db + """ + connection_db = db_mock + flag = htbtworker.commit_and_close_db(connection_db) + self.assertEqual(True, flag) + with patch('htbtworker.postgres_db_open.commit', new=Mock(side_effect=htbtworker.psycopg2.DatabaseError())): + flag = htbtworker.commit_and_close_db(connection_db) + self.assertEqual(False, flag) + + +if __name__ == "__main__": # pragma: no cover + unittest.main() diff --git a/tests/test_misshtbtd.py b/tests/test_misshtbtd.py new file mode 100644 index 0000000..0fc8a24 --- /dev/null +++ b/tests/test_misshtbtd.py @@ -0,0 +1,215 @@ +# ============LICENSE_START======================================================= +# Copyright (c) 2020-2023 AT&T Intellectual Property. All rights reserved. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END========================================================= + +import htbtworker +import misshtbtd +import time +import psycopg2 +import os +import tempfile +import json +import unittest +from unittest.mock import * +from _pytest.outcomes import skip +from pickle import FALSE + +class Test_misshtbtd(unittest.TestCase): + + def setUp(self): + htbtworker.configjsonfile = (os.path.dirname(__file__))+"/test-config.json" + + @patch ('psycopg2.connect') + def test_create_database(self, mock1): + status = True + mock_cursor = MagicMock() + mock_cursor.configure_mock( + **{ + "fetchone.return_value": [("1")] + } + ) + mock1.return_value = mock_cursor + misshtbtd.create_database("vnf_table_1",htbtworker.configjsonfile, "10.0.0.0","1234","testuser","testpwd","heartbeatdb") + self.assertEqual(status, True) + + @patch ('htbtworker.postgres_db_open') + def test_read_hb_common(self, mock1): + + mock_cursor = Mock() + mock_cursor.configure_mock( + **{ + "cursor.return_value.fetchall.return_value": [["1", "AA", "123456789", "RUNNING"]] + } + ) + mock1.return_value = mock_cursor + self.assertEqual(('1', 'RUNNING', 'AA', '123456789'), misshtbtd.read_hb_common("testuser","testpwd","10.0.0.0","1234","heartbeatdb")) + + @patch ('misshtbtd.db_table_creation_check') + @patch ('htbtworker.postgres_db_open') + def test_create_update_hb_common(self, mock1, mock2): + ''' + TODO: argument ordering TBD + ''' + mock_cursor = Mock() + mock1.return_value = mock_cursor + mock2.return_value = True + status = True + misshtbtd.create_update_hb_common (0,111, "RUNNING", "testuser","testpwd","10.0.0.0","1234","testdb") + self.assertEqual(status, True) + mock2.return_value = False + misshtbtd.create_update_hb_common (1,111, "RUNNING", "testuser","testpwd","10.0.0.0","1234","testdb") + self.assertEqual(status, True) + + def test_db_table_creation_check (self): + """ + Test to verify existence of given table + """ + mock_cursor = Mock() + mock_cursor.configure_mock( + **{ + "cursor.return_value.fetchone.return_value": ("vnf_table_2") + } + ) + status = misshtbtd.db_table_creation_check (mock_cursor,"vnf_table_2") + self.assertEqual(status, True) + + @patch ('misshtbtd.db_table_creation_check') + def test_create_update_vnf_table_1 (self, mock1): + """ + TBD + """ + status = True + mock_cursor = Mock() + mock_cursor.configure_mock( + **{ + "cursor.return_value.fetchall.return_value": [["Heartbeat_vDNS"],["Heartbeat_vFW"]] + } + ) + misshtbtd.create_update_vnf_table_1 (htbtworker.configjsonfile,1, mock_cursor) + self.assertEqual(status, True) + misshtbtd.create_update_vnf_table_1 (htbtworker.configjsonfile,0, mock_cursor) + self.assertEqual(status, True) + + def test_read_hb_properties_default_from_file (self): + """ + TBD + """ + return_val = ("10.0.0.0","1234", "postgres-test", "postgres-test", "postgres", "True", "300") + misshtbtd.hb_properties_file = (os.path.dirname(__file__)) + "/hbproperties-test.yaml" + (ip_address, port_num, user_name, password, db_name, cbs_polling_required, cbs_polling_interval) = misshtbtd.read_hb_properties_default() + self.assertEqual (return_val,(ip_address, port_num, user_name, password, db_name, cbs_polling_required, cbs_polling_interval) ) + + @patch.dict(os.environ, {"pg_ipAddress": "10.0.0.10", "pg_portNum":"1234", "pg_userName": "test","pg_passwd":"test"}) + def test_read_hb_properties_default_from_env (self): + """ + TBD + """ + return_val = ("10.0.0.10","1234", "test", "test", "postgres", "True", "300") + misshtbtd.hb_properties_file = (os.path.dirname(__file__)) + "/hbproperties-test.yaml" + (ip_address, port_num, user_name, password, db_name, cbs_polling_required, cbs_polling_interval) = misshtbtd.read_hb_properties_default() + self.assertEqual (return_val,(ip_address, port_num, user_name, password, db_name, cbs_polling_required, cbs_polling_interval) ) + + def test_read_hb_properties_from_file (self): + """ + TBD + """ + htbtworker.configjsonfile = (os.path.dirname(__file__))+"/test-config.json" + misshtbtd.hb_properties_file = (os.path.dirname(__file__)) + "/hbproperties-test.yaml" + + return_val = ("10.0.4.1","5432", "postgres", "postgres", "postgres", "True", "300") + (ip_address, port_num, user_name, password, db_name, cbs_polling_required, cbs_polling_interval) = misshtbtd.read_hb_properties(htbtworker.configjsonfile) + self.assertEqual (return_val,(ip_address, port_num, user_name, password, db_name, cbs_polling_required, cbs_polling_interval) ) + + @patch.dict(os.environ, {"pg_ipAddress": "10.0.0.10", "pg_portNum":"1234", "pg_userName": "test","pg_passwd":"test"}) + def test_read_hb_properties_exception_handling (self): + """ + TBD + """ + htbtworker.configjsonfile = (os.path.dirname(__file__))+"/aa-config.json" + misshtbtd.hb_properties_file = (os.path.dirname(__file__)) + "/hbproperties-test.yaml" + + return_val = ("10.0.0.10","1234", "test", "test", "postgres", "True", "300") + (ip_address, port_num, user_name, password, db_name, cbs_polling_required, cbs_polling_interval) = misshtbtd.read_hb_properties(htbtworker.configjsonfile) + self.assertEqual (return_val,(ip_address, port_num, user_name, password, db_name, cbs_polling_required, cbs_polling_interval) ) + + + @patch ('mod.htbt_get_cbs_config') + def test_fetch_json_file (self, mock1): + """ + TBD + """ + #mock.return_value.is_file.return_value = True + mock1.return_value = True + misshtbtd.CONFIG_PATH = "test-config.json" + filename = misshtbtd.fetch_json_file() + self.assertEqual (misshtbtd.CONFIG_PATH, filename) + # mock1.return_value = False + # filename = misshtbtd.fetch_json_file() + # self.assertEqual ("./etc/config.json", filename) + + @patch ('htbtworker.postgres_db_open') + @patch ('misshtbtd.db_table_creation_check') + @patch ('misshtbtd.create_update_vnf_table_1') + def test_create_update_db(self, mock1, mock2, mock3): + ''' + TODO: argument ordering TBD + ''' + mock_cursor = Mock() + mock3.return_value = mock_cursor + mock1.return_value = True + mock2.return_value = True + status = True + misshtbtd.create_update_db (0,htbtworker.configjsonfile, "10.0.0.0", "1234", "test","test", "testdb") + self.assertEqual(status, True) + mock1.return_value = False + misshtbtd.create_update_db (0,htbtworker.configjsonfile, "10.0.0.0", "1234", "test","test", "testdb") + self.assertEqual(status, True) + + @patch ('multiprocessing.Process') + @patch ('misshtbtd.create_update_db') + @patch('misshtbtd.create_update_hb_common') + def test_create_process(self, mock1, mock2, mock3): + job_list = [] + mock_process = Mock() + mock_process.configure_mock( + **{ + "start.return_value": "1" + } + ) + mock1.return_value = mock_process + job_list = misshtbtd.create_process ([],htbtworker.configjsonfile, 1) + self.assertTrue(job_list) + + @patch ('multiprocessing.Process') + @patch ('misshtbtd.read_hb_common') + @patch ('misshtbtd.create_update_db') + @patch ('misshtbtd.create_update_hb_common') + def test_main(self, mock1, mock2, mock3, mock4): + status = True + mock_process = Mock() + mock_process.configure_mock( + **{ + "start.return_value": "1", + "pid.return_Value":"1111" + } + ) + mock1.return_value = mock_process + current_time = round(time.time()) + mock2.return_value = ('1', 'RUNNING', 'AA', current_time) + misshtbtd.main() + self.assertEqual(status, True) + +if __name__ == "__main__": # pragma: no cover + unittest.main() @@ -1,6 +1,7 @@ # content of: tox.ini , put in same dir as setup.py [tox] -envlist = py38,py39 +envlist = py36,py38,py39 +skip_missing_interpreters = true [testenv] deps= diff --git a/version.properties b/version.properties index 6c69733..8201005 100644 --- a/version.properties +++ b/version.properties @@ -1,5 +1,5 @@ major=2 -minor=5 +minor=6 patch=0 base_version=${major}.${minor}.${patch} release_version=${base_version} |