#!/usr/bin/env python3 ################################################################################### # Test case renderer. # Create a HTML page from a YAML test case file. # # Copyright (C) 2018 # Luis Araujo <luis.araujo@collabora.co.uk> # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 US ################################################################################### import os import yaml from jinja2 import Environment, FileSystemLoader from parser import parse_format from exceptions import ParserTypeError, ParserMissingFieldError TEMPLATE_DIR="." # This command parses each line of a list and returns a structure of the form # (comment, command, output) to apply the following formatting for the respective # sections: # # pre-conditions: # notes: # expected: # - Start line with '$' for commands. # - Start line with '>' for command output. # - Start line with '@' to attach image. # - Start line with '~' to add web link. # - Everything else is a comment. # # run: steps: (only for automated tests) # - Start line with '#' for comments , everything else is a command. # def parse_list(lines, automated_run=False): processed_lines = [] for line in lines: p, c = '', '' sline = line.strip() if not sline: continue if automated_run: if sline[0] == '#': # Remove the '#' with the slice [1:] processed_lines.append((sline[1:], '', '', '', '')) else: # Add the '$ ' in the line for the command processed_lines.append(('', '$ '+sline, '', '', '')) else: if sline[0] == '$': processed_lines.append(('', sline, '', '', '')) elif sline[0] == '>': processed_lines.append(('', '', sline[1:].split('\n'), '', '')) elif sline[0] == '@': processed_lines.append(('', '', '', sline[1:], '')) elif sline[0] == '~': processed_lines.append(('', '', '', '', sline[1:])) else: processed_lines.append((sline, '', '', '', '')) return processed_lines def priority_color(priority): return \ (priority == 'low' and 'secondary') or \ (priority == 'medium' and 'info') or \ (priority == 'high' and 'warning') or \ (priority == 'critical' and 'danger') or 'light' def get_template_values(testcase_data): template_values = {} is_automated = False # Mandatory fields metadata = testcase_data.get('metadata') if not metadata: print("Error: missing mandatory field metadata") exit(1) for mv in ['name', 'image-type', 'image-arch', 'type', 'exec-type', 'priority', 'description', 'expected']: value = metadata.get(mv) if value: if mv == 'exec-type' and value == 'automated': is_automated = True if mv == 'expected': template_values.update({ mv : parse_list(value) }) else: # Set the priority_color. if mv == 'priority': template_values.update({ 'priority_color' : priority_color(value) }) template_values.update({ mv.replace('-', '_') : value }) else: print("Error: missing mandatory field", mv) exit(1) run = testcase_data.get('run') if not run: print("Error: missing mandatory field run") exit(1) else: steps = run.get('steps') if not steps: print("Error: missing mandatory field steps for run") exit(1) # 'is_automated' so automated tests steps are parsed differently. template_values.update({ 'run_steps' : parse_list(steps, automated_run=is_automated) }) # No mandatory fields for nm in ['notes', 'format', 'maintainer', 'resources', 'pre-conditions', 'post-conditions']: value = metadata.get(nm) if value: template_values.update({ nm.replace('-', '_') : parse_list(value) if nm in ['notes', 'pre-conditions', 'post-conditions'] else value }) install = testcase_data.get('install') if install: deps = install.get('deps') if not deps: print("Error: missing mandatory field deps for install") exit(1) template_values.update({ 'install_steps' : deps }) # A install.deps directive will always add a preconditions section # to install the required packages using the macro to install packages. template_values.update({ 'packages_list' : ' '.join(deps) }) # Macros variables ostree_preconditions = metadata.get('macro_ostree_preconditions') if ostree_preconditions: template_values.update({ 'pkgname' : ostree_preconditions }) packages_list = metadata.get('macro_install_packages_preconditions') if packages_list: template_values.update({ 'packages_list' : packages_list }) modules_preconditions = metadata.get('macro_modules_preconditions') if modules_preconditions: template_values.update({ 'libname' : modules_preconditions }) return template_values def generate_test_case(tc_file, directory): try: with open(tc_file) as testcase: tc_data = yaml.safe_load(testcase) except yaml.scanner.ScannerError as e: print("yaml format error:", e) exit(1) # Parse file to detect any syntax error. print("Parsing file", tc_file) try: parse_format(tc_data) except (ParserTypeError, ParserMissingFieldError) as error: print("Error: " + str(error)) exit(1) env = Environment(loader=FileSystemLoader([TEMPLATE_DIR])) # Get template from environment and render it. data = env.get_template('templates/index.html').render(get_template_values(tc_data)) filename = os.path.splitext(os.path.basename(tc_file))[0] + ".html" print("Generating test case page", filename) with open(os.path.join(directory, filename), 'w') as html_file: html_file.write(data)