Skip to content

Port tests to barrage#4357

Draft
martinpitt wants to merge 6 commits into
systemd:mainfrom
martinpitt:test-barrage
Draft

Port tests to barrage#4357
martinpitt wants to merge 6 commits into
systemd:mainfrom
martinpitt:test-barrage

Conversation

@martinpitt

@martinpitt martinpitt commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

The mere installation of barrage already involved some decisions and will probably trigger some discussion.

I split out the barrage install, unit+install, and the integration test porting into three separate commits to make the review slightly easier. If you prefer, I can eventually all squash it.

@martinpitt martinpitt force-pushed the test-barrage branch 3 times, most recently from 954cb2a to b3dab11 Compare June 11, 2026 19:21
@martinpitt

Copy link
Copy Markdown
Contributor Author

I went through all the commits and did some cleanups. I also had a new claude session review the commits, including a careful cataloguing of old and new tests and making sure I didn't drop anything. I also introduced and verified TEST_DEBUG_SHELL as a replacement for --debug-shell.

@martinpitt martinpitt changed the title WIP: Port tests to barrage Port tests to barrage Jun 11, 2026
@martinpitt martinpitt marked this pull request as ready for review June 11, 2026 19:51
Comment thread .github/workflows/ci.yml Outdated
@behrmann

Copy link
Copy Markdown
Contributor

That's a big chunk of work! Thanks!

I've had a quick look over it and there are things I do like about this, but I'd be happier if this weren't so unittest/javaesque, i.e. there's got to be some test classes for setup (what fixtures did in pytest), but some of the config tests, json or kmod could do with just test functions, making the diff smaller (and the whole thing more flat). Also, generally using the functions from barrage.assertions seems preferable to those self.assertEqual unittest things.

@martinpitt

Copy link
Copy Markdown
Contributor Author

@behrmann cheers! Agreed to restructuring the classes wrt. fixtures, and flattening some test files.

Also, generally using the functions from barrage.assertions seems preferable to those self.assertEqual unittest things.

I don't understand this. The docs explicitly say "Assertion helpers — same names as unittest", and barrage's own tests all use self.assertEqual() and the like. It seems to me that the Assert.eq() etc. methods are just an internal implementation detail of AsyncTestCase.assert*() ?

@behrmann

Copy link
Copy Markdown
Contributor

Ok, so this might be a case of the blind leading the blind, since I've not yet really had the time to look at barrage all to closely (mea culpa), but I don't think the Assert.* are internal, since they are explicitly mentioned in the README and I think Daan might have added them, because I've mentioned how much I dislike the unittest style of tests. :) I would greatly prefer the pytest style of using plain assert, but the implementation of that is somewhat magical and too involved, which is why that was reasonable middle ground. He also referred to that style yesterday as "old style", which also indicates that the explicit Assert.* are intended for use.

@martinpitt

Copy link
Copy Markdown
Contributor Author

@behrmann Ah! got it -- these are for test functions, as obviously they don't have a self.

Most unit tests are straightforward, I fully agree they should be functions. I already re-converted them locally.

Only test_config.py raises a little bit of doubt: The thing is, barrage really doesn't have a concept for "fixtures" in the pytest sense. We can use the AsyncExitStack functionality and move the fixtures into helpers. That amounts to one extra line per test. I'd personally use a class for this to share the setUp(), and also provide grouping for related tests. But it's not a strong opinion, and as these are existing tests, I get that it's attractive to minimize the structural diff.

I pushed a new version which moves the unit and install tests to functions. I didn't yet touch the integration tests.

@martinpitt

martinpitt commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

@behrmann I talked to @daandemeyer (he was sitting next to me), and the executive decision was to do the Assert.* things everywhere. FWIW, I agree, for consistency -- we should just update barrage's tests and doc for that.

I moved the integration tests to functional as well. I spot-checked some of them, but I still run into io.systemd.NamespaceResource.NoDynamicRange all the time, even with --max-concurrency=1. There is clearly a bug with that still, but it doesn't affect CI (which runs as root). So let's get the bots' opinion.

There are still lots of concurrency bugs once more than one VM actually runs in parallel. Working through them.

@martinpitt

martinpitt commented Jun 14, 2026

Copy link
Copy Markdown
Contributor Author

I worked this out. This first requires a bunch of fixes for the tests to allow running them in parallel, I split that out into #4360.

Then I fixed the actual mkosi invocations to be async as well. On the latest run on my fork things now succeed, and they only take ~ 7 instead of ~ 15 minutes, i.e. actual 2x parallelism as specified in the workflow. I'm afraid we can't get higher until barrage learns about test VM resource usage and throttling itself -- test_initrd_luks takes 2 GiB, everything else 1.5 GiB, so on a 4 GiB GitHub runner concurrency=2 is the maximum that we can do reliably. But on my laptop, or if we would run this stuff on custom infra, it can go much higher.

@martinpitt

martinpitt commented Jun 14, 2026

Copy link
Copy Markdown
Contributor Author

For those following along at home: At least for me, the NoDynamicRange failures on unprivileged runs are rather unbearable (and I refuse to run builds/tests as root on my laptop). I have a commit which helps a lot, but it's a bit gross and it seems to me there is a systemd-nsresourced bug to fix instead. But just in case you play around with this locally.

@daandemeyer also sent a PR to systemd about that: systemd/systemd#42534

@martinpitt

Copy link
Copy Markdown
Contributor Author

Rebased and adjusted for the "pass on snapshot to extension build" change that happened in the meantime. Mostly green, just this ppc64le download failure smells like qemu emulation segfault. Feel free to retry.

Otherwise ready to review.

@martinpitt martinpitt marked this pull request as draft June 25, 2026 09:25
@martinpitt

Copy link
Copy Markdown
Contributor Author

#4373 landed, so that output directory fix needs to be re-done.

…tput dir

A build can be told its output directory on the command line (`-O`) while a
later verb that consumes the build (vm, boot, summary, …) only knows it from
`OutputDirectory=` in the configuration. As long as both point at the same
directory, the consumer must still find the build history the build wrote.

This is what systemd does: its meson build passes `--output-dir`
explicitly, while a developer running `mkosi vm` (without
`--output-dir`) afterwards relies on `OutputDirectory=`. Capture this
behaviour so we don't regress it again.

This broke once in commit da49fe9 ("Put build history into the output
directory"), which keyed the history location on the CLI value only, and
was reverted in commit 582eade.
martinpitt and others added 5 commits June 26, 2026 11:19
When building into separate output directories (e.g. the integration
test suite running in parallel), all builds shared a single build
history in the config directory. A verb that consumes a previous build
(vm, boot, summary, …) then read back whichever build ran last instead
of the one for the output directory it was pointed at.

To fix that and keep an output directory isolated, store the history in
it as well, and prefer it when given `--output-directory`.

The config directory copy is kept and is still used when no `-O` is
passed, so a consumer that gets the output directory from
`OutputDirectory=` in the configuration keeps working (and the
output-dir lookup falls back to it, status quo ante). This is what
commit da49fe9 tried to do, but it stored the history *only* in the
output directory keyed on the CLI value, which broke consumers that take
the output directory from the configuration.

Keying the read on the CLI value and keeping the config-dir copy avoids
that regression. Cover this in the new
`test_history_found_via_configured_output_directory()`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The integration tests build into a per-test `--output-directory`, but
the verbs that consume the build (vm, boot) did not pass it, so they
recovered the build's configuration from the history in the config
directory. This breaks parallel tests, as they read the history file
from current global file (i.e. whichever build happened to finish last).

This is the tests/__init__.py half of the reverted commit da49fe9.
(That wasn't problematic.)
We are going to port our tests to <https://github.com/amutable-systems/barrage>.

Get it into the box via pip; this will allow dependabot (or renovate) to
keep it up to date without custom logic, once we move from "pull from
git" to "pull latest release from pypi". With renovate, we could also keep
the git SHA pinning, but renovate requires some more set up effort.

Note: An alternative way for this would be to pull in barrage as a
submodule. Dependabot/renovate work great for these, but the human
ergonomics are not very pleasant.
barrage does not have the equivalent of pytest markers, but it can
select by file pattern. So unit tests retain `test_*.py`, and rename the
other two kinds to `install_*.py` and `integration_*.py`.

This parallelizes the subprocess-y parts like test_linters.py.

Co-developed-by: Claude Opus 4.8 <noreply@anthropic.com>
barrage has no equivalent to pytest's `parametrize`. Open-code that with
`do_test_*(params...)` helpers and individual tests calling that.

Stop passing the explicit `--distribution` to the test. The new
`ImageConfigManager` singleton (which replaces the old `config` pytest
fixture) reads the distribution from `mkosi.local.conf`. This avoids
having to specify it twice, and leaves the configuration to
`integration-test-setup.sh`.

Drop the `log_setup()` call. The integration tests themselves don't use
`logging`, this mostly just affects the called `mkosi` subprocesses
which already do it. This is very prone to interfere with barrage's own
stderr capturing.

Replace the `--debug-shell` pytest option with a `TEST_DEBUG_SHELL` env
variable, as barrage doesn't have test-defined CLI options.

Make the mkosi invocations in tests/__init__.py async, so that they can
actually run in parallel.

Remove installation and remaining traces of pytest.

Co-developed-by: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants