3 Copyright (c) 2011-2014 ARM Limited
5 Licensed under the Apache License, Version 2.0 (the "License");
6 you may not use this file except in compliance with the License.
7 You may obtain a copy of the License at
9 http://www.apache.org/licenses/LICENSE-2.0
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
17 Author: Przemyslaw Wirkus <Przemyslaw.wirkus@arm.com>
20 from workspace_tools.utils import construct_enum
23 ResultExporterType = construct_enum(HTML='Html_Exporter',
24 JUNIT='JUnit_Exporter')
27 class ReportExporter():
28 """ Class exports extended test result Python data structure to
29 different formats like HTML, JUnit XML.
31 Parameter 'test_result_ext' format:
33 u'uARM': { u'LPC1768': { 'MBED_2': { 0: { 'copy_method': 'shutils.copy()',
35 'elapsed_time': 1.7929999828338623,
36 'single_test_output': 'Host test instrumentation on ...\r\n',
37 'single_test_result': 'OK',
38 'target_name': u'LPC1768',
39 'test_description': 'stdio',
41 'toolchain_name': u'uARM'}},
43 CSS_STYLE = """<style>
51 background-color: #F5DA81;
58 <script type="text/javascript">
59 function show (elem) {
60 elem.style.display = "block";
62 function hide (elem) {
63 elem.style.display = "";
68 def __init__(self, result_exporter_type):
69 self.result_exporter_type = result_exporter_type
71 def report(self, test_summary_ext, test_suite_properties=None):
72 """ Invokes report depending on exporter_type set in constructor
74 if self.result_exporter_type == ResultExporterType.HTML:
76 return self.exporter_html(test_summary_ext, test_suite_properties)
77 elif self.result_exporter_type == ResultExporterType.JUNIT:
79 return self.exporter_junit(test_summary_ext, test_suite_properties)
82 def report_to_file(self, test_summary_ext, file_name, test_suite_properties=None):
83 """ Stores report to specified file
85 report = self.report(test_summary_ext, test_suite_properties=test_suite_properties)
86 if report is not None:
87 with open(file_name, 'w') as f:
90 def get_tooltip_name(self, toolchain, target, test_id, loop_no):
91 """ Generate simple unique tool-tip name which can be used.
92 For example as HTML <div> section id attribute.
94 return "target_test_%s_%s_%s_%d"% (toolchain.lower(), target.lower(), test_id.lower(), loop_no)
96 def get_result_div_sections(self, test, test_no):
97 """ Generates separate <dvi> sections which contains test results output.
100 RESULT_COLORS = {'OK' : 'LimeGreen',
102 'ERROR' : 'LightCoral',}
104 tooltip_name = self.get_tooltip_name(test['toolchain_name'], test['target_name'], test['test_id'], test_no)
105 background_color = RESULT_COLORS[test['single_test_result'] if test['single_test_result'] in RESULT_COLORS else 'ERROR']
106 result_div_style = "background-color: %s"% background_color
108 result = """<div class="name" style="%s" onmouseover="show(%s)" onmouseout="hide(%s)">
110 <div class = "tooltip" id= "%s">
111 <b>%s</b> in <b>%.2f sec</b><br />
118 """% (result_div_style,
121 test['single_test_result'],
123 test['test_description'],
124 test['elapsed_time'],
125 test['single_test_output'].replace('\n', '<br />'))
128 def get_result_tree(self, test_results):
129 """ If test was run in a loop (we got few results from the same test)
130 we will show it in a column to see all results.
131 This function produces HTML table with corresponding results.
134 test_ids = sorted(test_results.keys())
135 for test_no in test_ids:
136 test = test_results[test_no]
138 <td valign="top">%s</td>
139 </tr>"""% self.get_result_div_sections(test, test_no)
143 def get_all_unique_test_ids(self, test_result_ext):
144 """ Gets all unique test ids from all ran tests.
145 We need this to create complete list of all test ran.
148 toolchains = test_result_ext.keys()
149 for toolchain in toolchains:
150 targets = test_result_ext[toolchain].keys()
151 for target in targets:
152 tests = test_result_ext[toolchain][target].keys()
154 return sorted(list(set(result)))
157 # Exporters functions
160 def exporter_html(self, test_result_ext, test_suite_properties=None):
161 """ Export test results in proprietary html format.
165 <title>mbed SDK test suite test result report</title>
170 """% (self.CSS_STYLE, self.JAVASCRIPT)
172 unique_test_ids = self.get_all_unique_test_ids(test_result_ext)
173 toolchains = sorted(test_result_ext.keys())
174 result += '<table><tr>'
175 for toolchain in toolchains:
176 targets = sorted(test_result_ext[toolchain].keys())
177 for target in targets:
178 result += '<td></td>'
179 result += '<td></td>'
181 tests = sorted(test_result_ext[toolchain][target].keys())
182 for test in unique_test_ids:
183 result += """<td align="center">%s</td>"""% test
186 <td valign="center">%s</td>
187 <td valign="center"><b>%s</b></td>
188 """% (toolchain, target)
190 for test in unique_test_ids:
191 test_result = self.get_result_tree(test_result_ext[toolchain][target][test]) if test in tests else ''
192 result += '<td>%s</td>'% (test_result)
196 result += '</body></html>'
199 def exporter_junit(self, test_result_ext, test_suite_properties=None):
200 """ Export test results in JUnit XML compliant format
202 from junit_xml import TestSuite, TestCase
206 toolchains = sorted(test_result_ext.keys())
207 for toolchain in toolchains:
208 targets = sorted(test_result_ext[toolchain].keys())
209 for target in targets:
211 tests = sorted(test_result_ext[toolchain][target].keys())
213 test_results = test_result_ext[toolchain][target][test]
214 test_ids = sorted(test_results.keys())
215 for test_no in test_ids:
216 test_result = test_results[test_no]
217 name = test_result['test_description']
218 classname = 'test.%s.%s.%s'% (target, toolchain, test_result['test_id'])
219 elapsed_sec = test_result['elapsed_time']
220 _stdout = test_result['single_test_output']
223 tc = TestCase(name, classname, elapsed_sec, _stdout, _stderr)
224 # Test case extra failure / error info
225 if test_result['single_test_result'] == 'FAIL':
226 message = test_result['single_test_result']
227 tc.add_failure_info(message, _stdout)
228 elif test_result['single_test_result'] != 'OK':
229 message = test_result['single_test_result']
230 tc.add_error_info(message, _stdout)
232 test_cases.append(tc)
233 ts = TestSuite("test.suite.%s.%s"% (target, toolchain), test_cases, properties=test_suite_properties[target][toolchain])
234 test_suites.append(ts)
235 return TestSuite.to_xml_string(test_suites)