diff mbox series

[v2] resulttool: Add support to create test report in JUnit XML format

Message ID 20240828092027.2827279-1-clara.kowalsky@siemens.com
State Accepted, archived
Commit 3f9be03946243feaa09b908d7010899769091fe6
Headers show
Series [v2] resulttool: Add support to create test report in JUnit XML format | expand

Commit Message

Clara Kowalsky Aug. 28, 2024, 9:20 a.m. UTC
This adds the functionality to convert the results of the
testresults.json file to a unit test report in JUnit XML format. The
unit test report can be used in the CI/CD pipeline to display the test
results.

To use the resulttool scripts, first source oe environment, then run the
entry point script to look for help.
	$ resulttool

To generate the unit test report, execute the below
	$ resulttool junit <json_file>

By default the unit test report is stored as
<build_dir>/tmp/log/oeqa/junit.xml.

Signed-off-by: Clara Kowalsky <clara.kowalsky@siemens.com>
---
 scripts/lib/resulttool/junit.py | 77 +++++++++++++++++++++++++++++++++
 scripts/resulttool              |  5 +++
 2 files changed, 82 insertions(+)
 create mode 100644 scripts/lib/resulttool/junit.py
diff mbox series

Patch

diff --git a/scripts/lib/resulttool/junit.py b/scripts/lib/resulttool/junit.py
new file mode 100644
index 0000000000..c7a53dc550
--- /dev/null
+++ b/scripts/lib/resulttool/junit.py
@@ -0,0 +1,77 @@ 
+# resulttool - report test results in JUnit XML format
+#
+# Copyright (c) 2024, Siemens AG.
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+
+import os
+import re
+import xml.etree.ElementTree as ET
+import resulttool.resultutils as resultutils
+
+def junit(args, logger):
+    testresults = resultutils.load_resultsdata(args.json_file, configmap=resultutils.store_map)
+
+    total_time = 0
+    skipped = 0
+    failures = 0
+    errors = 0
+
+    for tests in testresults.values():
+        results = tests[next(reversed(tests))].get("result", {})
+
+    for result_id, result in results.items():
+        # filter out ptestresult.rawlogs and ptestresult.sections
+        if re.search(r'\.test_', result_id):
+            total_time += result.get("duration", 0)
+
+            if result['status'] == "FAILED":
+                failures += 1
+            elif result['status'] == "ERROR":
+                errors += 1
+            elif result['status'] == "SKIPPED":
+                skipped += 1
+
+    testsuites_node = ET.Element("testsuites")
+    testsuites_node.set("time", "%s" % total_time)
+    testsuite_node = ET.SubElement(testsuites_node, "testsuite")
+    testsuite_node.set("name", "Testimage")
+    testsuite_node.set("time", "%s" % total_time)
+    testsuite_node.set("tests", "%s" % len(results))
+    testsuite_node.set("failures", "%s" % failures)
+    testsuite_node.set("errors", "%s" % errors)
+    testsuite_node.set("skipped", "%s" % skipped)
+
+    for result_id, result in results.items():
+        if re.search(r'\.test_', result_id):
+            testcase_node = ET.SubElement(testsuite_node, "testcase", {
+                "name": result_id,
+                "classname": "Testimage",
+                "time": str(result['duration'])
+            })
+            if result['status'] == "SKIPPED":
+                ET.SubElement(testcase_node, "skipped", message=result['log'])
+            elif result['status'] == "FAILED":
+                ET.SubElement(testcase_node, "failure", message=result['log'])
+            elif result['status'] == "ERROR":
+                ET.SubElement(testcase_node, "error", message=result['log'])
+
+    tree = ET.ElementTree(testsuites_node)
+
+    if args.junit_xml_path is None:
+        args.junit_xml_path = os.environ['BUILDDIR'] + '/tmp/log/oeqa/junit.xml'
+    tree.write(args.junit_xml_path, encoding='UTF-8', xml_declaration=True)
+
+    logger.info('Saved JUnit XML report as %s' % args.junit_xml_path)
+
+def register_commands(subparsers):
+    """Register subcommands from this plugin"""
+    parser_build = subparsers.add_parser('junit', help='create test report in JUnit XML format',
+                                         description='generate unit test report in JUnit XML format based on the latest test results in the testresults.json.',
+                                         group='analysis')
+    parser_build.set_defaults(func=junit)
+    parser_build.add_argument('json_file',
+                              help='json file should point to the testresults.json')
+    parser_build.add_argument('-j', '--junit_xml_path',
+                              help='junit xml path allows setting the path of the generated test report. The default location is <build_dir>/tmp/log/oeqa/junit.xml')
diff --git a/scripts/resulttool b/scripts/resulttool
index fc282bda6c..66a6af9959 100755
--- a/scripts/resulttool
+++ b/scripts/resulttool
@@ -15,6 +15,9 @@ 
 # To report test report, execute the below
 #     $ resulttool report <source_dir>
 #
+# To create a unit test report in JUnit XML format, execute the below
+#     $ resulttool junit <json_file>
+#
 # To perform regression file analysis, execute the below
 #     $ resulttool regression-file <base_result_file> <target_result_file>
 #
@@ -43,6 +46,7 @@  import resulttool.regression
 import resulttool.report
 import resulttool.manualexecution
 import resulttool.log
+import resulttool.junit
 logger = scriptutils.logger_create('resulttool')
 
 def main():
@@ -61,6 +65,7 @@  def main():
     resulttool.regression.register_commands(subparsers)
     resulttool.report.register_commands(subparsers)
     resulttool.log.register_commands(subparsers)
+    resulttool.junit.register_commands(subparsers)
 
     args = parser.parse_args()
     if args.debug: