aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2022-07-08 14:39:07 -0400
committerTom Rini <trini@konsulko.com>2022-07-08 14:39:07 -0400
commit9ff4ce8abc627b8696c9bd6fd726dd1dbf4b9a5c (patch)
treed28c5d99d4996b080ec0c38f24a0232d611ea847 /tools
parent7bc0be96f79344d7b103dd64c31be0574f7b39e9 (diff)
parente87da5704ffa6fc782d93d137fa30a37a5df3566 (diff)
Merge tag 'dm-pull-28jun22' of https://source.denx.de/u-boot/custodians/u-boot-dm into next
nman external-symbol improvements Driver model memory-usage reporting patman test-reporting improvements Add bloblist design goals
Diffstat (limited to 'tools')
-rw-r--r--tools/binman/elf.py12
-rw-r--r--tools/binman/elf_test.py12
-rw-r--r--tools/binman/ftest.py33
-rwxr-xr-xtools/binman/main.py8
-rw-r--r--tools/binman/test/021_image_pad.dts2
-rw-r--r--tools/binman/test/024_sorted.dts2
-rw-r--r--tools/binman/test/028_pack_4gb_outside.dts2
-rw-r--r--tools/binman/test/029_x86_rom.dts6
-rw-r--r--tools/binman/test/053_symbols.dts2
-rw-r--r--tools/binman/test/149_symbols_tpl.dts4
-rw-r--r--tools/binman/test/155_symbols_tpl_x86.dts4
-rw-r--r--tools/binman/test/187_symbols_sub.dts2
-rw-r--r--tools/binman/test/Makefile2
-rw-r--r--tools/binman/test/generated/autoconf.h3
-rw-r--r--tools/binman/test/u_boot_binman_syms.c6
-rw-r--r--tools/binman/test/u_boot_binman_syms_size.c6
-rwxr-xr-xtools/buildman/main.py8
-rw-r--r--tools/concurrencytest/concurrencytest.py83
-rwxr-xr-xtools/dtoc/main.py9
-rwxr-xr-xtools/dtoc/test_dtoc.py6
-rwxr-xr-xtools/dtoc/test_fdt.py29
-rwxr-xr-xtools/patman/main.py8
-rw-r--r--tools/patman/settings.py7
-rw-r--r--tools/patman/test_util.py150
24 files changed, 274 insertions, 132 deletions
diff --git a/tools/binman/elf.py b/tools/binman/elf.py
index afa05e58fd..6d440ddf21 100644
--- a/tools/binman/elf.py
+++ b/tools/binman/elf.py
@@ -25,6 +25,9 @@ try:
except: # pragma: no cover
ELF_TOOLS = False
+# BSYM in little endian, keep in sync with include/binman_sym.h
+BINMAN_SYM_MAGIC_VALUE = 0x4d595342
+
# Information about an EFL symbol:
# section (str): Name of the section containing this symbol
# address (int): Address of the symbol (its value)
@@ -223,9 +226,12 @@ def LookupAndWriteSymbols(elf_fname, entry, section):
raise ValueError('%s has size %d: only 4 and 8 are supported' %
(msg, sym.size))
- # Look up the symbol in our entry tables.
- value = section.GetImage().LookupImageSymbol(name, sym.weak, msg,
- base.address)
+ if name == '_binman_sym_magic':
+ value = BINMAN_SYM_MAGIC_VALUE
+ else:
+ # Look up the symbol in our entry tables.
+ value = section.GetImage().LookupImageSymbol(name, sym.weak,
+ msg, base.address)
if value is None:
value = -1
pack_string = pack_string.lower()
diff --git a/tools/binman/elf_test.py b/tools/binman/elf_test.py
index 02bc108374..5a51c64cfe 100644
--- a/tools/binman/elf_test.py
+++ b/tools/binman/elf_test.py
@@ -127,7 +127,7 @@ class TestElf(unittest.TestCase):
elf_fname = self.ElfTestFile('u_boot_binman_syms')
with self.assertRaises(ValueError) as e:
elf.LookupAndWriteSymbols(elf_fname, entry, section)
- self.assertIn('entry_path has offset 4 (size 8) but the contents size '
+ self.assertIn('entry_path has offset 8 (size 8) but the contents size '
'is a', str(e.exception))
def testMissingImageStart(self):
@@ -161,18 +161,20 @@ class TestElf(unittest.TestCase):
This should produce -1 values for all thress symbols, taking up the
first 16 bytes of the image.
"""
- entry = FakeEntry(24)
+ entry = FakeEntry(28)
section = FakeSection(sym_value=None)
elf_fname = self.ElfTestFile('u_boot_binman_syms')
elf.LookupAndWriteSymbols(elf_fname, entry, section)
- self.assertEqual(tools.get_bytes(255, 20) + tools.get_bytes(ord('a'), 4),
- entry.data)
+ expected = (struct.pack('<L', elf.BINMAN_SYM_MAGIC_VALUE) +
+ tools.get_bytes(255, 20) +
+ tools.get_bytes(ord('a'), 4))
+ self.assertEqual(expected, entry.data)
def testDebug(self):
"""Check that enabling debug in the elf module produced debug output"""
try:
tout.init(tout.DEBUG)
- entry = FakeEntry(20)
+ entry = FakeEntry(24)
section = FakeSection()
elf_fname = self.ElfTestFile('u_boot_binman_syms')
with test_util.capture_sys_output() as (stdout, stderr):
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index b5cf549703..fa1f421c05 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -43,8 +43,8 @@ from patman import tout
# Contents of test files, corresponding to different entry types
U_BOOT_DATA = b'1234'
U_BOOT_IMG_DATA = b'img'
-U_BOOT_SPL_DATA = b'56780123456789abcdefghi'
-U_BOOT_TPL_DATA = b'tpl9876543210fedcbazyw'
+U_BOOT_SPL_DATA = b'56780123456789abcdefghijklm'
+U_BOOT_TPL_DATA = b'tpl9876543210fedcbazywvuts'
BLOB_DATA = b'89'
ME_DATA = b'0abcd'
VGA_DATA = b'vga'
@@ -1406,8 +1406,9 @@ class TestFunctional(unittest.TestCase):
elf_fname = self.ElfTestFile('u_boot_binman_syms')
syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
+ self.assertEqual(syms['_binman_sym_magic'].address, addr)
self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
- addr)
+ addr + 4)
self._SetupSplElf('u_boot_binman_syms')
data = self._DoReadFileDtb(dts, entry_args=entry_args,
@@ -1415,17 +1416,17 @@ class TestFunctional(unittest.TestCase):
# The image should contain the symbols from u_boot_binman_syms.c
# Note that image_pos is adjusted by the base address of the image,
# which is 0x10 in our test image
- sym_values = struct.pack('<LQLL', 0x00,
- u_boot_offset + len(U_BOOT_DATA),
+ sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE,
+ 0x00, u_boot_offset + len(U_BOOT_DATA),
0x10 + u_boot_offset, 0x04)
- expected = (sym_values + base_data[20:] +
+ expected = (sym_values + base_data[24:] +
tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
- base_data[20:])
+ base_data[24:])
self.assertEqual(expected, data)
def testSymbols(self):
"""Test binman can assign symbols embedded in U-Boot"""
- self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x18)
+ self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
def testSymbolsNoDtb(self):
"""Test binman can assign symbols embedded in U-Boot SPL"""
@@ -3610,20 +3611,20 @@ class TestFunctional(unittest.TestCase):
def _CheckSymbolsTplSection(self, dts, expected_vals):
data = self._DoReadFile(dts)
- sym_values = struct.pack('<LQLL', *expected_vals)
+ sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
upto1 = 4 + len(U_BOOT_SPL_DATA)
- expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
+ expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
self.assertEqual(expected1, data[:upto1])
upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
- expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
+ expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
self.assertEqual(expected2, data[upto1:upto2])
- upto3 = 0x34 + len(U_BOOT_DATA)
+ upto3 = 0x3c + len(U_BOOT_DATA)
expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
self.assertEqual(expected3, data[upto2:upto3])
- expected4 = sym_values + U_BOOT_TPL_DATA[20:]
+ expected4 = sym_values + U_BOOT_TPL_DATA[24:]
self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
def testSymbolsTplSection(self):
@@ -3631,14 +3632,14 @@ class TestFunctional(unittest.TestCase):
self._SetupSplElf('u_boot_binman_syms')
self._SetupTplElf('u_boot_binman_syms')
self._CheckSymbolsTplSection('149_symbols_tpl.dts',
- [0x04, 0x1c, 0x10 + 0x34, 0x04])
+ [0x04, 0x20, 0x10 + 0x3c, 0x04])
def testSymbolsTplSectionX86(self):
"""Test binman can assign symbols in a section with end-at-4gb"""
self._SetupSplElf('u_boot_binman_syms_x86')
self._SetupTplElf('u_boot_binman_syms_x86')
self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
- [0xffffff04, 0xffffff1c, 0xffffff34,
+ [0xffffff04, 0xffffff20, 0xffffff3c,
0x04])
def testPackX86RomIfwiSectiom(self):
@@ -4488,7 +4489,7 @@ class TestFunctional(unittest.TestCase):
def testSymbolsSubsection(self):
"""Test binman can assign symbols from a subsection"""
- self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x18)
+ self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
def testReadImageEntryArg(self):
"""Test reading an image that would need an entry arg to generate"""
diff --git a/tools/binman/main.py b/tools/binman/main.py
index 5fb9404ef6..14432a8d0d 100755
--- a/tools/binman/main.py
+++ b/tools/binman/main.py
@@ -13,7 +13,6 @@ import os
import site
import sys
import traceback
-import unittest
# Get the absolute path to this file at run-time
our_path = os.path.dirname(os.path.realpath(__file__))
@@ -73,19 +72,18 @@ def RunTests(debug, verbosity, processes, test_preserve_dirs, args, toolpath):
from binman import image_test
import doctest
- result = unittest.TestResult()
test_name = args and args[0] or None
# Run the entry tests first ,since these need to be the first to import the
# 'entry' module.
- test_util.run_test_suites(
- result, debug, verbosity, test_preserve_dirs, processes, test_name,
+ result = test_util.run_test_suites(
+ 'binman', debug, verbosity, test_preserve_dirs, processes, test_name,
toolpath,
[bintool_test.TestBintool, entry_test.TestEntry, ftest.TestFunctional,
fdt_test.TestFdt, elf_test.TestElf, image_test.TestImage,
cbfs_util_test.TestCbfs, fip_util_test.TestFip])
- return test_util.report_result('binman', test_name, result)
+ return (0 if result.wasSuccessful() else 1)
def RunTestCoverage(toolpath):
"""Run the tests and check that we get 100% coverage"""
diff --git a/tools/binman/test/021_image_pad.dts b/tools/binman/test/021_image_pad.dts
index 1ff8dab296..c5abbbcdd6 100644
--- a/tools/binman/test/021_image_pad.dts
+++ b/tools/binman/test/021_image_pad.dts
@@ -10,7 +10,7 @@
};
u-boot {
- offset = <24>;
+ offset = <28>;
};
};
};
diff --git a/tools/binman/test/024_sorted.dts b/tools/binman/test/024_sorted.dts
index b79d9adf68..b54f9b1419 100644
--- a/tools/binman/test/024_sorted.dts
+++ b/tools/binman/test/024_sorted.dts
@@ -7,7 +7,7 @@
binman {
sort-by-offset;
u-boot {
- offset = <26>;
+ offset = <30>;
};
u-boot-spl {
diff --git a/tools/binman/test/028_pack_4gb_outside.dts b/tools/binman/test/028_pack_4gb_outside.dts
index 11a1f6059e..b6ad7fb56a 100644
--- a/tools/binman/test/028_pack_4gb_outside.dts
+++ b/tools/binman/test/028_pack_4gb_outside.dts
@@ -13,7 +13,7 @@
};
u-boot-spl {
- offset = <0xffffffe7>;
+ offset = <0xffffffe3>;
};
};
};
diff --git a/tools/binman/test/029_x86_rom.dts b/tools/binman/test/029_x86_rom.dts
index 88aa007bba..ad8f9d6e1b 100644
--- a/tools/binman/test/029_x86_rom.dts
+++ b/tools/binman/test/029_x86_rom.dts
@@ -7,13 +7,13 @@
binman {
sort-by-offset;
end-at-4gb;
- size = <32>;
+ size = <36>;
u-boot {
- offset = <0xffffffe0>;
+ offset = <0xffffffdc>;
};
u-boot-spl {
- offset = <0xffffffe7>;
+ offset = <0xffffffe3>;
};
};
};
diff --git a/tools/binman/test/053_symbols.dts b/tools/binman/test/053_symbols.dts
index 2965809276..b28f34a72f 100644
--- a/tools/binman/test/053_symbols.dts
+++ b/tools/binman/test/053_symbols.dts
@@ -10,7 +10,7 @@
};
u-boot {
- offset = <0x18>;
+ offset = <0x1c>;
};
u-boot-spl2 {
diff --git a/tools/binman/test/149_symbols_tpl.dts b/tools/binman/test/149_symbols_tpl.dts
index 0a4ab3f1fa..4e649c4597 100644
--- a/tools/binman/test/149_symbols_tpl.dts
+++ b/tools/binman/test/149_symbols_tpl.dts
@@ -11,12 +11,12 @@
};
u-boot-spl2 {
- offset = <0x1c>;
+ offset = <0x20>;
type = "u-boot-spl";
};
u-boot {
- offset = <0x34>;
+ offset = <0x3c>;
};
section {
diff --git a/tools/binman/test/155_symbols_tpl_x86.dts b/tools/binman/test/155_symbols_tpl_x86.dts
index 9d7dc51b3d..e1ce33e67f 100644
--- a/tools/binman/test/155_symbols_tpl_x86.dts
+++ b/tools/binman/test/155_symbols_tpl_x86.dts
@@ -14,12 +14,12 @@
};
u-boot-spl2 {
- offset = <0xffffff1c>;
+ offset = <0xffffff20>;
type = "u-boot-spl";
};
u-boot {
- offset = <0xffffff34>;
+ offset = <0xffffff3c>;
};
section {
diff --git a/tools/binman/test/187_symbols_sub.dts b/tools/binman/test/187_symbols_sub.dts
index 54511a7371..3ab62d3721 100644
--- a/tools/binman/test/187_symbols_sub.dts
+++ b/tools/binman/test/187_symbols_sub.dts
@@ -11,7 +11,7 @@
};
u-boot {
- offset = <24>;
+ offset = <28>;
};
};
diff --git a/tools/binman/test/Makefile b/tools/binman/test/Makefile
index 57057e2d58..bea8567c9b 100644
--- a/tools/binman/test/Makefile
+++ b/tools/binman/test/Makefile
@@ -21,7 +21,7 @@ CC = $(CROSS_COMPILE)gcc
OBJCOPY = $(CROSS_COMPILE)objcopy
VPATH := $(SRC)
-CFLAGS := -march=i386 -m32 -nostdlib -I $(SRC)../../../include \
+CFLAGS := -march=i386 -m32 -nostdlib -I $(SRC)../../../include -I $(SRC) \
-Wl,--no-dynamic-linker
LDS_UCODE := -T $(SRC)u_boot_ucode_ptr.lds
diff --git a/tools/binman/test/generated/autoconf.h b/tools/binman/test/generated/autoconf.h
new file mode 100644
index 0000000000..6a23039f46
--- /dev/null
+++ b/tools/binman/test/generated/autoconf.h
@@ -0,0 +1,3 @@
+#define CONFIG_BINMAN 1
+#define CONFIG_SPL_BUILD 1
+#define CONFIG_SPL_BINMAN_SYMBOLS 1
diff --git a/tools/binman/test/u_boot_binman_syms.c b/tools/binman/test/u_boot_binman_syms.c
index 37fc339ce8..ed761246ae 100644
--- a/tools/binman/test/u_boot_binman_syms.c
+++ b/tools/binman/test/u_boot_binman_syms.c
@@ -5,9 +5,13 @@
* Simple program to create some binman symbols. This is used by binman tests.
*/
-#define CONFIG_BINMAN
+typedef unsigned long ulong;
+
+#include <linux/kconfig.h>
#include <binman_sym.h>
+DECLARE_BINMAN_MAGIC_SYM;
+
binman_sym_declare(unsigned long, u_boot_spl_any, offset);
binman_sym_declare(unsigned long long, u_boot_spl2, offset);
binman_sym_declare(unsigned long, u_boot_any, image_pos);
diff --git a/tools/binman/test/u_boot_binman_syms_size.c b/tools/binman/test/u_boot_binman_syms_size.c
index 7224bc1863..fa41b3d9a3 100644
--- a/tools/binman/test/u_boot_binman_syms_size.c
+++ b/tools/binman/test/u_boot_binman_syms_size.c
@@ -5,7 +5,11 @@
* Simple program to create some binman symbols. This is used by binman tests.
*/
-#define CONFIG_BINMAN
+typedef unsigned long ulong;
+
+#include <linux/kconfig.h>
#include <binman_sym.h>
+DECLARE_BINMAN_MAGIC_SYM;
+
binman_sym_declare(char, u_boot_spl, pos);
diff --git a/tools/buildman/main.py b/tools/buildman/main.py
index 3b6af24080..67c560c48d 100755
--- a/tools/buildman/main.py
+++ b/tools/buildman/main.py
@@ -11,7 +11,6 @@ import multiprocessing
import os
import re
import sys
-import unittest
# Bring in the patman libraries
our_path = os.path.dirname(os.path.realpath(__file__))
@@ -34,19 +33,18 @@ def RunTests(skip_net_tests, verboose, args):
from buildman import test
import doctest
- result = unittest.TestResult()
test_name = args and args[0] or None
if skip_net_tests:
test.use_network = False
# Run the entry tests first ,since these need to be the first to import the
# 'entry' module.
- test_util.run_test_suites(
- result, False, verboose, False, None, test_name, [],
+ result = test_util.run_test_suites(
+ 'buildman', False, verboose, False, None, test_name, [],
[test.TestBuild, func_test.TestFunctional,
'buildman.toolchain', 'patman.gitutil'])
- return test_util.report_result('buildman', test_name, result)
+ return (0 if result.wasSuccessful() else 1)
options, args = cmdline.ParseArgs()
diff --git a/tools/concurrencytest/concurrencytest.py b/tools/concurrencytest/concurrencytest.py
index 5e88b94f41..1c4f03f37e 100644
--- a/tools/concurrencytest/concurrencytest.py
+++ b/tools/concurrencytest/concurrencytest.py
@@ -31,6 +31,7 @@ from subunit import ProtocolTestCase, TestProtocolClient
from subunit.test_results import AutoTimingTestResultDecorator
from testtools import ConcurrentTestSuite, iterate_tests
+from testtools.content import TracebackContent, text_content
_all__ = [
@@ -43,11 +44,81 @@ _all__ = [
CPU_COUNT = cpu_count()
-def fork_for_tests(concurrency_num=CPU_COUNT):
+class BufferingTestProtocolClient(TestProtocolClient):
+ """A TestProtocolClient which can buffer the test outputs
+
+ This class captures the stdout and stderr output streams of the
+ tests as it runs them, and includes the output texts in the subunit
+ stream as additional details.
+
+ Args:
+ stream: A file-like object to write a subunit stream to
+ buffer (bool): True to capture test stdout/stderr outputs and
+ include them in the test details
+ """
+ def __init__(self, stream, buffer=True):
+ super().__init__(stream)
+ self.buffer = buffer
+
+ def _addOutcome(self, outcome, test, error=None, details=None,
+ error_permitted=True):
+ """Report a test outcome to the subunit stream
+
+ The parent class uses this function as a common implementation
+ for various methods that report successes, errors, failures, etc.
+
+ This version automatically upgrades the error tracebacks to the
+ new 'details' format by wrapping them in a Content object, so
+ that we can include the captured test output in the test result
+ details.
+
+ Args:
+ outcome: A string describing the outcome - used as the
+ event name in the subunit stream.
+ test: The test case whose outcome is to be reported
+ error: Standard unittest positional argument form - an
+ exc_info tuple.
+ details: New Testing-in-python drafted API; a dict from
+ string to subunit.Content objects.
+ error_permitted: If True then one and only one of error or
+ details must be supplied. If False then error must not
+ be supplied and details is still optional.
+ """
+ if details is None:
+ details = {}
+
+ # Parent will raise an exception if error_permitted is False but
+ # error is not None. We want that exception in that case, so
+ # don't touch error when error_permitted is explicitly False.
+ if error_permitted and error is not None:
+ # Parent class prefers error over details
+ details['traceback'] = TracebackContent(error, test)
+ error_permitted = False
+ error = None
+
+ if self.buffer:
+ stdout = sys.stdout.getvalue()
+ if stdout:
+ details['stdout'] = text_content(stdout)
+
+ stderr = sys.stderr.getvalue()
+ if stderr:
+ details['stderr'] = text_content(stderr)
+
+ return super()._addOutcome(outcome, test, error=error,
+ details=details, error_permitted=error_permitted)
+
+
+def fork_for_tests(concurrency_num=CPU_COUNT, buffer=False):
"""Implementation of `make_tests` used to construct `ConcurrentTestSuite`.
:param concurrency_num: number of processes to use.
"""
+ if buffer:
+ test_protocol_client_class = BufferingTestProtocolClient
+ else:
+ test_protocol_client_class = TestProtocolClient
+
def do_fork(suite):
"""Take suite and start up multiple runners by forking (Unix only).
@@ -76,7 +147,7 @@ def fork_for_tests(concurrency_num=CPU_COUNT):
# child actually gets keystrokes for pdb etc).
sys.stdin.close()
subunit_result = AutoTimingTestResultDecorator(
- TestProtocolClient(stream)
+ test_protocol_client_class(stream)
)
process_suite.run(subunit_result)
except:
@@ -93,7 +164,13 @@ def fork_for_tests(concurrency_num=CPU_COUNT):
else:
os.close(c2pwrite)
stream = os.fdopen(c2pread, 'rb')
- test = ProtocolTestCase(stream)
+ # If we don't pass the second argument here, it defaults
+ # to sys.stdout.buffer down the line. But if we don't
+ # pass it *now*, it may be resolved after sys.stdout is
+ # replaced with a StringIO (to capture tests' outputs)
+ # which doesn't have a buffer attribute and can end up
+ # occasionally causing a 'broken-runner' error.
+ test = ProtocolTestCase(stream, sys.stdout.buffer)
result.append(test)
return result
return do_fork
diff --git a/tools/dtoc/main.py b/tools/dtoc/main.py
index fac9db9c78..5508759d4d 100755
--- a/tools/dtoc/main.py
+++ b/tools/dtoc/main.py
@@ -24,7 +24,6 @@ see doc/driver-model/of-plat.rst
from argparse import ArgumentParser
import os
import sys
-import unittest
# Bring in the patman libraries
our_path = os.path.dirname(os.path.realpath(__file__))
@@ -49,18 +48,18 @@ def run_tests(processes, args):
from dtoc import test_src_scan
from dtoc import test_dtoc
- result = unittest.TestResult()
sys.argv = [sys.argv[0]]
test_name = args.files and args.files[0] or None
test_dtoc.setup()
- test_util.run_test_suites(
- result, debug=True, verbosity=1, test_preserve_dirs=False,
+ result = test_util.run_test_suites(
+ toolname='dtoc', debug=True, verbosity=1, test_preserve_dirs=False,
processes=processes, test_name=test_name, toolpath=[],
class_and_module_list=[test_dtoc.TestDtoc,test_src_scan.TestSrcScan])
- return test_util.report_result('binman', test_name, result)
+ return (0 if result.wasSuccessful() else 1)
+
def RunTestCoverage():
"""Run the tests and check that we get 100% coverage"""
diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py
index c81bcc9c32..879ca2ab2b 100755
--- a/tools/dtoc/test_dtoc.py
+++ b/tools/dtoc/test_dtoc.py
@@ -616,8 +616,11 @@ struct dm_test_pdata __attribute__ ((section (".priv_data")))
u8 _denx_u_boot_test_bus_priv_some_bus[sizeof(struct dm_test_priv)]
\t__attribute__ ((section (".priv_data")));
#include <dm/test.h>
-u8 _denx_u_boot_test_bus_ucplat_some_bus[sizeof(struct dm_test_uclass_priv)]
+u8 _denx_u_boot_test_bus_ucplat_some_bus[sizeof(struct dm_test_uclass_plat)]
\t__attribute__ ((section (".priv_data")));
+#include <dm/test.h>
+u8 _denx_u_boot_test_bus_uc_priv_some_bus[sizeof(struct dm_test_uclass_priv)]
+ __attribute__ ((section (".priv_data")));
#include <test.h>
DM_DEVICE_INST(some_bus) = {
@@ -628,6 +631,7 @@ DM_DEVICE_INST(some_bus) = {
\t.driver_data\t= DM_TEST_TYPE_FIRST,
\t.priv_\t\t= _denx_u_boot_test_bus_priv_some_bus,
\t.uclass\t\t= DM_UCLASS_REF(testbus),
+\t.uclass_priv_ = _denx_u_boot_test_bus_uc_priv_some_bus,
\t.uclass_node\t= {
\t\t.prev = &DM_UCLASS_REF(testbus)->dev_head,
\t\t.next = &DM_UCLASS_REF(testbus)->dev_head,
diff --git a/tools/dtoc/test_fdt.py b/tools/dtoc/test_fdt.py
index 914ed6aed5..3baf4437cd 100755
--- a/tools/dtoc/test_fdt.py
+++ b/tools/dtoc/test_fdt.py
@@ -780,25 +780,17 @@ def RunTests(args):
Args:
args: List of positional args provided to fdt. This can hold a test
name to execute (as in 'fdt -t testFdt', for example)
+
+ Returns:
+ Return code, 0 on success
"""
- result = unittest.TestResult()
- sys.argv = [sys.argv[0]]
test_name = args and args[0] or None
- for module in (TestFdt, TestNode, TestProp, TestFdtUtil):
- if test_name:
- try:
- suite = unittest.TestLoader().loadTestsFromName(test_name, module)
- except AttributeError:
- continue
- else:
- suite = unittest.TestLoader().loadTestsFromTestCase(module)
- suite.run(result)
-
- print(result)
- for _, err in result.errors:
- print(err)
- for _, err in result.failures:
- print(err)
+ result = test_util.run_test_suites(
+ 'test_fdt', False, False, False, None, test_name, None,
+ [TestFdt, TestNode, TestProp, TestFdtUtil])
+
+ return (0 if result.wasSuccessful() else 1)
+
if __name__ != '__main__':
sys.exit(1)
@@ -816,6 +808,7 @@ parser.add_option('-T', '--test-coverage', action='store_true',
# Run our meagre tests
if options.test:
- RunTests(args)
+ ret_code = RunTests(args)
+ sys.exit(ret_code)
elif options.test_coverage:
RunTestCoverage()
diff --git a/tools/patman/main.py b/tools/patman/main.py
index 2a2ac45709..66d4806c8d 100755
--- a/tools/patman/main.py
+++ b/tools/patman/main.py
@@ -12,7 +12,6 @@ import re
import shutil
import sys
import traceback
-import unittest
if __name__ == "__main__":
# Allow 'from patman import xxx to work'
@@ -134,13 +133,12 @@ if args.cmd == 'test':
import doctest
from patman import func_test
- result = unittest.TestResult()
- test_util.run_test_suites(
- result, False, False, False, None, None, None,
+ result = test_util.run_test_suites(
+ 'patman', False, False, False, None, None, None,
[test_checkpatch.TestPatch, func_test.TestFunctional,
'gitutil', 'settings', 'terminal'])
- sys.exit(test_util.report_result('patman', args.testname, result))
+ sys.exit(0 if result.wasSuccessful() else 1)
# Process commits, produce patches files, check them, email them
elif args.cmd == 'send':
diff --git a/tools/patman/settings.py b/tools/patman/settings.py
index 7c2b5c196c..4c847fe88f 100644
--- a/tools/patman/settings.py
+++ b/tools/patman/settings.py
@@ -246,8 +246,10 @@ def _UpdateDefaults(main_parser, config):
# Collect the defaults from each parser
defaults = {}
+ parser_defaults = []
for parser in parsers:
pdefs = parser.parse_known_args()[0]
+ parser_defaults.append(pdefs)
defaults.update(vars(pdefs))
# Go through the settings and collect defaults
@@ -264,8 +266,11 @@ def _UpdateDefaults(main_parser, config):
else:
print("WARNING: Unknown setting %s" % name)
- # Set all the defaults (this propagates through all subparsers)
+ # Set all the defaults and manually propagate them to subparsers
main_parser.set_defaults(**defaults)
+ for parser, pdefs in zip(parsers, parser_defaults):
+ parser.set_defaults(**{ k: v for k, v in defaults.items()
+ if k in pdefs })
def _ReadAliasFile(fname):
"""Read in the U-Boot git alias file if it exists.
diff --git a/tools/patman/test_util.py b/tools/patman/test_util.py
index c60eb3628e..c27e0b39e5 100644
--- a/tools/patman/test_util.py
+++ b/tools/patman/test_util.py
@@ -15,6 +15,7 @@ from patman import command
from io import StringIO
+buffer_outputs = True
use_concurrent = True
try:
from concurrencytest.concurrencytest import ConcurrentTestSuite
@@ -102,49 +103,85 @@ def capture_sys_output():
sys.stdout, sys.stderr = old_out, old_err
-def report_result(toolname:str, test_name: str, result: unittest.TestResult):
- """Report the results from a suite of tests
+class FullTextTestResult(unittest.TextTestResult):
+ """A test result class that can print extended text results to a stream
+
+ This is meant to be used by a TestRunner as a result class. Like
+ TextTestResult, this prints out the names of tests as they are run,
+ errors as they occur, and a summary of the results at the end of the
+ test run. Beyond those, this prints information about skipped tests,
+ expected failures and unexpected successes.
Args:
- toolname: Name of the tool that ran the tests
- test_name: Name of test that was run, or None for all
- result: A unittest.TestResult object containing the results
+ stream: A file-like object to write results to
+ descriptions (bool): True to print descriptions with test names
+ verbosity (int): Detail of printed output per test as they run
+ Test stdout and stderr always get printed when buffering
+ them is disabled by the test runner. In addition to that,
+ 0: Print nothing
+ 1: Print a dot per test
+ 2: Print test names
+ 3: Print test names, and buffered outputs for failing tests
"""
- # Remove errors which just indicate a missing test. Since Python v3.5 If an
- # ImportError or AttributeError occurs while traversing name then a
- # synthetic test that raises that error when run will be returned. These
- # errors are included in the errors accumulated by result.errors.
- if test_name:
- errors = []
-
- for test, err in result.errors:
- if ("has no attribute '%s'" % test_name) not in err:
- errors.append((test, err))
- result.testsRun -= 1
- result.errors = errors
-
- print(result)
- for test, err in result.errors:
- print(test.id(), err)
- for test, err in result.failures:
- print(err, result.failures)
- if result.skipped:
- print('%d %s test%s SKIPPED:' % (len(result.skipped), toolname,
- 's' if len(result.skipped) > 1 else ''))
- for skip_info in result.skipped:
- print('%s: %s' % (skip_info[0], skip_info[1]))
- if result.errors or result.failures:
- print('%s tests FAILED' % toolname)
- return 1
- return 0
-
-
-def run_test_suites(result, debug, verbosity, test_preserve_dirs, processes,
+ def __init__(self, stream, descriptions, verbosity):
+ self.verbosity = verbosity
+ super().__init__(stream, descriptions, verbosity)
+
+ def printErrors(self):
+ "Called by TestRunner after test run to summarize the tests"
+ # The parent class doesn't keep unexpected successes in the same
+ # format as the rest. Adapt it to what printErrorList expects.
+ unexpected_successes = [
+ (test, 'Test was expected to fail, but succeeded.\n')
+ for test in self.unexpectedSuccesses
+ ]
+
+ super().printErrors() # FAIL and ERROR
+ self.printErrorList('SKIP', self.skipped)
+ self.printErrorList('XFAIL', self.expectedFailures)
+ self.printErrorList('XPASS', unexpected_successes)
+
+ def addError(self, test, err):
+ """Called when an error has occurred."""
+ super().addError(test, err)
+ self._mirrorOutput &= self.verbosity >= 3
+
+ def addFailure(self, test, err):
+ """Called when a test has failed."""
+ super().addFailure(test, err)
+ self._mirrorOutput &= self.verbosity >= 3
+
+ def addSubTest(self, test, subtest, err):
+ """Called at the end of a subtest."""
+ super().addSubTest(test, subtest, err)
+ self._mirrorOutput &= self.verbosity >= 3
+
+ def addSuccess(self, test):
+ """Called when a test has completed successfully"""
+ super().addSuccess(test)
+ # Don't print stdout/stderr for successful tests
+ self._mirrorOutput = False
+
+ def addSkip(self, test, reason):
+ """Called when a test is skipped."""
+ # Add empty line to keep spacing consistent with other results
+ if not reason.endswith('\n'):
+ reason += '\n'
+ super().addSkip(test, reason)
+ self._mirrorOutput &= self.verbosity >= 3
+
+ def addExpectedFailure(self, test, err):
+ """Called when an expected failure/error occurred."""
+ super().addExpectedFailure(test, err)
+ self._mirrorOutput &= self.verbosity >= 3
+
+
+def run_test_suites(toolname, debug, verbosity, test_preserve_dirs, processes,
test_name, toolpath, class_and_module_list):
"""Run a series of test suites and collect the results
Args:
- result: A unittest.TestResult object to add the results to
+ toolname: Name of the tool that ran the tests
debug: True to enable debugging, which shows a full stack trace on error
verbosity: Verbosity level to use (0-4)
test_preserve_dirs: True to preserve the input directory used by tests
@@ -158,11 +195,6 @@ def run_test_suites(result, debug, verbosity, test_preserve_dirs, processes,
class_and_module_list: List of test classes (type class) and module
names (type str) to run
"""
- for module in class_and_module_list:
- if isinstance(module, str) and (not test_name or test_name == module):
- suite = doctest.DocTestSuite(module)
- suite.run(result)
-
sys.argv = [sys.argv[0]]
if debug:
sys.argv.append('-D')
@@ -174,6 +206,22 @@ def run_test_suites(result, debug, verbosity, test_preserve_dirs, processes,
suite = unittest.TestSuite()
loader = unittest.TestLoader()
+ runner = unittest.TextTestRunner(
+ stream=sys.stdout,
+ verbosity=(1 if verbosity is None else verbosity),
+ buffer=buffer_outputs,
+ resultclass=FullTextTestResult,
+ )
+
+ if use_concurrent and processes != 1:
+ suite = ConcurrentTestSuite(suite,
+ fork_for_tests(processes or multiprocessing.cpu_count(),
+ buffer=buffer_outputs))
+
+ for module in class_and_module_list:
+ if isinstance(module, str) and (not test_name or test_name == module):
+ suite.addTests(doctest.DocTestSuite(module))
+
for module in class_and_module_list:
if isinstance(module, str):
continue
@@ -184,15 +232,17 @@ def run_test_suites(result, debug, verbosity, test_preserve_dirs, processes,
preserve_outdirs=test_preserve_dirs and test_name is not None,
toolpath=toolpath, verbosity=verbosity)
if test_name:
- try:
+ # Since Python v3.5 If an ImportError or AttributeError occurs
+ # while traversing a name then a synthetic test that raises that
+ # error when run will be returned. Check that the requested test
+ # exists, otherwise these errors are included in the results.
+ if test_name in loader.getTestCaseNames(module):
suite.addTests(loader.loadTestsFromName(test_name, module))
- except AttributeError:
- continue
else:
suite.addTests(loader.loadTestsFromTestCase(module))
- if use_concurrent and processes != 1:
- concurrent_suite = ConcurrentTestSuite(suite,
- fork_for_tests(processes or multiprocessing.cpu_count()))
- concurrent_suite.run(result)
- else:
- suite.run(result)
+
+ print(f" Running {toolname} tests ".center(70, "="))
+ result = runner.run(suite)
+ print()
+
+ return result