From patchwork Fri Apr 29 03:49:23 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lucas Meneghel Rodrigues X-Patchwork-Id: 740191 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p3T3nnlD014873 for ; Fri, 29 Apr 2011 03:49:53 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752561Ab1D2Dtg (ORCPT ); Thu, 28 Apr 2011 23:49:36 -0400 Received: from mx1.redhat.com ([209.132.183.28]:8170 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751175Ab1D2Dtd (ORCPT ); Thu, 28 Apr 2011 23:49:33 -0400 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p3T3nVNu027625 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Thu, 28 Apr 2011 23:49:31 -0400 Received: from freedom.redhat.com (vpn-9-184.rdu.redhat.com [10.11.9.184]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id p3T3nRAh030385; Thu, 28 Apr 2011 23:49:30 -0400 From: Lucas Meneghel Rodrigues To: autotest@test.kernel.org Cc: kvm@vger.kernel.org, Lucas Meneghel Rodrigues Subject: [PATCH 1/4] tools/html_report: Make html report generation autotest generic Date: Fri, 29 Apr 2011 00:49:23 -0300 Message-Id: <1304048966-5870-2-git-send-email-lmr@redhat.com> In-Reply-To: <1304048966-5870-1-git-send-email-lmr@redhat.com> References: <1304048966-5870-1-git-send-email-lmr@redhat.com> X-Scanned-By: MIMEDefang 2.67 on 10.5.11.11 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Fri, 29 Apr 2011 03:49:53 +0000 (UTC) The html report tool was a bit too tied to KVM autotest, and that was not necessary. Turn it into a generic module that can be used by any autotest job, encapsulate the main worker function into autotest API so we don't need to exec it in a subshell, fix naming of the report and CSS details. Signed-off-by: Lucas Meneghel Rodrigues --- client/tools/html_report.py | 158 ++++++++++++++++++++++++++++--------------- 1 files changed, 104 insertions(+), 54 deletions(-) diff --git a/client/tools/html_report.py b/client/tools/html_report.py index 8b4b109..7b17a75 100755 --- a/client/tools/html_report.py +++ b/client/tools/html_report.py @@ -1,6 +1,6 @@ #!/usr/bin/python """ -Script used to parse the test results and generate an HTML report. +Module used to parse the autotest job results and generate an HTML report. @copyright: (c)2005-2007 Matt Kruse (javascripttoolbox.com) @copyright: Red Hat 2008-2009 @@ -27,7 +27,6 @@ body { text-decoration:none; font:bold 2em/2em Arial, Helvetica, sans-serif; text-transform:none; - text-shadow: 2px 2px 2px #555; text-align: left; color:#555555; border-bottom: 1px solid #555555; @@ -37,7 +36,6 @@ body { text-decoration:none; font:bold 16px Arial, Helvetica, sans-serif; text-transform:uppercase; - text-shadow: 2px 2px 2px #555; text-align: left; color:#555555; margin-bottom:0; @@ -1374,21 +1372,27 @@ function processList(ul) { } """ - -################################################################# -## This script gets kvm autotest results directory path as an ## -## input and create a single html formatted result page. ## -################################################################# - stimelist = [] def make_html_file(metadata, results, tag, host, output_file_name, dirname): + """ + Create HTML file contents for the job report, to stdout or filesystem. + + @param metadata: Dictionary with Job metadata (tests, exec time, etc). + @param results: List with testcase results. + @param tag: Job tag. + @param host: Client hostname. + @param output_file_name: Output file name. If empty string, prints to + stdout. + @param dirname: Prefix for HTML links. If empty string, the HTML links + will be relative to the results dir. + """ html_prefix = """ -KVM Autotest Results +Autotest job execution results @@ -1407,14 +1411,13 @@ return true; """ % (format_css, table_js, maketree_js) - if output_file_name: output = open(output_file_name, "w") else: #if no output file defined, print html file to console output = sys.stdout # create html page print >> output, html_prefix - print >> output, '

KVM Autotest Execution Report

' + print >> output, '

Autotest job execution report

' # formating date and time to print t = datetime.datetime.now() @@ -1438,7 +1441,7 @@ return true; stat_str = ('From %d tests executed, %d have passed (%d%% failures)' % (total_executed, total_passed, failed_perct)) - kvm_ver_str = metadata['kvmver'] + kvm_ver_str = metadata.get('kvmver', None) print >> output, '' print >> output, '' % host @@ -1446,10 +1449,10 @@ return true; print >> output, '' % now.ctime() print >> output, ''% stat_str print >> output, '' - print >> output, '' % kvm_ver_str + if kvm_ver_str is not None: + print >> output, '' % kvm_ver_str print >> output, '
HOST:%s
DATE:%s
STATS:%s
KVM VERSION:%s
KVM VERSION:%s
' - ## print test results print >> output, '
' print >> output, '

Test Results

' @@ -1529,6 +1532,12 @@ id="t1" class="stats table-autosort:4 table-autofilter table-stripeclass:alterna def parse_result(dirname, line): + """ + Parse job status log line. + + @param dirname: Job results dir + @param line: Status log line. + """ parts = line.split() if len(parts) < 4: return None @@ -1556,7 +1565,7 @@ def parse_result(dirname, line): # assign actual values rx = re.compile('^(\w+)\.(.*)$') m1 = rx.findall(parts[3]) - result['testcase'] = m1[0][1] + result['testcase'] = str(tag) result['title'] = str(tag) result['status'] = parts[1] if result['status'] != 'GOOD': @@ -1572,10 +1581,16 @@ def parse_result(dirname, line): def get_exec_log(resdir, tag): - stdout_file = os.path.join(resdir, tag) + '/debug/stdout' - stderr_file = os.path.join(resdir, tag) + '/debug/stderr' - status_file = os.path.join(resdir, tag) + '/status' - dmesg_file = os.path.join(resdir, tag) + '/sysinfo/dmesg' + """ + Get job execution summary. + + @param resdir: Job results dir. + @param tag: Job tag. + """ + stdout_file = os.path.join(resdir, tag, 'debug', 'stdout') + stderr_file = os.path.join(resdir, tag, 'debug', 'stderr') + status_file = os.path.join(resdir, tag, 'status') + dmesg_file = os.path.join(resdir, tag, 'sysinfo', 'dmesg') log = '' log += '
STDERR:
' log += get_info_file(stderr_file) @@ -1589,6 +1604,13 @@ def get_exec_log(resdir, tag): def get_info_file(filename): + """ + Gets the contents of an autotest info file. + + It also and highlights the file contents with possible problems. + + @param filename: Info file path. + """ data = '' errors = re.compile(r"\b(error|fail|failed)\b", re.IGNORECASE) if os.path.isfile(filename): @@ -1610,8 +1632,10 @@ def get_info_file(filename): return data - def usage(): + """ + Print stand alone program usage. + """ print 'usage:', print 'make_html_report.py -r [-f output_file] [-R]' print '(e.g. make_html_reporter.py -r '\ @@ -1626,6 +1650,9 @@ def get_keyval_value(result_dir, key): """ Return the value of the first appearance of key in any keyval file in result_dir. If no appropriate line is found, return 'Unknown'. + + @param result_dir: Path that holds the keyval files. + @param key: Specific key we're retrieving. """ keyval_pattern = os.path.join(result_dir, "kvm.*", "keyval") keyval_lines = commands.getoutput(r"grep -h '\b%s\b.*=' %s" @@ -1643,15 +1670,69 @@ def get_kvm_version(result_dir): """ Return an HTML string describing the KVM version. - @param result_dir: An Autotest job result dir + @param result_dir: An Autotest job result dir. """ kvm_version = get_keyval_value(result_dir, "kvm_version") kvm_userspace_version = get_keyval_value(result_dir, "kvm_userspace_version") + if kvm_version == "Unknown" or kvm_userspace_version == "Unknown": + return None return "Kernel: %s
Userspace: %s" % (kvm_version, kvm_userspace_version) +def create_report(dirname, html_path='', output_file_name=None): + """ + Create an HTML report with info about an autotest client job. + + If no relative path (html_path) or output file name provided, an HTML + file in the toplevel job results dir called 'job_report.html' will be + created, with relative links. + + @param html_path: Prefix for the HTML links. Useful to specify absolute + in the report (not wanted most of the time). + @param output_file_name: Path to the report file. + """ + res_dir = os.path.abspath(dirname) + tag = res_dir + status_file_name = os.path.join(dirname, 'status') + sysinfo_dir = os.path.join(dirname, 'sysinfo') + host = get_info_file(os.path.join(sysinfo_dir, 'hostname')) + rx = re.compile('^\s+[END|START].*$') + # create the results set dict + results_data = [] + if os.path.exists(status_file_name): + f = open(status_file_name, "r") + lines = f.readlines() + f.close() + for line in lines: + if rx.match(line): + result_dict = parse_result(dirname, line) + if result_dict: + results_data.append(result_dict) + # create the meta info dict + metalist = { + 'uname': get_info_file(os.path.join(sysinfo_dir, 'uname')), + 'cpuinfo':get_info_file(os.path.join(sysinfo_dir, 'cpuinfo')), + 'meminfo':get_info_file(os.path.join(sysinfo_dir, 'meminfo')), + 'df':get_info_file(os.path.join(sysinfo_dir, 'df')), + 'modules':get_info_file(os.path.join(sysinfo_dir, 'modules')), + 'gcc':get_info_file(os.path.join(sysinfo_dir, 'gcc_--version')), + 'dmidecode':get_info_file(os.path.join(sysinfo_dir, 'dmidecode')), + 'dmesg':get_info_file(os.path.join(sysinfo_dir, 'dmesg')), + } + if get_kvm_version(dirname) is not None: + metalist['kvm_ver'] = get_kvm_version(dirname) + + if output_file_name is None: + output_file_name = os.path.join(dirname, 'job_report.html') + make_html_file(metalist, results_data, tag, host, output_file_name, + html_path) + + def main(argv): + """ + Parses the arguments and executes the stand alone program. + """ dirname = None output_file_name = None relative_path = False @@ -1682,38 +1763,7 @@ def main(argv): if dirname: if os.path.isdir(dirname): # TBD: replace it with a validation of # autotest result dir - res_dir = os.path.abspath(dirname) - tag = res_dir - status_file_name = dirname + '/status' - sysinfo_dir = dirname + '/sysinfo' - host = get_info_file('%s/hostname' % sysinfo_dir) - rx = re.compile('^\s+[END|START].*$') - # create the results set dict - results_data = [] - if os.path.exists(status_file_name): - f = open(status_file_name, "r") - lines = f.readlines() - f.close() - for line in lines: - if rx.match(line): - result_dict = parse_result(dirname, line) - if result_dict: - results_data.append(result_dict) - # create the meta info dict - metalist = { - 'uname': get_info_file('%s/uname' % sysinfo_dir), - 'cpuinfo':get_info_file('%s/cpuinfo' % sysinfo_dir), - 'meminfo':get_info_file('%s/meminfo' % sysinfo_dir), - 'df':get_info_file('%s/df' % sysinfo_dir), - 'modules':get_info_file('%s/modules' % sysinfo_dir), - 'gcc':get_info_file('%s/gcc_--version' % sysinfo_dir), - 'dmidecode':get_info_file('%s/dmidecode' % sysinfo_dir), - 'dmesg':get_info_file('%s/dmesg' % sysinfo_dir), - 'kvmver':get_kvm_version(dirname) - } - - make_html_file(metalist, results_data, tag, host, output_file_name, - html_path) + create_report(dirname, html_path, output_file_name) sys.exit(0) else: print 'Invalid result directory <%s>' % dirname