Skip to content

tests/int: revamp (drop runc(), use run -N, add asserts) - #5429

Open
kolyshkin wants to merge 9 commits into
opencontainers:mainfrom
kolyshkin:int-shim
Open

kolyshkin wants to merge 9 commits into
opencontainers:mainfrom
kolyshkin:int-shim

Conversation

@kolyshkin

@kolyshkin kolyshkin commented Aug 28, 2026 •

Copy link
Copy Markdown
Contributor

This supersedes #4946, taking a different approach to the problems
discussed there (see this comment and below).

The end result is that integration tests call runc the way any other
command is called, and check its output with helpers that say what went
wrong:

run -0 runc start ctr
assert_output --partial "something"

instead of the current

runc start ctr
[ "$status" -eq 0 ]
[[ "$output" == *"something"* ]]

where runc is a bash function hiding a call to bats' run helper, and
a failed comparison only shows the expression, not the values.

What a failure looks like now

To see this in practice, four deliberate bugs were introduced (runc -v
printing spec :, runc list -q adding a trailing space to the ID, a
reworded hook error, and runc delete --force failing on a missing
container), and the tests were run with and without this PR:

Bug Before Now
list -q adds a trailing space 20 lines of every runc call made so far, ending with an output that looks exactly right expected: 'test_box1'
actual: 'test_box1 '
spec : instead of spec: the failed expression, plus the whole runc -v output to eyeball expected: 'spec: [0-9]+\.[0-9]+\.[0-9]+'
actual: 'spec : 1.3.0'
reworded hook error ditto, with the message to compare by hand expected: 'error running createRuntime hook #1:'
actual: '...failure in createRuntime hook #1...'
delete --force fails [ "$status" -eq 0 ]' failed -- but after which call? run -0 runc delete --force notexists' failed, expected exit code 0, got 1

The trailing space one is the point of the whole exercise. Before:

not ok 1 list
# (in test file tests/integration/list.bats, line 37)
#   `[ "${lines[0]}" = "test_box1" ]' failed
# runc spec --rootless (status=0)
#
# runc run -d --console-socket /tmp/.../tty/sock test_box1 (status=0)
#
[... 10 more lines of the preceding commands and their output ...]
# runc list -q (status=0)
# test_box1
# test_box2
# test_box3

The expected value is not shown, the actual one looks correct, and the
difference is invisible. Now:

not ok 1 list
# (in test file tests/integration/list.bats, line 32)
#   `assert_line --index 0 "test_box1"' failed
# -- line 0 does not match (exact) --
# expected: 'test_box1'
#   actual: 'test_box1 '
# --

@kolyshkin
kolyshkin marked this pull request as draft August 28, 2026 06:08
@kolyshkin kolyshkin changed the title tests/int: add runc wrapper script and assert helper tests/int: use bats' run helper for runc, add assert Aug 28, 2026
@kolyshkin
kolyshkin force-pushed the int-shim branch 2 times, most recently from 9357195 to 580166d Compare August 28, 2026 06:47
@kolyshkin kolyshkin changed the title tests/int: use bats' run helper for runc, add assert tests/int: revamp (add assert, drop function runc, use run -N, etc.) Aug 28, 2026
@kolyshkin
kolyshkin force-pushed the int-shim branch 2 times, most recently from e73b626 to 5fb7f31 Compare August 28, 2026 07:53
@kolyshkin kolyshkin changed the title tests/int: revamp (add assert, drop function runc, use run -N, etc.) tests/int: revamp (add asserts, drop function runc, use run -N) Aug 28, 2026
@kolyshkin
kolyshkin force-pushed the int-shim branch 2 times, most recently from 87cf0b4 to 5fb7f31 Compare August 28, 2026 08:40
@kolyshkin
kolyshkin marked this pull request as ready for review August 28, 2026 08:40
@kolyshkin
kolyshkin force-pushed the int-shim branch 2 times, most recently from d9deecf to 6bd8318 Compare August 29, 2026 02:37
@kolyshkin kolyshkin changed the title tests/int: revamp (add asserts, drop function runc, use run -N) tests/int: revamp (add asserts, drop function runc, use run -N) Aug 29, 2026
@kolyshkin kolyshkin changed the title tests/int: revamp (add asserts, drop function runc, use run -N) tests/int: revamp (drop runc(), use run -N, add asserts) Aug 29, 2026
@kolyshkin
kolyshkin force-pushed the int-shim branch 2 times, most recently from 4d160e8 to a5cbc11 Compare August 29, 2026 02:47
@kolyshkin
kolyshkin requested review from lifubang and rata and removed request for rata September 1, 2026 00:07
@kolyshkin
kolyshkin force-pushed the int-shim branch 2 times, most recently from 1bf73d7 to 60daed2 Compare September 3, 2026 22:03
@kolyshkin

Copy link
Copy Markdown
Contributor Author

@AkihiroSuda @cyphar @thaJeztah @lifubang @rata PTAL (this changes our bats tests considerably, and so I have to rebase this manually every time we merge something involving bats tests). If you agree with the concept and the implementation, can we please merge this to reduce my load?

One note on reimplementing asserts vs using bats' own -- unfortunately, they don't come with bats-core and the installation is a real PITA, on the other hand the re-implementation is pretty straightforward and probably wouldn't change much. Yet if you don't like it, I can remove the last few commits which add/use asserts.

@thaJeztah

Copy link
Copy Markdown
Member

Sorry, looks like I missed the previous ping; are the failures expected, or something broken in the current PR?

Comment thread tests/integration/cpu_affinity.bats Outdated
@kolyshkin

kolyshkin commented Sep 11, 2026 •

Copy link
Copy Markdown
Contributor Author

Sorry, looks like I missed the previous ping; are the failures expected, or something broken in the current PR?

@thaJeztah It got broken because since it's been written we have added other tests (for example, in commit 5f76d4d), and they all use the old syntax (like runc ... ; [ $status -eq 1 ] etc instead of run -1 runc).

I am fixing this right now, but this is basically why I keep asking for reviews -- this changes the tests style slightly, and thus I need to maintain it until it's merged.

@kolyshkin
kolyshkin force-pushed the int-shim branch 2 times, most recently from 29d3a5d to 2cdc568 Compare September 11, 2026 04:52
@kolyshkin

Copy link
Copy Markdown
Contributor Author

I'd love this to be included into 1.6 (but not setting the milestone to not block 1.6-rc1 release); while it does touch runc directly (it's just CI), it will reshape the way we're writing the tests and I'd rather have it sooner than later (it's a big patch set and hard to keep updated as we move along).

PTAL @cyphar @thaJeztah @AkihiroSuda

@thaJeztah thaJeztah left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

When runc is used as the right hand side of a pipe, it runs in a
subshell, so the $status and $output set by bats' run helper (called
from the runc wrapper) do not propagate to the test. As a result, the
checks that follow such a call silently test the values left over from
the previous runc call.

Use a heredoc redirection instead of piping the heredoc in.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
We already have a function called runc, and adding a variable with the
same name, while not technically incorrect, does not help readability.

Fixes: a38f42a
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Until now, runc in integration tests was a bash function, wrapping the
actual binary to add the flags all tests need (--root and, sometimes,
--systemd-cgroup).

A function can not be used where a real binary is required, which is why
we also had setup_runc_cmdline and RUNC_CMDLINE, used by the tests that
run runc under taskset or in a separate mount namespace.

Add tests/integration/bin/runc, a small wrapper script doing the same
thing, and prepend its directory to PATH. This way runc can be used both
directly and after commands like taskset, nsenter, or timeout, and
RUNC_CMDLINE is no longer needed.

Note that the runc bash function still takes precedence for a plain
"runc ..." call in tests, so their behavior is unchanged.

The directory is always put first in PATH, and the runc found in PATH
is checked to be the wrapper, so that the tests can not silently use
some other runc binary instead.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
With this option, bats prints the value of $output for a failed test,
which is exactly what the sane_run wrapper does manually (and what the
next commit removes it for).

The option requires bats v1.7.0, so bump the minimum version. Our CI
uses v1.12.0 on GHA and builds the same version from source on EL8;
other platforms use their distro package, which is expected to be new
enough (and bats_require_minimum_version makes it obvious if it isn't).

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Now that runc is a real binary (a wrapper script in PATH), tests can
call it the way any other command is called, using bats' run helper
directly:

	run -0 runc start ctr

instead of the old

	runc start ctr
	[ "$status" -eq 0 ]

where runc was a bash function hiding a call to run. The exit code check
is now part of the call: -N for an expected exit code, ! for "any
failure", and no argument where the exit code is checked later or not at
all.

This has to be done in one go: while the runc function exists, "run runc"
would call it, resulting in a nested run.

Other changes made necessary or possible by this:

  - The runc and sane_run functions are gone. The output of a failed
    command is now printed by bats itself, see the previous commit.

  - __runc (a raw runc call, not using run) is now simply runc.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
A fair number of runc calls do not check the exit code at all, although
they should. Fix that.

Note that two of the checks added to update.bats expect an error (exit
code 1), as the test cases there are about runc rejecting a combination
of options.

The remaining calls that do not check the exit code are the ones that
check $status themselves (in an if, or against different values), the
one in a background subshell (where a failure can not be detected), and
the one that is explicitly documented as being allowed to fail.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
When a test fails on a string comparison, all we see is the failed
expression, which usually means adding some debug output and rerunning
the test to find out what the actual value was.

The bats-assert library solves this, but it (together with its
bats-support dependency) has to be installed separately on every distro
we test on, which is more trouble than it's worth for a few functions.

Add assert_output, refute_output, and assert_line, implementing a subset
of the bats-assert API (so that the tests read the same way, and this
code can be dropped should bats-assert ever be added as a dependency),
and use them for the comparisons against an exact value. Now, when such
a check fails, the test log shows what was expected and what was there:

	-- output does not match (exact) --
	expected: '/override'
	  actual: $'\0/override'
	--

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
The point of the assert helpers is that a failed test says what it
wanted and what it got, so leaving most comparisons as bare [[ ]]
defeats it.

Convert the rest of the checks on $output and $lines. Those using a glob
to look for a substring become --partial, the rest become --regexp (the
patterns are translated to extended regular expressions, and anchored
where the glob was).

The few remaining [[ ]] are not assertions: one is an if condition, and
another one is the left hand side of ||, offering an alternative to the
assert that follows it.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
The "Writing integration tests" section only pointed at helpers.bash,
which does not say much about how a test is supposed to be written.

Now that tests call runc via bats' run helper and check the output with
assert_output and friends, document that: how the expected exit code is
given to run, which assertions are available, and why they are preferred
over a bare test expression.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
@kolyshkin

Copy link
Copy Markdown
Contributor Author

A somewhat heavy rebase after merging #5455. I'd rather have this one merged (unless there are any objections) to avoid further rebase work. PTAL @lifubang @AkihiroSuda

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants