diff options
-rw-r--r-- | requirements.txt | 1 | ||||
-rw-r--r-- | run_basicvm_nomulticloud.py | 1 | ||||
-rw-r--r-- | src/onaptests/configuration/settings.py | 1 | ||||
-rw-r--r-- | src/onaptests/configuration/ubuntu16_multicloud_yaml_settings.py | 3 | ||||
-rw-r--r-- | src/onaptests/configuration/ubuntu16_nomulticloud_settings.py | 2 | ||||
-rw-r--r-- | src/onaptests/scenario/basic_vm.py | 4 | ||||
-rw-r--r-- | src/onaptests/steps/reports_collection.py | 35 | ||||
-rw-r--r-- | src/onaptests/templates/reporting/base.html.j2 | 231 | ||||
-rw-r--r-- | src/onaptests/templates/reporting/reporting.html.j2 | 43 |
9 files changed, 316 insertions, 5 deletions
diff --git a/requirements.txt b/requirements.txt index 7ed56d2..a2e82b3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ xtesting openstacksdk onapsdk>=7.0.0 +jinja2 diff --git a/run_basicvm_nomulticloud.py b/run_basicvm_nomulticloud.py index e6be410..9ebefb8 100644 --- a/run_basicvm_nomulticloud.py +++ b/run_basicvm_nomulticloud.py @@ -20,3 +20,4 @@ if __name__ == "__main__": basic_vm_instantiate.cleanup() except ValueError as error: logger.info("service instance deleted as expected {0}".format(error)) + basic_vm_instantiate.reports_collection.generate_report() diff --git a/src/onaptests/configuration/settings.py b/src/onaptests/configuration/settings.py index 7385fa0..3339082 100644 --- a/src/onaptests/configuration/settings.py +++ b/src/onaptests/configuration/settings.py @@ -38,4 +38,5 @@ LOG_CONFIG = { } } +REPORTING_FILE_PATH = "/tmp/reporting.html" # SOCK_HTTP = "socks5h://127.0.0.1:8080" diff --git a/src/onaptests/configuration/ubuntu16_multicloud_yaml_settings.py b/src/onaptests/configuration/ubuntu16_multicloud_yaml_settings.py index abc56e6..5036ed8 100644 --- a/src/onaptests/configuration/ubuntu16_multicloud_yaml_settings.py +++ b/src/onaptests/configuration/ubuntu16_multicloud_yaml_settings.py @@ -2,6 +2,9 @@ import sys from .settings import * # pylint: disable=W0614 """ Specific ubuntu16 with multicloud and yaml config scenario.""" +SERVICE_DETAILS = ("Onboarding, distribution and instantiation of a VM" + + "using à la carte and Multicloud module") +SERVICE_COMPONENTS="SDC, DMAAP, AAI, SO, SDNC, Multicloud" USE_MULTICLOUD = True # Set ONLY_INSTANTIATE to true to run an instantiation without repeating diff --git a/src/onaptests/configuration/ubuntu16_nomulticloud_settings.py b/src/onaptests/configuration/ubuntu16_nomulticloud_settings.py index 6e04992..64c9ce3 100644 --- a/src/onaptests/configuration/ubuntu16_nomulticloud_settings.py +++ b/src/onaptests/configuration/ubuntu16_nomulticloud_settings.py @@ -9,6 +9,8 @@ from .settings import * # pylint: disable=W0614 # pylint: disable=bad-whitespace # The ONAP part +SERVICE_DETAILS="Onboarding, distribution and instanitation of an Ubuntu VM using à la carte" +SERVICE_COMPONENTS="SDC, DMAAP, AAI, SO, SDNC" USE_MULTICLOUD = False # Set ONLY_INSTANTIATE to true to run an instantiation without repeating # onboarding and related AAI configuration (Cloud config) diff --git a/src/onaptests/scenario/basic_vm.py b/src/onaptests/scenario/basic_vm.py index 15a6f5d..48fd169 100644 --- a/src/onaptests/scenario/basic_vm.py +++ b/src/onaptests/scenario/basic_vm.py @@ -42,7 +42,7 @@ class BasicVm(testcase.TestCase): self.__logger.info("No cleanup requested. Test completed.") self.result = 100 - def clean(self): """Clean Additional resources if needed.""" - pass + self.__logger.info("Generate Test report") + self.test.reports_collection.generate_report() diff --git a/src/onaptests/steps/reports_collection.py b/src/onaptests/steps/reports_collection.py index b61b571..62c0447 100644 --- a/src/onaptests/steps/reports_collection.py +++ b/src/onaptests/steps/reports_collection.py @@ -1,5 +1,7 @@ +import sys from typing import Dict - +from jinja2 import Environment, FileSystemLoader, select_autoescape +from onapsdk.configuration import settings class ReportsCollection: """Collection to store steps execution statuses.""" @@ -29,7 +31,34 @@ class ReportsCollection: """ report: Dict[str, str] = {} for element in self._collection[::-1]: - print(element) - print(type(element)) report.update(element) return report + + def generate_report(self) -> None: + step_list = self.report + failing_steps = [] + for step,status in step_list.items(): + if 'FAIL' in status: + failing_steps[step] = status + usecase = settings.SERVICE_NAME + try: + details = settings.SERVICE_DETAILS + except: + details = "" + try: + components = settings.SERVICE_COMPONENTS + except: + components = "" + log_path = settings.LOG_CONFIG['handlers']['file']['filename'] + jinja_env = Environment( + autoescape=select_autoescape(['html']), + loader=FileSystemLoader(sys.path[-1] + '/onaptests/templates/reporting')) + + jinja_env.get_template('reporting.html.j2').stream( + failing_steps=failing_steps, + steps=step_list, + usecase=usecase, + details=details, + components=components, + log_path=log_path).dump( + settings.REPORTING_FILE_PATH) diff --git a/src/onaptests/templates/reporting/base.html.j2 b/src/onaptests/templates/reporting/base.html.j2 new file mode 100644 index 0000000..cbb4e44 --- /dev/null +++ b/src/onaptests/templates/reporting/base.html.j2 @@ -0,0 +1,231 @@ +{% macro color(failing, total) %} +{% if failing == 0 %} +is-success +{% else %} +{% if (failing / total) <= 0.1 %} +is-warning +{% else %} +is-danger +{% endif %} +{% endif %} +{% endmacro %} + +{% macro percentage(failing, total) %} +{{ ((total - failing) / total) | round }} +{% endmacro %} + +{% macro statistic(resource_name, failing, total) %} +{% set success = total - failing %} +<div class="level-item has-text-centered"> + <div> + <p class="heading">{{ resource_name | capitalize }}</p> + <p class="title">{{ success }}/{{ total }}</p> + <progress class="progress {{ color(failing, total) }}" value="{{ success }}" max="{{ total }}">{{ percentage(failing, total) }}</progress> + </div> + </div> +{% endmacro %} + +{% macro pods_table(pods) %} +<div id="pods" class="table-container"> + <table class="table is-fullwidth is-striped is-hoverable"> + <thead> + <tr> + <th>Name</th> + <th>Ready</th> + <th>Status</th> + <th>Reason</th> + <th>Restarts</th> + </tr> + </thead> + <tbody> + {% for pod in pods %} + <tr> + <td><a href="./pod-{{ pod.name }}.html" title="{{ pod.name }}">{{ pod.k8s.metadata.name }}</a></td> + {% if pod.init_done %} + <td>{{ pod.running_containers }}/{{ (pod.containers | length) }}</td> + {% else %} + <td>Init:{{ pod.runned_init_containers }}/{{ (pod.init_containers | length) }}</td> + {% endif %} + <td>{{ pod.k8s.status.phase }}</td> + <td>{{ pod.k8s.status.reason }}</td> + {% if pod.init_done %} + <td>{{ pod.restart_count }}</td> + {% else %} + <td>{{ pod.init_restart_count }}</td> + {% endif %} + </tr> + {% endfor %} + </tbody> + </table> +</div> +{% endmacro %} + +{% macro key_value_description_list(title, dict) %} +<dt><strong>{{ title | capitalize }}:</strong></dt> +<dd> + {% if dict %} + {% for key, value in dict.items() %} + {% if loop.first %} + <dl> + {% endif %} + <dt>{{ key }}:</dt> + <dd>{{ value }}</dd> + {% if loop.last %} + </dl> + {% endif %} + {% endfor %} + {% endif %} +</dd> +{% endmacro %} + +{% macro description(k8s) %} +<div class="container"> + <h1 class="title is-1">Description</h1> + <div class="content"> + <dl> + {% if k8s.spec.type %} + <dt><strong>Type:</strong></dt> + <dd>{{ k8s.spec.type }}</dd> + {% if (k8s.spec.type | lower) == "clusterip" %} + <dt><strong>Headless:</strong></dt> + <dd>{% if (k8s.spec.cluster_ip | lower) == "none" %}Yes{% else %}No{% endif %}</dd> + {% endif %} + {% endif %} + {{ key_value_description_list('Labels', k8s.metadata.labels) | indent(width=6) }} + {{ key_value_description_list('Annotations', k8s.metadata.annotations) | indent(width=6) }} + {% if k8s.spec.selector %} + {% if k8s.spec.selector.match_labels %} + {{ key_value_description_list('Selector', k8s.spec.selector.match_labels) | indent(width=6) }} + {% else %} + {{ key_value_description_list('Selector', k8s.spec.selector) | indent(width=6) }} + {% endif %} + {% endif %} + {% if k8s.phase %} + <dt><strong>Status:</strong></dt> + <dd>{{ k8s.phase }}</dd> + {% endif %} + {% if k8s.metadata.owner_references %} + <dt><strong>Controlled By:</strong></dt> + <dd>{{ k8s.metadata.owner_references[0].kind }}/{{ k8s.metadata.owner_references[0].name }}</dd> + {% endif %} + </dl> + </div> +</div> +{% endmacro %} + +{% macro pods_container(pods, parent, has_title=True) %} +<div class="container"> + {% if has_title %} + <h1 class="title is-1">Pods</h1> + {% endif %} + {% if (pods | length) > 0 %} + {{ pods_table(pods) | indent(width=2) }} + {% else %} + <div class="notification is-warning">{{ parent }} has no pods!</div> + {% endif %} +</div> +{% endmacro %} + +{% macro two_level_breadcrumb(title, name) %} +<section class="section"> + <div class="container"> + <nav class="breadcrumb" aria-label="breadcrumbs"> + <ul> + <li><a href="./index.html">Summary</a></li> + <li class="is-active"><a href="#" aria-current="page">{{ title | capitalize }} {{ name }}</a></li> + </ul> + </nav> + </div> +</section> +{% endmacro %} + +{% macro pod_parent_summary(title, name, failed_pods, pods) %} +{{ summary(title, name, [{'title': 'Pod', 'failing': failed_pods, 'total': (pods | length)}]) }} +{% endmacro %} + +{% macro number_ok(number, none_value, total=None) %} +{% if number %} +{% if total and number < total %} +<span class="tag is-warning">{{ number }}</span> +{% else %} +{{ number }} +{% endif %} +{% else %} +<span class="tag is-warning">{{ none_value }}</span> +{% endif %} +{% endmacro %} + +{% macro summary(title, name, statistics) %} +<section class="hero is-light"> + <div class="hero-body"> + <div class="container"> + <h1 class="title is-1"> + {{ title | capitalize }} {{ name }} Summary + </h1> + <nav class="level"> + {% for stat in statistics %} + {% if stat.total > 0 %} + {{ statistic(stat.title, stat.failing, stat.total) | indent(width=8) }} + {% endif %} + {% endfor %} + </nav> + </div> + </div> +</section> +{% endmacro %} + +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Tests results - {% block title %}{% endblock %}</title> + <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.0/css/bulma.min.css"> + <script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script> + {% block more_head %}{% endblock %} + </head> + <body> + <nav class="navbar" role="navigation" aria-label="main navigation"> + <div class="navbar-brand"> + <a class="navbar-item" href="https://www.onap.org"> + <img src="https://www.onap.org/wp-content/uploads/sites/20/2017/02/logo_onap_2017.png" width="234" height="50"> + </a> + + <a role="button" class="navbar-burger burger" aria-label="menu" aria-expanded="false" data-target="navbarBasicExample"> + <span aria-hidden="true"></span> + <span aria-hidden="true"></span> + <span aria-hidden="true"></span> + </a> + </div> + + <div id="navbarBasicExample" class="navbar-menu"> + <div class="navbar-start"> + <a class="navbar-item"> + Summary + </a> + </div> + </div> + </nav> + + {% block content %}{% endblock %} + + <footer class="footer"> + <div class="container"> + <div class="columns"> + <div class="column"> + <p class="has-text-grey-light"> + <a href="https://bulma.io/made-with-bulma/"> + <img src="https://bulma.io/images/made-with-bulma.png" alt="Made with Bulma" width="128" height="24"> + </a> + </div> + <div class="column"> + <a class="has-text-grey" href="https://gitlab.com/Orange-OpenSource/lfn/tools/kubernetes-status" style="border-bottom: 1px solid currentColor;"> + Improve this page on Gitlab + </a> + </p> + </div> + </div> + </div> + </footer> + </body> +</html> diff --git a/src/onaptests/templates/reporting/reporting.html.j2 b/src/onaptests/templates/reporting/reporting.html.j2 new file mode 100644 index 0000000..5dafe3f --- /dev/null +++ b/src/onaptests/templates/reporting/reporting.html.j2 @@ -0,0 +1,43 @@ +{% extends "base.html.j2" %} +{% block title %}Summary{% endblock %} +{% block content %} + {{ summary('Results', "", [ + { 'title': 'Pythonsdk Tests', 'failing': (failing_steps | length), 'total': (steps | length)}, + ]) + }} + + <section class="section"> + <div class="container"> + <h1 class="title is-1"> + {{ usecase }} + </h1> + Description: {{ details }} + <br> + Components: {{ components }} + <br> + <a href="{{ log_path }}"> Logs</a> + <!-- Pythonsdk steps table --> + <div id="helms" class="table-container"> + <table class="table is-fullwidth is-striped is-hoverable"> + <thead> + <tr> + <th>Name</th> + <th>Status</th> + </tr> + </thead> + <tbody> + {% for step,value in steps.items() %} + <tr {% if value == 'FAIL' %} class="has-background-danger" {% else %} class="has-background-success-light" {% endif %}> + <td> + {{ step }} + </td> + <td> + {{ value }} + </td> + </tr> + {% endfor %} + </tbody> + </table> + </div> + </div> +{% endblock %} |