Merge tag 'linux-kselftest-kunit-fixes-5.14-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest
Pull kunit fixes from Shuah Khan:
"Fixes to kunit tool and documentation:
- fix asserts on older python versions
- fixes to misleading error messages when TAP header format is
incorrect or when file is missing
- documentation fix: drop obsolete information about uml_abort
coverage
- remove unnecessary annotations"
* tag 'linux-kselftest-kunit-fixes-5.14-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest:
kunit: tool: Assert the version requirement
kunit: tool: remove unnecessary "annotations" import
Documentation: kunit: drop obsolete note about uml_abort for coverage
kunit: tool: Fix error messages for cases of no tests and wrong TAP header
This commit is contained in:
@@ -86,19 +86,7 @@ Generating code coverage reports under UML
|
|||||||
.. note::
|
.. note::
|
||||||
TODO(brendanhiggins@google.com): There are various issues with UML and
|
TODO(brendanhiggins@google.com): There are various issues with UML and
|
||||||
versions of gcc 7 and up. You're likely to run into missing ``.gcda``
|
versions of gcc 7 and up. You're likely to run into missing ``.gcda``
|
||||||
files or compile errors. We know one `faulty GCC commit
|
files or compile errors.
|
||||||
<https://github.com/gcc-mirror/gcc/commit/8c9434c2f9358b8b8bad2c1990edf10a21645f9d>`_
|
|
||||||
but not how we'd go about getting this fixed. The compile errors still
|
|
||||||
need some investigation.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
TODO(brendanhiggins@google.com): for recent versions of Linux
|
|
||||||
(5.10-5.12, maybe earlier), there's a bug with gcov counters not being
|
|
||||||
flushed in UML. This translates to very low (<1%) reported coverage. This is
|
|
||||||
related to the above issue and can be worked around by replacing the
|
|
||||||
one call to ``uml_abort()`` (it's in ``os_dump_core()``) with a plain
|
|
||||||
``exit()``.
|
|
||||||
|
|
||||||
|
|
||||||
This is different from the "normal" way of getting coverage information that is
|
This is different from the "normal" way of getting coverage information that is
|
||||||
documented in Documentation/dev-tools/gcov.rst.
|
documented in Documentation/dev-tools/gcov.rst.
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import sys
|
|||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
assert sys.version_info >= (3, 7), "Python version is too old"
|
||||||
|
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from enum import Enum, auto
|
from enum import Enum, auto
|
||||||
|
|
||||||
|
|||||||
@@ -6,15 +6,13 @@
|
|||||||
# Author: Felix Guo <felixguoxiuping@gmail.com>
|
# Author: Felix Guo <felixguoxiuping@gmail.com>
|
||||||
# Author: Brendan Higgins <brendanhiggins@google.com>
|
# Author: Brendan Higgins <brendanhiggins@google.com>
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
import importlib.util
|
import importlib.util
|
||||||
import logging
|
import logging
|
||||||
import subprocess
|
import subprocess
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import signal
|
import signal
|
||||||
from typing import Iterator
|
from typing import Iterator, Optional, Tuple
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from contextlib import ExitStack
|
from contextlib import ExitStack
|
||||||
|
|
||||||
@@ -208,7 +206,7 @@ def get_source_tree_ops(arch: str, cross_compile: Optional[str]) -> LinuxSourceT
|
|||||||
raise ConfigError(arch + ' is not a valid arch')
|
raise ConfigError(arch + ' is not a valid arch')
|
||||||
|
|
||||||
def get_source_tree_ops_from_qemu_config(config_path: str,
|
def get_source_tree_ops_from_qemu_config(config_path: str,
|
||||||
cross_compile: Optional[str]) -> tuple[
|
cross_compile: Optional[str]) -> Tuple[
|
||||||
str, LinuxSourceTreeOperations]:
|
str, LinuxSourceTreeOperations]:
|
||||||
# The module name/path has very little to do with where the actual file
|
# The module name/path has very little to do with where the actual file
|
||||||
# exists (I learned this through experimentation and could not find it
|
# exists (I learned this through experimentation and could not find it
|
||||||
|
|||||||
@@ -338,9 +338,11 @@ def bubble_up_suite_errors(test_suites: Iterable[TestSuite]) -> TestStatus:
|
|||||||
def parse_test_result(lines: LineStream) -> TestResult:
|
def parse_test_result(lines: LineStream) -> TestResult:
|
||||||
consume_non_diagnostic(lines)
|
consume_non_diagnostic(lines)
|
||||||
if not lines or not parse_tap_header(lines):
|
if not lines or not parse_tap_header(lines):
|
||||||
return TestResult(TestStatus.NO_TESTS, [], lines)
|
return TestResult(TestStatus.FAILURE_TO_PARSE_TESTS, [], lines)
|
||||||
expected_test_suite_num = parse_test_plan(lines)
|
expected_test_suite_num = parse_test_plan(lines)
|
||||||
if not expected_test_suite_num:
|
if expected_test_suite_num == 0:
|
||||||
|
return TestResult(TestStatus.NO_TESTS, [], lines)
|
||||||
|
elif expected_test_suite_num is None:
|
||||||
return TestResult(TestStatus.FAILURE_TO_PARSE_TESTS, [], lines)
|
return TestResult(TestStatus.FAILURE_TO_PARSE_TESTS, [], lines)
|
||||||
test_suites = []
|
test_suites = []
|
||||||
for i in range(1, expected_test_suite_num + 1):
|
for i in range(1, expected_test_suite_num + 1):
|
||||||
|
|||||||
@@ -157,8 +157,18 @@ class KUnitParserTest(unittest.TestCase):
|
|||||||
kunit_parser.TestStatus.FAILURE,
|
kunit_parser.TestStatus.FAILURE,
|
||||||
result.status)
|
result.status)
|
||||||
|
|
||||||
|
def test_no_header(self):
|
||||||
|
empty_log = test_data_path('test_is_test_passed-no_tests_run_no_header.log')
|
||||||
|
with open(empty_log) as file:
|
||||||
|
result = kunit_parser.parse_run_tests(
|
||||||
|
kunit_parser.extract_tap_lines(file.readlines()))
|
||||||
|
self.assertEqual(0, len(result.suites))
|
||||||
|
self.assertEqual(
|
||||||
|
kunit_parser.TestStatus.FAILURE_TO_PARSE_TESTS,
|
||||||
|
result.status)
|
||||||
|
|
||||||
def test_no_tests(self):
|
def test_no_tests(self):
|
||||||
empty_log = test_data_path('test_is_test_passed-no_tests_run.log')
|
empty_log = test_data_path('test_is_test_passed-no_tests_run_with_header.log')
|
||||||
with open(empty_log) as file:
|
with open(empty_log) as file:
|
||||||
result = kunit_parser.parse_run_tests(
|
result = kunit_parser.parse_run_tests(
|
||||||
kunit_parser.extract_tap_lines(file.readlines()))
|
kunit_parser.extract_tap_lines(file.readlines()))
|
||||||
@@ -173,7 +183,7 @@ class KUnitParserTest(unittest.TestCase):
|
|||||||
with open(crash_log) as file:
|
with open(crash_log) as file:
|
||||||
result = kunit_parser.parse_run_tests(
|
result = kunit_parser.parse_run_tests(
|
||||||
kunit_parser.extract_tap_lines(file.readlines()))
|
kunit_parser.extract_tap_lines(file.readlines()))
|
||||||
print_mock.assert_any_call(StrContains('no tests run!'))
|
print_mock.assert_any_call(StrContains('could not parse test results!'))
|
||||||
print_mock.stop()
|
print_mock.stop()
|
||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
@@ -309,7 +319,7 @@ class KUnitJsonTest(unittest.TestCase):
|
|||||||
result["sub_groups"][1]["test_cases"][0])
|
result["sub_groups"][1]["test_cases"][0])
|
||||||
|
|
||||||
def test_no_tests_json(self):
|
def test_no_tests_json(self):
|
||||||
result = self._json_for('test_is_test_passed-no_tests_run.log')
|
result = self._json_for('test_is_test_passed-no_tests_run_with_header.log')
|
||||||
self.assertEqual(0, len(result['sub_groups']))
|
self.assertEqual(0, len(result['sub_groups']))
|
||||||
|
|
||||||
class StrContains(str):
|
class StrContains(str):
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
TAP version 14
|
||||||
|
1..0
|
||||||
Reference in New Issue
Block a user