kunit: tool: Parse and print the reason tests are skipped

When a KUnit test (or other KTAP test) is skipped, a "skip reason" can be
provided. kunit.py has never done anything with this, ignoring anything
included in the KTAP output after the 'SKIP' directive.

Since we have it, and it's used, print it in a nice friendly yellow in
parentheses after a skipped test's name.

(And, by parsing it, it can be included in the JUnit results as well.)

Link: https://lore.kernel.org/r/20260606013827.240790-1-david@davidgow.net
Signed-off-by: David Gow <david@davidgow.net>
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
This commit is contained in:
David Gow 2026-06-06 09:38:17 +08:00 committed by Shuah Khan
parent 5c1553dd5d
commit bfd73e009d
2 changed files with 27 additions and 5 deletions

View File

@ -44,11 +44,12 @@ class Test:
self.subtests = [] # type: List[Test]
self.log = [] # type: List[str]
self.counts = TestCounts()
self.skip_reason = ''
def __str__(self) -> str:
"""Returns string representation of a Test class object."""
return (f'Test({self.status}, {self.name}, {self.expected_count}, '
f'{self.subtests}, {self.log}, {self.counts})')
f'{self.subtests}, {self.log}, {self.counts}, {self.skip_reason})')
def __repr__(self) -> str:
"""Returns string representation of a Test class object."""
@ -352,9 +353,9 @@ def parse_test_plan(lines: LineStream, test: Test) -> bool:
lines.pop()
return True
TEST_RESULT = re.compile(r'^\s*(ok|not ok) ([0-9]+) ?(- )?([^#]*)( # .*)?$')
TEST_RESULT = re.compile(r'^\s*(ok|not ok) ([0-9]+) ?(:?- )?([^#]*)( # .*)?$')
TEST_RESULT_SKIP = re.compile(r'^\s*(ok|not ok) ([0-9]+) ?(- )?(.*) # SKIP ?(.*)$')
TEST_RESULT_SKIP = re.compile(r'^\s*(ok|not ok) ([0-9]+) ?(:?- )?(.*) # SKIP ?(.*)$')
def peek_test_name_match(lines: LineStream, test: Test) -> bool:
"""
@ -418,7 +419,7 @@ def parse_test_result(lines: LineStream, test: Test,
# Set name of test object
if skip_match:
test.name = skip_match.group(4) or skip_match.group(5)
test.name = skip_match.group(4)
else:
test.name = match.group(4)
@ -431,6 +432,7 @@ def parse_test_result(lines: LineStream, test: Test,
status = match.group(1)
if skip_match:
test.status = TestStatus.SKIPPED
test.skip_reason = skip_match.group(5) or ''
elif status == 'ok':
test.status = TestStatus.SUCCESS
else:
@ -539,7 +541,10 @@ def format_test_result(test: Test, printer: Printer) -> str:
if test.status == TestStatus.SUCCESS:
return printer.green('[PASSED] ') + test.name
if test.status == TestStatus.SKIPPED:
return printer.yellow('[SKIPPED] ') + test.name
skip_message = printer.yellow('[SKIPPED] ') + test.name
if test.skip_reason != '':
skip_message += printer.yellow(' (' + test.skip_reason + ')')
return skip_message
if test.status == TestStatus.NO_TESTS:
return printer.yellow('[NO TESTS RUN] ') + test.name
if test.status == TestStatus.TEST_CRASHED:

View File

@ -235,10 +235,27 @@ class KUnitParserTest(unittest.TestCase):
with open(skipped_log) as file:
result = kunit_parser.parse_run_tests(file.readlines(), stdout)
# The test result is skipped, and the skip reason is valid
self.assertEqual(kunit_parser.TestStatus.SKIPPED, result.subtests[1].subtests[1].status)
self.assertEqual("this test should be skipped", result.subtests[1].subtests[1].skip_reason)
# A skipped test does not fail the whole suite.
self.assertEqual(kunit_parser.TestStatus.SUCCESS, result.status)
self.assertEqual(result.counts, kunit_parser.TestCounts(passed=4, skipped=1))
def test_skipped_reason_parse(self):
skipped_log = _test_data_path('test_skip_all_tests.log')
with open(skipped_log) as file:
result = kunit_parser.parse_run_tests(file.readlines(), stdout)
# The first test is skipped, with the correct reaons
self.assertEqual(kunit_parser.TestStatus.SKIPPED, result.subtests[0].subtests[0].status)
self.assertEqual("all tests skipped", result.subtests[0].subtests[0].skip_reason)
# The first suite is skipped, with no reason
self.assertEqual(kunit_parser.TestStatus.SKIPPED, result.subtests[0].status)
self.assertEqual("", result.subtests[0].skip_reason)
def test_skipped_all_tests(self):
skipped_log = _test_data_path('test_skip_all_tests.log')
with open(skipped_log) as file: