aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools/run_tests/report_utils.py
blob: 5648a694cd0db4881b093891ec5384c9e4f23316 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
#     * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
#     * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"""Generate XML and HTML test reports."""

from __future__ import print_function

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
import string
import xml.etree.cElementTree as ET


def _filter_msg(msg, output_format):
  """Filters out nonprintable and illegal characters from the message."""
  if output_format in ['XML', 'HTML']:
    # keep whitespaces but remove formfeed and vertical tab characters
    # that make XML report unparseable.
    filtered_msg = filter(
        lambda x: x in string.printable and x != '\f' and x != '\v',
        msg.decode('UTF-8', 'ignore'))
    if output_format == 'HTML':
      filtered_msg = filtered_msg.replace('"', '"')
    return filtered_msg
  else:
    return msg


def render_junit_xml_report(resultset, xml_report):
  """Generate JUnit-like XML report."""
  root = ET.Element('testsuites')
  testsuite = ET.SubElement(root, 'testsuite', id='1', package='grpc', 
                            name='tests')
  for shortname, results in resultset.items():
    for result in results:
      xml_test = ET.SubElement(testsuite, 'testcase', name=shortname) 
      if result.elapsed_time:
        xml_test.set('time', str(result.elapsed_time))
      ET.SubElement(xml_test, 'system-out').text = _filter_msg(result.message,
                                                               'XML')
      if result.state == 'FAILED':
        ET.SubElement(xml_test, 'failure', message='Failure')
      elif result.state == 'TIMEOUT':
        ET.SubElement(xml_test, 'error', message='Timeout')
  tree = ET.ElementTree(root)
  tree.write(xml_report, encoding='UTF-8')


def render_interop_html_report(
  client_langs, server_langs, test_cases, auth_test_cases, http2_cases, 
  resultset, num_failures, cloud_to_prod, prod_servers, http2_interop):
  """Generate HTML report for interop tests."""
  template_file = 'tools/run_tests/interop_html_report.template'
  try:
    mytemplate = Template(filename=template_file, format_exceptions=True)
  except NameError:
    print('Mako template is not installed. Skipping HTML report generation.')
    return
  except IOError as e:
    print('Failed to find the template %s: %s' % (template_file, e))
    return

  sorted_test_cases = sorted(test_cases)
  sorted_auth_test_cases = sorted(auth_test_cases)
  sorted_http2_cases = sorted(http2_cases)
  sorted_client_langs = sorted(client_langs)
  sorted_server_langs = sorted(server_langs)
  sorted_prod_servers = sorted(prod_servers)

  args = {'client_langs': sorted_client_langs, 
          'server_langs': sorted_server_langs,
          'test_cases': sorted_test_cases,
          'auth_test_cases': sorted_auth_test_cases,
          'http2_cases': sorted_http2_cases,
          'resultset': resultset,
          'num_failures': num_failures,
          'cloud_to_prod': cloud_to_prod,
          'prod_servers': sorted_prod_servers,
          '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')
  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