From e7f8e8ecafdf36537a0b0ab032aeba0baf1f1cd3 Mon Sep 17 00:00:00 2001 From: Carl Mastrangelo Date: Tue, 8 Dec 2015 17:22:44 -0800 Subject: [PATCH] Make pretty interop tets output graphs --- tools/run_tests/interop_html_report.template | 24 ++++++++++- tools/run_tests/report_utils.py | 11 ++++- tools/run_tests/run_interop_tests.py | 42 ++++++++++++++++++-- 3 files changed, 70 insertions(+), 7 deletions(-) diff --git a/tools/run_tests/interop_html_report.template b/tools/run_tests/interop_html_report.template index 1ba2e6cfc22..c01bdf7a778 100644 --- a/tools/run_tests/interop_html_report.template +++ b/tools/run_tests/interop_html_report.template @@ -40,6 +40,26 @@ % endif +<%def name="fill_one_http2_test_result(shortname, resultset)"> + ## keep this mostly in sync with the template above + % if shortname in resultset: + ## Because interop tests does not have runs_per_test flag, each test is + ## run once. So there should only be one element for each result. + <% result = resultset[shortname][0] %> + +
+ ${int(result.http2results['percent'] * 100)}% +
+
+ + % else: + Not implemented + % endif + + % if num_failures > 1:

${num_failures} tests failed!

% elif num_failures: @@ -95,11 +115,11 @@ shortname = 'cloud_to_cloud:http2:%s_server:%s' % ( server_lang, test_case) %> - ${fill_one_test_result(shortname, resultset)} + ${fill_one_http2_test_result(shortname, resultset)} % endfor % if cloud_to_prod: <% shortname = 'cloud_to_prod:http2:%s' % test_case %> - ${fill_one_test_result(shortname, resultset)} + ${fill_one_http2_test_result(shortname, resultset)} % endif % endfor diff --git a/tools/run_tests/report_utils.py b/tools/run_tests/report_utils.py index 12b1972f1af..35f2069beea 100644 --- a/tools/run_tests/report_utils.py +++ b/tools/run_tests/report_utils.py @@ -32,6 +32,7 @@ try: from mako.runtime import Context from mako.template import Template + from mako import exceptions except (ImportError): pass # Mako not installed but it is ok. import os @@ -103,9 +104,15 @@ def render_interop_html_report( 'num_failures': num_failures, 'cloud_to_prod': cloud_to_prod, 'http2_interop': http2_interop} + html_report_out_dir = 'reports' if not os.path.exists(html_report_out_dir): os.mkdir(html_report_out_dir) html_file_path = os.path.join(html_report_out_dir, 'index.html') - with open(html_file_path, 'w') as output_file: - mytemplate.render_context(Context(output_file, **args)) + try: + with open(html_file_path, 'w') as output_file: + mytemplate.render_context(Context(output_file, **args)) + except: + print(exceptions.text_error_template().render()) + raise + diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py index 37b631bd0da..9a925bee4e1 100755 --- a/tools/run_tests/run_interop_tests.py +++ b/tools/run_tests/run_interop_tests.py @@ -31,17 +31,24 @@ """Run interop (cross-language) tests in parallel.""" import argparse +import atexit import dockerjob import itertools import jobset +import json import multiprocessing import os +import re import report_utils +import subprocess import sys import tempfile import time import uuid +# Docker doesn't clean up after itself, so we do it on exit. +atexit.register(lambda: subprocess.call(['stty', 'echo'])) + ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..')) os.chdir(ROOT) @@ -513,6 +520,33 @@ def build_interop_image_jobspec(language, tag=None): return build_job +def aggregate_http2_results(stdout): + match = re.search(r'\{"cases[^\]]*\]\}', stdout) + if not match: + return None + + results = json.loads(match.group(0)) + skipped = 0 + passed = 0 + failed = 0 + failed_cases = [] + for case in results['cases']: + if case.get('skipped', False): + skipped += 1 + else: + if case.get('passed', False): + passed += 1 + else: + failed += 1 + failed_cases.append(case.get('name', "NONAME")) + return { + 'passed': passed, + 'failed': failed, + 'skipped': skipped, + 'failed_cases': ', '.join(failed_cases), + 'percent': 1.0 * passed / (passed + failed) + } + argp = argparse.ArgumentParser(description='Run interop tests.') argp.add_argument('-l', '--language', choices=['all'] + sorted(_LANGUAGES), @@ -639,9 +673,7 @@ try: docker_image=docker_images.get(str(language))) jobs.append(test_job) - # TODO(carl-mastrangelo): Currently prod TLS terminators aren't spec compliant. Reenable - # this once a better solution is in place. - if args.http2_interop and False: + if args.http2_interop: for test_case in _HTTP2_TEST_CASES: test_job = cloud_to_prod_jobspec(http2Interop, test_case, docker_image=docker_images.get(str(http2Interop))) @@ -703,6 +735,10 @@ try: report_utils.render_junit_xml_report(resultset, 'report.xml') + for name, job in resultset.iteritems(): + if "http2" in name: + job[0].http2results = aggregate_http2_results(job[0].message) + report_utils.render_interop_html_report( set([str(l) for l in languages]), servers, _TEST_CASES, _AUTH_TEST_CASES, _HTTP2_TEST_CASES, resultset, num_failures,