Compare commits

..

9 Commits
tesh ... tesg

Author SHA1 Message Date
Simon Glass
0ceb01480f test: Add parallel test execution support
Running the full test suite takes a long time. It would be useful to
distribute tests across multiple sandbox instances to speed up testing.

Add support for running tests in parallel across multiple sandbox
instances. Each worker runs a subset of tests based on its worker ID.

Add -P<n>:<w> option to the ut command where n is the total number of
workers and w is this worker's ID (0 to n-1). Tests are distributed
by index modulo number of workers.

Series-to: concept
Series-cc: heinrich
Cover-letter:
test: Various improvements to unit-test infrastructure

This series adds several improvements to the unit-test infrastructure:

- Move disk images to the persistent-data directory so they don't
  pollute the source tree
- Add a way to keep pytest-created artefacts for faster iteration on
  C tests
- Add a helper to simplify running manual unit tests from Python
- Allow combined flags with the ut command (e.g. -Efm)
- Add a -E flag to emit machine-readable result lines
- Add a -P flag to distribute tests across parallel workers
- Add -m as an alias for -f (force manual tests)

These changes make it easier to run and debug tests, especially when
iterating on C test code.
END

Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
Series-links: 1:94
2025-12-29 09:04:35 -07:00
Simon Glass
21b9118757 doc: ut: Document return value
Add documentation for the return value of the ut command:
- Returns 0 on success if all tests pass
- Returns 1 on failure if any test fails
- Skipped tests do not cause a failure

Also explain when tests may be skipped and how to detect skipped tests
programmatically using the -E flag.

Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
2025-12-29 08:55:46 -07:00
Simon Glass
4e257da1a3 test: Add a flag to emit per-test result lines
The ut command shows test output but does not provide a machine-readable
indication of whether each individual test passed or failed. External
tools must rely on heuristics like scanning for failure patterns in the
output.

Add a -E flag that emits an explicit result line after each test:
  Result: PASS: test_name: file.c
  Result: FAIL: test_name: file.c

This allows tools to reliably determine per-test pass/fail status
without fragile pattern matching. The flag is optional to maintain
backward compatibility with existing scripts.

Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
2025-12-29 08:55:46 -07:00
Simon Glass
7c1985400a test: ut: Refactor argument processing to use a loop
The current argument-parsing logic uses switch (str[1]) which only
processes the second character of each argument. This prevents combining
multiple single-character flags in one argument (e.g., -fm).

Refactor the code to use a for loop that iterates through all characters
in the argument. For flags that take a value (like -r and -I), use goto
to skip the rest of the argument after processing.

This allows combined flags like -fmR instead of requiring -f -m -R.

Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
2025-12-29 08:55:46 -07:00
Simon Glass
b476f7e51b test: ut: Add -m as alias for the -f flag
Add -m as an alias for the -f flag which forces manual tests to run.
This provides consistency with external test runners that will use -m
for "manual" tests.

Also update the documentation to explain what manual tests are, and fix
a typo ("types" -> "times") in the -r description.

Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
2025-12-29 08:55:46 -07:00
Simon Glass
350e7624ec test: py: Add run_ut() helper for manual unit tests
Running manual unit tests (those with _norun suffix) involves a common
pattern: building the ut command with the -f flag, running it, and
checking for failures. This is verbose and error-prone.

Add a run_ut() method to ConsoleBase that simplifies this. It handles
the command construction, test arguments and failure checking
automatically.

Before:
    output = ubman.run_command(
        f'ut -f fs fs_test_ext4l_probe_norun fs_image={ext4_image}')
    assert 'failures: 0' in output

After:
    ubman.run_ut('fs', 'fs_test_ext4l_probe', fs_image=ext4_image)

Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
2025-12-29 08:55:46 -07:00
Simon Glass
bcfa556a36 test: py: Add --persist flag to keep test artefacts
When iterating on C test code, the Python fixtures that create disk
images run each time, even though the images have not changed. This
slows down the development cycle unnecessarily.

Add a -P/--persist option to prevent cleanup of test-generated files
like disk images. This allows re-running C tests directly, without
re-running the Python fixture each time.

Update the ext4l test to respect the persist flag.

Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
2025-12-29 08:55:46 -07:00
Simon Glass
570c30e820 test: Write the SPI image to the persistent-data directory
It is annoying to have disk images in the source directory since it
clutters up the working space.

Move spi.bin (used by the SPI tests) into the persistent-data
directory, update the driver and add a comment.

Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
2025-12-29 08:49:51 -07:00
Simon Glass
4ee8f5c74f test: Move disk images to persistent-data directory
It is annoying to have disk images in the source directory since it
clutters up the working space.

Remove cur_dir=True from DiskHelper calls so disk images are written to
the persistent-data directory instead.

Move scsi.img too (used by the bootstd tests) and mmc6.img (used by the
MBR tests.

Add a few comments as to where the images are used.

This keeps the source tree clean and puts disk images in the same place
as other test data.

Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
2025-12-29 07:36:29 -07:00
5 changed files with 39 additions and 16 deletions

View File

@@ -6,7 +6,7 @@ subdir-y :=
# You can set these variables from the command line.
SPHINXBUILD = sphinx-build
SPHINXOPTS = -q -W
SPHINXOPTS = -W
SPHINXDIRS = .
_SPHINXDIRS = $(patsubst $(srctree)/doc/%/conf.py,%,$(wildcard $(srctree)/doc/*/conf.py))
SPHINX_CONF = conf.py
@@ -51,8 +51,8 @@ loop_cmd = $(echo-cmd) $(cmd_$(1)) || exit;
# $5 reST source folder relative to $(srctree)/$(src),
# e.g. "media" for the linux-tv book-set at ./doc/media
quiet_cmd_sphinx =
cmd_sphinx = $(MAKE) -s BUILDDIR=$(abspath $(BUILDDIR)) $(build)=doc/media $2 && \
quiet_cmd_sphinx = SPHINX $@ --> file://$(abspath $(BUILDDIR)/$3/$4)
cmd_sphinx = $(MAKE) BUILDDIR=$(abspath $(BUILDDIR)) $(build)=doc/media $2 && \
PYTHONDONTWRITEBYTECODE=1 \
BUILDDIR=$(abspath $(BUILDDIR)) SPHINX_CONF=$(abspath $(srctree)/$(src)/$5/$(SPHINX_CONF)) \
$(SPHINXBUILD) \

View File

@@ -377,6 +377,7 @@ latex_elements = {
cjk_cmd = check_output(['fc-list', '--format="%{family[0]}\n"']).decode('utf-8', 'ignore')
if cjk_cmd.find("Noto Sans CJK SC") >= 0:
print ("enabling CJK for LaTeX builder")
latex_elements['preamble'] += '''
% This is needed for translations
\\usepackage{xeCJK}

View File

@@ -12,7 +12,8 @@ gen_rst = \
echo ${PARSER} $< $@ $(SRC_DIR)/$(notdir $@).exceptions; \
${PARSER} $< $@ $(SRC_DIR)/$(notdir $@).exceptions
quiet_gen_rst = ${PARSER} $< $@ $(SRC_DIR)/$(notdir $@).exceptions
quiet_gen_rst = echo ' PARSE $(patsubst $(srctree)/%,%,$<)'; \
${PARSER} $< $@ $(SRC_DIR)/$(notdir $@).exceptions
silent_gen_rst = ${gen_rst}

View File

@@ -72,49 +72,69 @@ class TestExt4l:
def test_probe(self, ubman, ext4_image):
"""Test that ext4l can probe an ext4 filesystem."""
with ubman.log.section('Test ext4l probe'):
ubman.run_ut('fs', 'fs_test_ext4l_probe', fs_image=ext4_image)
output = ubman.run_command(
f'ut -f fs fs_test_ext4l_probe_norun fs_image={ext4_image}')
assert 'failures: 0' in output
def test_msgs(self, ubman, ext4_image):
"""Test that ext4l_msgs env var produces mount messages."""
with ubman.log.section('Test ext4l msgs'):
ubman.run_ut('fs', 'fs_test_ext4l_msgs', fs_image=ext4_image)
output = ubman.run_command(
f'ut -f fs fs_test_ext4l_msgs_norun fs_image={ext4_image}')
assert 'failures: 0' in output
def test_ls(self, ubman, ext4_image):
"""Test that ext4l can list directory contents."""
with ubman.log.section('Test ext4l ls'):
ubman.run_ut('fs', 'fs_test_ext4l_ls', fs_image=ext4_image)
output = ubman.run_command(
f'ut -f fs fs_test_ext4l_ls_norun fs_image={ext4_image}')
assert 'failures: 0' in output
def test_opendir(self, ubman, ext4_image):
"""Test that ext4l can iterate directory entries."""
with ubman.log.section('Test ext4l opendir'):
ubman.run_ut('fs', 'fs_test_ext4l_opendir', fs_image=ext4_image)
output = ubman.run_command(
f'ut -f fs fs_test_ext4l_opendir_norun fs_image={ext4_image}')
assert 'failures: 0' in output
def test_exists(self, ubman, ext4_image):
"""Test that ext4l_exists reports file existence correctly."""
with ubman.log.section('Test ext4l exists'):
ubman.run_ut('fs', 'fs_test_ext4l_exists', fs_image=ext4_image)
output = ubman.run_command(
f'ut -f fs fs_test_ext4l_exists_norun fs_image={ext4_image}')
assert 'failures: 0' in output
def test_size(self, ubman, ext4_image):
"""Test that ext4l_size reports file size correctly."""
with ubman.log.section('Test ext4l size'):
ubman.run_ut('fs', 'fs_test_ext4l_size', fs_image=ext4_image)
output = ubman.run_command(
f'ut -f fs fs_test_ext4l_size_norun fs_image={ext4_image}')
assert 'failures: 0' in output
def test_read(self, ubman, ext4_image):
"""Test that ext4l can read file contents."""
with ubman.log.section('Test ext4l read'):
ubman.run_ut('fs', 'fs_test_ext4l_read', fs_image=ext4_image)
output = ubman.run_command(
f'ut -f fs fs_test_ext4l_read_norun fs_image={ext4_image}')
assert 'failures: 0' in output
def test_uuid(self, ubman, ext4_image):
"""Test that ext4l can return the filesystem UUID."""
with ubman.log.section('Test ext4l uuid'):
ubman.run_ut('fs', 'fs_test_ext4l_uuid', fs_image=ext4_image)
output = ubman.run_command(
f'ut -f fs fs_test_ext4l_uuid_norun fs_image={ext4_image}')
assert 'failures: 0' in output
def test_statfs(self, ubman, ext4_image):
"""Test that ext4l can return filesystem statistics."""
with ubman.log.section('Test ext4l statfs'):
ubman.run_ut('fs', 'fs_test_ext4l_statfs', fs_image=ext4_image)
output = ubman.run_command(
f'ut -f fs fs_test_ext4l_statfs_norun fs_image={ext4_image}')
assert 'failures: 0' in output
def test_fsinfo(self, ubman, ext4_image):
"""Test that fsinfo command displays filesystem statistics."""
with ubman.log.section('Test ext4l fsinfo'):
ubman.run_ut('fs', 'fs_test_ext4l_fsinfo', fs_image=ext4_image)
output = ubman.run_command(
f'ut -f fs fs_test_ext4l_fsinfo_norun fs_image={ext4_image}')
assert 'failures: 0' in output

View File

@@ -87,6 +87,7 @@ bootm loados
bootm prep
fdt addr
fdt print
ut -f bootstd vbe_test_fixup_norun
'''
@pytest.mark.boardspec('sandbox')
@@ -116,9 +117,9 @@ def test_vbe_os_request(ubman):
cmd = base_script % params
with ubman.log.section('Kernel load'):
ubman.run_command_list(cmd.splitlines())
output = ubman.run_command_list(cmd.splitlines())
ubman.run_ut('bootstd', 'vbe_test_fixup')
assert 'failures: 0' in output[-1]
@pytest.mark.boardspec('sandbox')
def test_vbe_extlinux_fit_no_oem(ubman):