1# resulttool - report test results in JUnit XML format 2# 3# Copyright (c) 2024, Siemens AG. 4# 5# SPDX-License-Identifier: GPL-2.0-only 6# 7 8import os 9import re 10import xml.etree.ElementTree as ET 11import resulttool.resultutils as resultutils 12 13def junit(args, logger): 14 testresults = resultutils.load_resultsdata(args.json_file, configmap=resultutils.store_map) 15 16 total_time = 0 17 skipped = 0 18 failures = 0 19 errors = 0 20 21 for tests in testresults.values(): 22 results = tests[next(reversed(tests))].get("result", {}) 23 24 for result_id, result in results.items(): 25 # filter out ptestresult.rawlogs and ptestresult.sections 26 if re.search(r'\.test_', result_id): 27 total_time += result.get("duration", 0) 28 29 if result['status'] == "FAILED": 30 failures += 1 31 elif result['status'] == "ERROR": 32 errors += 1 33 elif result['status'] == "SKIPPED": 34 skipped += 1 35 36 testsuites_node = ET.Element("testsuites") 37 testsuites_node.set("time", "%s" % total_time) 38 testsuite_node = ET.SubElement(testsuites_node, "testsuite") 39 testsuite_node.set("name", "Testimage") 40 testsuite_node.set("time", "%s" % total_time) 41 testsuite_node.set("tests", "%s" % len(results)) 42 testsuite_node.set("failures", "%s" % failures) 43 testsuite_node.set("errors", "%s" % errors) 44 testsuite_node.set("skipped", "%s" % skipped) 45 46 for result_id, result in results.items(): 47 if re.search(r'\.test_', result_id): 48 testcase_node = ET.SubElement(testsuite_node, "testcase", { 49 "name": result_id, 50 "classname": "Testimage", 51 "time": str(result['duration']) 52 }) 53 if result['status'] == "SKIPPED": 54 ET.SubElement(testcase_node, "skipped", message=result['log']) 55 elif result['status'] == "FAILED": 56 ET.SubElement(testcase_node, "failure", message=result['log']) 57 elif result['status'] == "ERROR": 58 ET.SubElement(testcase_node, "error", message=result['log']) 59 60 tree = ET.ElementTree(testsuites_node) 61 62 if args.junit_xml_path is None: 63 args.junit_xml_path = os.environ['BUILDDIR'] + '/tmp/log/oeqa/junit.xml' 64 tree.write(args.junit_xml_path, encoding='UTF-8', xml_declaration=True) 65 66 logger.info('Saved JUnit XML report as %s' % args.junit_xml_path) 67 68def register_commands(subparsers): 69 """Register subcommands from this plugin""" 70 parser_build = subparsers.add_parser('junit', help='create test report in JUnit XML format', 71 description='generate unit test report in JUnit XML format based on the latest test results in the testresults.json.', 72 group='analysis') 73 parser_build.set_defaults(func=junit) 74 parser_build.add_argument('json_file', 75 help='json file should point to the testresults.json') 76 parser_build.add_argument('-j', '--junit_xml_path', 77 help='junit xml path allows setting the path of the generated test report. The default location is <build_dir>/tmp/log/oeqa/junit.xml') 78