Skip to content
Snippets Groups Projects
Commit f2cf0328 authored by Nikolay Stanchev's avatar Nikolay Stanchev
Browse files

Implements tests for alerts API

parent 2569f8ae
No related branches found
No related tags found
No related merge requests found
......@@ -26,12 +26,13 @@
# Python standard libs
from os import listdir
from os.path import isfile, join
from urllib.parse import urlparse
# PIP installed libs
import pytest
from yaml import load
from pyramid import testing
from requests import get, delete
from toscaparser.tosca_template import ToscaTemplate
# CLMC-service imports
......@@ -129,27 +130,67 @@ class TestAlertsConfigurationAPI(object):
"""
Tests the POST API endpoint of the alerts configuration API responsible for receiving alerts specifications.
Unit test consists of:
* Traverse all valid TOSCA Alerts Specifications in the src/service/clmcservice/resources/tosca/test-data/clmc-validator/valid
Test steps are:
* Traverse all valid TOSCA Alerts Specifications in the
src/service/clmcservice/resources/tosca/test-data/clmc-validator/valid and src/service/clmcservice/resources/tosca/test-data/tosca-parser/valid
* Sending a valid TOSCA Alert Specification to the view responsible for configuring Kapacitor
* Check that Kapacitor alerts, topics and handlers are created with the correct identifier and arguments
:param app_config: fixture for setUp/tearDown of the web service registry
"""
test_data_path = join(ROOT_DIR, *["resources", "tosca", "test-data", "clmc-validator", "valid"])
for test_folder in ("clmc-validator", "tosca-parser"):
test_data_path = join(ROOT_DIR, *["resources", "tosca", "test-data", test_folder, "valid"])
for test_file_path in listdir(test_data_path):
alert_spec_abs_path = join(test_data_path, test_file_path)
if not isfile(alert_spec_abs_path):
continue # skip directories
if not test_file_path.lower().endswith('.yaml'):
continue # non-yaml files are not intended for being tested
print("Testing file {0} in folder {1}".format(test_file_path, test_folder))
request = testing.DummyRequest()
with open(alert_spec_abs_path) as alert_spec:
sfc, sfc_instance, alert_ids, topic_handlers = extract_alert_spec_data(alert_spec)
alert_spec.seek(0)
request.POST['alert-spec'] = FieldStorageMock(test_file_path, alert_spec) # a simple mock class is used to mimic the FieldStorage class
clmc_service_response = AlertsConfigurationAPI(request).post_alerts_specification()
assert (sfc, sfc_instance) == (clmc_service_response["service_function_chain_id"], clmc_service_response["service_function_chain_instance_id"]), \
"Incorrect extraction of metadata for file {0}". format(test_file_path)
for test_file_path in listdir(test_data_path):
# traverse through all alert IDs and check that they are created within Kapacitor
for alert_id in alert_ids:
kapacitor_response = get("http://localhost:9092/kapacitor/v1/tasks/{0}".format(alert_id))
assert kapacitor_response.status_code == 200, "Alert with ID {0} was not created - test file {1}.".format(alert_id, test_file_path)
kapacitor_response_json = kapacitor_response.json()
assert "link" in kapacitor_response_json, "Incorrect response from kapacitor for alert with ID {0} - test file {1}".format(alert_id, test_file_path)
assert kapacitor_response_json["status"] == "enabled", "Alert with ID {0} was created but is disabled - test file {1}".format(alert_id, test_file_path)
request = testing.DummyRequest()
alert_spec_abs_path = join(test_data_path, test_file_path)
print(alert_spec_abs_path)
with open(alert_spec_abs_path) as alert_spec:
request.POST['alert-spec'] = FieldStorageMock(test_file_path, alert_spec) # a simple mock class is used to mimic the FieldStorage class
# check that all topic IDs were registered within Kapacitor
topic_ids = list(topic_handlers.keys())
kapacitor_response = get("http://localhost:9092/kapacitor/v1/alerts/topics")
assert kapacitor_response.status_code == 200, "Kapacitor couldn't return the list of created topics - test file {0}".format(test_file_path)
kapacitor_response_json = kapacitor_response.json()
kapacitor_defined_topics = [topic["id"] for topic in kapacitor_response_json["topics"]]
assert set(topic_ids).issubset(kapacitor_defined_topics), "Not all topic IDs were created within kapacitor - test file {0}".format(test_file_path)
print(AlertsConfigurationAPI(request).post_alerts_specification())
# check that all handler IDs were created and each of them is subscribed to the correct topic ID
for topic_id in topic_handlers:
for handler_id, handler_url in topic_handlers[topic_id]:
kapacitor_response = get("http://localhost:9092/kapacitor/v1/alerts/topics/{0}/handlers/{1}".format(topic_id, handler_id))
assert kapacitor_response.status_code == 200, "Handler with ID {0} for topic with ID {1} doesn't exist - test file {2}".format(handler_id, topic_id, test_file_path)
kapacitor_response_json = kapacitor_response.json()
assert kapacitor_response_json["id"] == handler_id, "Incorrect ID of handler {0} in the Kapacitor response - test file {1}".format(handler_id, test_file_path)
assert kapacitor_response_json["kind"] == "post", "Incorrect kind of handler {0} in the Kapacitor response - test file {1}".format(handler_id, test_file_path)
assert kapacitor_response_json["options"]["url"], "Incorrect url of handler {0} in the Kapacitor response - test file {1}".format(handler_id, test_file_path)
break
clear_kapacitor_alerts(alert_ids, topic_handlers)
class FieldStorageMock(object):
......@@ -164,3 +205,59 @@ class FieldStorageMock(object):
self.filename = filename
self.file = file
def extract_alert_spec_data(alert_spec):
"""
A utility function to extract the expected alert, handler and topic identifiers from a given alert specification.
:param alert_spec: the alert specification file (file object)
:return: a tuple containing sfc_id and sfc_instance_id along with a list and a dictionary of generated IDs (alert IDs (list), topic IDs linked to handler IDs (dict))
"""
yaml_alert_spec = load(alert_spec)
adjust_tosca_definitions_import(yaml_alert_spec)
tosca_tpl = ToscaTemplate(yaml_dict_tpl=yaml_alert_spec)
sfc, sfc_instance = tosca_tpl.tpl["metadata"]["sfc"], tosca_tpl.tpl["metadata"]["sfci"]
alert_ids = [] # saves all alert IDs in a list
topic_handlers = {} # saves all topics in a dictionary, each topic is linked to a list of handler pairs (a handler pair consists of handler id and handler url)
for policy in tosca_tpl.policies:
policy_id = policy.name
for trigger in policy.triggers:
trigger_id = trigger.name
topic_id = "{0}.{1}.{2}".format(sfc, sfc_instance, trigger_id)
topic_handlers[topic_id] = []
alert_id = "{0}.{1}.{2}.{3}".format(sfc, sfc_instance, policy_id, trigger_id)
alert_ids.append(alert_id)
for handler_url in trigger.trigger_tpl["action"]["implementation"]:
handler_host = urlparse(handler_url).hostname
handler_id = "{0}.{1}.{2}".format(policy_id, trigger_id, handler_host)
topic_handlers[topic_id].append((handler_id, handler_url))
return sfc, sfc_instance, alert_ids, topic_handlers
def clear_kapacitor_alerts(alert_ids, topic_handlers):
"""
A utility function to clean up Kapacitor from the configured alerts, topics and handlers.
:param alert_ids: the list of alert IDs to delete
:param topic_handlers: the dictionary of topic and handlers to delete
"""
for alert_id in alert_ids:
kapacitor_response = delete("http://localhost:9092/kapacitor/v1/tasks/{0}".format(alert_id)) # delete alert
assert kapacitor_response.status_code == 204
for topic_id in topic_handlers:
for handler_id, handler_url in topic_handlers[topic_id]:
kapacitor_response = delete("http://localhost:9092/kapacitor/v1/alerts/topics/{0}/handlers/{1}".format(topic_id, handler_id)) # delete handler
assert kapacitor_response.status_code == 204
kapacitor_response = delete("http://localhost:9092/kapacitor/v1/alerts/topics/{0}".format(topic_id)) # delete topic
assert kapacitor_response.status_code == 204
......@@ -24,7 +24,6 @@
# Python standard libs
import logging
from json import dumps
from urllib.parse import urlparse
# PIP installed libs
......@@ -136,7 +135,7 @@ class AlertsConfigurationAPI(object):
}
# send the request and receive a response
response = post(kapacitor_api_tasks_url, data=dumps(kapacitor_http_request_body))
response = post(kapacitor_api_tasks_url, json=kapacitor_http_request_body)
response_content = response.json()
# log the response
log.info(response_content, response.status_code)
......@@ -147,10 +146,10 @@ class AlertsConfigurationAPI(object):
# subscribe all http handlers to the created topic
kapacitor_api_handlers_url = "http://localhost:9092/kapacitor/v1/alerts/topics/{0}/handlers".format(topic_id)
for http_handler_url in http_handlers:
http_handler_host = urlparse(http_handler_url).netloc
http_handler_host = urlparse(http_handler_url).hostname
handler_id = "{0}.{1}.{2}".format(policy.name, event_id, http_handler_host)
kapacitor_http_request_body = fill_http_post_handler_vars(handler_id, http_handler_url)
response = post(kapacitor_api_handlers_url, data=dumps(kapacitor_http_request_body))
response = post(kapacitor_api_handlers_url, json=kapacitor_http_request_body)
response_content = response.json()
log.info(response_content, response.status_code)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment