mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 22:07:35 -04:00
This is used by things like Jenkins and other CI systems, which can pretty-print the test output and potentially provide test-level comparisons between runs. The implementation here is pretty basic: it only provides the raw results, split into tests and test suites, and doesn't provide any overall metadata. However, CI systems like Jenkins can ingest it and it is already useful. Link: https://lore.kernel.org/r/20260606013827.240790-2-david@davidgow.net Reviewed-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de> Signed-off-by: David Gow <david@davidgow.net> Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
62 lines
2.2 KiB
Python
62 lines
2.2 KiB
Python
# SPDX-License-Identifier: GPL-2.0
|
|
#
|
|
# Generates JUnit XML files from KUnit test results
|
|
#
|
|
# Copyright (C) 2026, Google LLC and David Gow.
|
|
|
|
from xml.sax.saxutils import quoteattr, XMLGenerator
|
|
import xml.etree.ElementTree as ET
|
|
from kunit_parser import Test, TestStatus
|
|
from typing import Optional
|
|
|
|
# Get a string representing a tes suite (including subtests) in JUnit XML
|
|
def get_test_suite(test: Test, parent: Optional[ET.Element]) -> ET.Element:
|
|
suite_attrs = {
|
|
'name': test.name,
|
|
'tests': str(test.counts.total()),
|
|
'failures': str(test.counts.failed),
|
|
'skipped': str(test.counts.skipped),
|
|
'errors': str(test.counts.crashed + test.counts.errors),
|
|
}
|
|
|
|
if parent is not None:
|
|
test_suite_element = ET.SubElement(parent, 'testsuite', suite_attrs)
|
|
else:
|
|
test_suite_element = ET.Element('testsuite', suite_attrs)
|
|
|
|
for subtest in test.subtests:
|
|
if subtest.subtests:
|
|
get_test_suite(subtest, test_suite_element)
|
|
continue
|
|
test_case_element = ET.SubElement(test_suite_element, 'testcase', {'name': subtest.name})
|
|
if subtest.status == TestStatus.FAILURE:
|
|
ET.SubElement(test_case_element, 'failure', {}).text = 'Test Failed'
|
|
elif subtest.status == TestStatus.SKIPPED:
|
|
ET.SubElement(test_case_element, 'skipped', {}).text = subtest.skip_reason
|
|
elif subtest.status == TestStatus.TEST_CRASHED:
|
|
ET.SubElement(test_case_element, 'error', {}).text = 'Test Crashed'
|
|
|
|
if subtest.log:
|
|
ET.SubElement(test_case_element, 'system-out', {}).text = "\n".join(subtest.log)
|
|
|
|
return test_suite_element
|
|
|
|
# Get a string for an entire XML file for the test structure starting at test
|
|
def get_junit_result(test: Test) -> str:
|
|
root_element = get_test_suite(test, None)
|
|
ET.indent(root_element)
|
|
return ET.tostring(root_element, encoding="unicode", xml_declaration=True)
|
|
|
|
# Print a JUnit result to stdout.
|
|
def print_junit_result(test: Test) -> None:
|
|
root_element = get_test_suite(test, None)
|
|
ET.indent(root_element)
|
|
ET.dump(root_element)
|
|
|
|
# Write an entire XML file for the test structure starting at test
|
|
def write_junit_result(test: Test, filename: str) -> None:
|
|
root_element = get_test_suite(test, None)
|
|
ET.indent(root_element)
|
|
root_et = ET.ElementTree(root_element)
|
|
root_et.write(filename, encoding='utf-8', xml_declaration=True)
|