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 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
# Copyright 2021 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Module for outputting results in a human-readable format."""
import tempfile
from typing import Dict, IO, List, Optional, Union
# //testing imports.
from flake_suppressor_common import common_typing as ct
UrlListType = List[str]
StringTagsToUrlsType = Dict[str, UrlListType]
TestToStringTagsType = Dict[str, StringTagsToUrlsType]
StringMapType = Dict[str, TestToStringTagsType]
TestToUrlListType = Dict[str, UrlListType]
SuiteToTestsType = Dict[str, TestToUrlListType]
ConfigGroupedStringMapType = Dict[str, SuiteToTestsType]
NodeType = Union[UrlListType, StringTagsToUrlsType, TestToStringTagsType,
StringMapType, TestToUrlListType, SuiteToTestsType,
ConfigGroupedStringMapType]
def GenerateHtmlOutputFile(aggregated_results: ct.AggregatedResultsType,
outfile: Optional[IO] = None) -> None:
"""Generates an HTML results file.
Args:
aggregated_results: A map containing the aggregated test results.
outfile: A file-like object to output to. Will create one if not provided.
"""
outfile = outfile or tempfile.NamedTemporaryFile(
mode='w', delete=False, suffix='.html')
try:
outfile.write('<html>\n<body>\n')
string_map = _ConvertAggregatedResultsToStringMap(aggregated_results)
_OutputMapToHtmlFile(string_map, 'Grouped By Test', outfile)
config_map = _ConvertFromTestGroupingToConfigGrouping(string_map)
_OutputMapToHtmlFile(config_map, 'Grouped By Config', outfile)
outfile.write('</body>\n</html>\n')
finally:
outfile.close()
print('HTML results: %s' % outfile.name)
def _OutputMapToHtmlFile(string_map: StringMapType, result_header: str,
output_file: IO) -> None:
"""Outputs a map to a file as a nested list.
Args:
string_map: The string map to output.
result_header: A string containing the header contents placed before the
nested list.
output_file: A file-like object to output the map to.
"""
output_file.write('<h1>%s</h1>\n' % result_header)
output_file.write('<ul>\n')
_RecursiveHtmlToFile(string_map, output_file)
output_file.write('</ul>\n')
def _RecursiveHtmlToFile(node: NodeType, output_file: IO) -> None:
"""Recursively outputs a string map to an output file as HTML.
Specifically, contents are output as an unordered list (<ul>).
Args:
node: The current node to output. Must be either a dict or list.
output_file: A file-like object to output the HTML to.
"""
if isinstance(node, dict):
for key, value in node.items():
output_file.write('<li>%s</li>\n' % key)
output_file.write('<ul>\n')
_RecursiveHtmlToFile(value, output_file)
output_file.write('</ul>\n')
elif isinstance(node, list):
for element in node:
output_file.write('<li><a href="%s">%s</a></li>\n' % (element, element))
else:
raise RuntimeError('Unsupported type %s' % type(node).__name__)
def _ConvertAggregatedResultsToStringMap(
aggregated_results: ct.AggregatedResultsType) -> StringMapType:
"""Converts aggregated results to a format usable by _RecursiveHtmlToFile.
Specifically, updates the string representation of the typ tags and replaces
the lowest level dict with the build URL list.
Args:
aggregated_results: A map containing the aggregated test results.
Returns:
A map in the format:
{
'suite': {
'test': {
'space separated typ tags': ['build', 'url', 'list']
}
}
}
"""
string_map = {}
for suite, test_map in aggregated_results.items():
for test, tag_map in test_map.items():
for typ_tags, build_url_list in tag_map.items():
str_typ_tags = ' '.join(typ_tags)
string_map.setdefault(suite,
{}).setdefault(test,
{})[str_typ_tags] = build_url_list
return string_map
def _ConvertFromTestGroupingToConfigGrouping(string_map: StringMapType
) -> ConfigGroupedStringMapType:
"""Converts |string| map to be grouped by typ tags/configuration.
Args:
string_map: The output of _ConvertAggregatedResultsToStringMap.
Returns:
A map in the format:
{
'space separated typ tags': {
'suite': {
'test': ['build', 'url', 'list']
}
}
}
"""
converted_map = {}
for suite, test_map in string_map.items():
for test, tag_map in test_map.items():
for typ_tags, build_urls in tag_map.items():
converted_map.setdefault(typ_tags, {}).setdefault(suite,
{})[test] = build_urls
return converted_map
|