mirror of
https://github.com/systemd/systemd.git
synced 2025-01-12 13:18:14 +03:00
Merge pull request #32121 from CodethinkLabs/basic-mkosi-integration-tests
Basic mkosi integration tests
This commit is contained in:
commit
0c8bda7dc3
12
meson.build
12
meson.build
@ -2573,6 +2573,18 @@ endif
|
|||||||
|
|
||||||
#####################################################################
|
#####################################################################
|
||||||
|
|
||||||
|
if get_option('integration-tests') != false
|
||||||
|
system_mkosi = custom_target('system_mkosi',
|
||||||
|
build_always_stale : true,
|
||||||
|
output : 'system',
|
||||||
|
console : true,
|
||||||
|
command : ['mkosi', '-C', meson.project_source_root(), '--image=system', '--format=disk', '--output-dir', meson.project_build_root() / '@OUTPUT@', '--without-tests', '-fi', 'build'],
|
||||||
|
depends : [executables_by_name['bootctl'], executables_by_name['systemd-measure'], executables_by_name['systemd-repart'], ukify],
|
||||||
|
)
|
||||||
|
endif
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
|
||||||
subdir('rules.d')
|
subdir('rules.d')
|
||||||
subdir('test')
|
subdir('test')
|
||||||
|
|
||||||
|
@ -498,6 +498,8 @@ option('install-tests', type : 'boolean', value : false,
|
|||||||
description : 'install test executables')
|
description : 'install test executables')
|
||||||
option('log-message-verification', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' },
|
option('log-message-verification', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' },
|
||||||
description : 'do fake printf() calls to verify format strings')
|
description : 'do fake printf() calls to verify format strings')
|
||||||
|
option('integration-tests', type : 'boolean', value : false,
|
||||||
|
description : 'run the integration tests')
|
||||||
|
|
||||||
option('ok-color', type : 'combo',
|
option('ok-color', type : 'combo',
|
||||||
choices : ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan',
|
choices : ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan',
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
|
||||||
[Config]
|
[Config]
|
||||||
Images=system
|
@Images=system
|
||||||
MinimumVersion=23~devel
|
MinimumVersion=23~devel
|
||||||
|
|
||||||
[Output]
|
[Output]
|
||||||
@ -21,6 +21,7 @@ BuildSourcesEphemeral=yes
|
|||||||
@Incremental=yes
|
@Incremental=yes
|
||||||
@RuntimeSize=8G
|
@RuntimeSize=8G
|
||||||
@RuntimeBuildSources=yes
|
@RuntimeBuildSources=yes
|
||||||
|
@QemuSmp=2
|
||||||
ToolsTreePackages=virtiofsd
|
ToolsTreePackages=virtiofsd
|
||||||
KernelCommandLineExtra=systemd.crash_shell
|
KernelCommandLineExtra=systemd.crash_shell
|
||||||
systemd.log_level=debug,console:info
|
systemd.log_level=debug,console:info
|
||||||
@ -33,7 +34,7 @@ KernelCommandLineExtra=systemd.crash_shell
|
|||||||
rw
|
rw
|
||||||
# Lower the default device timeout so we get a shell earlier if the root device does
|
# Lower the default device timeout so we get a shell earlier if the root device does
|
||||||
# not appear for some reason.
|
# not appear for some reason.
|
||||||
systemd.default_device_timeout_sec=10
|
systemd.default_device_timeout_sec=20
|
||||||
# Make sure no LSMs are enabled by default.
|
# Make sure no LSMs are enabled by default.
|
||||||
apparmor=0
|
apparmor=0
|
||||||
selinux=0
|
selinux=0
|
||||||
|
@ -5,6 +5,9 @@
|
|||||||
|
|
||||||
[Content]
|
[Content]
|
||||||
Autologin=yes
|
Autologin=yes
|
||||||
|
ExtraTrees=
|
||||||
|
%D/mkosi.crt:/usr/lib/verity.d/mkosi.crt # sysext verification key
|
||||||
|
|
||||||
Packages=
|
Packages=
|
||||||
acl
|
acl
|
||||||
bash-completion
|
bash-completion
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
[Service]
|
||||||
|
PassEnvironment=SYSTEMD_UNIT_PATH
|
@ -28,6 +28,22 @@ To run just one of the cases:
|
|||||||
|
|
||||||
$ sudo make -C test/TEST-01-BASIC clean setup run
|
$ sudo make -C test/TEST-01-BASIC clean setup run
|
||||||
|
|
||||||
|
To run the meson-based integration test config
|
||||||
|
enable integration tests and options for required commands with the following:
|
||||||
|
|
||||||
|
$ meson configure build -Dintegration-tests=true -Dremote=enabled -Dopenssl=enabled -Dblkid=enabled -Dtpm2=enabled
|
||||||
|
|
||||||
|
Once enabled the integration tests can be run with:
|
||||||
|
|
||||||
|
$ sudo meson test -C build/ --suite integration-tests --num-processes "$((nproc / 2))"
|
||||||
|
|
||||||
|
As usual, specific tests can be run in meson by appending the name of the test
|
||||||
|
which is usually the name of the directory e.g.
|
||||||
|
|
||||||
|
$ sudo meson test -C build/ --suite integration-tests --num-processes "$((nproc / 2))" TEST-01-BASIC
|
||||||
|
|
||||||
|
See `meson introspect build --tests` for a list of tests.
|
||||||
|
|
||||||
Specifying the build directory
|
Specifying the build directory
|
||||||
==============================
|
==============================
|
||||||
|
|
||||||
|
13
test/TEST-02-UNITTESTS/meson.build
Normal file
13
test/TEST-02-UNITTESTS/meson.build
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
test_params += {
|
||||||
|
'mkosi_args': test_params['mkosi_args'] + [
|
||||||
|
'--kernel-command-line-extra=' + ' '.join([
|
||||||
|
'''
|
||||||
|
frobnicate!
|
||||||
|
|
||||||
|
systemd.setenv=TEST_CMDLINE_NEWLINE=foo
|
||||||
|
systemd.setenv=TEST_CMDLINE_NEWLINE=bar
|
||||||
|
|
||||||
|
''',
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
}
|
134
test/integration_test_wrapper.py
Executable file
134
test/integration_test_wrapper.py
Executable file
@ -0,0 +1,134 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
|
||||||
|
'''Test wrapper command for driving integration tests.
|
||||||
|
|
||||||
|
Note: This is deliberately rough and only intended to drive existing tests
|
||||||
|
with the expectation that as part of formally defining the API it will be tidy.
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
import shlex
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
|
TEST_EXIT_DROPIN = """\
|
||||||
|
[Unit]
|
||||||
|
SuccessAction=exit
|
||||||
|
FailureAction=exit
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
EMERGENCY_EXIT_DROPIN = """\
|
||||||
|
[Unit]
|
||||||
|
Wants=emergency-exit.service
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
EMERGENCY_EXIT_SERVICE = """\
|
||||||
|
[Unit]
|
||||||
|
DefaultDependencies=no
|
||||||
|
Conflicts=shutdown.target
|
||||||
|
Conflicts=rescue.service
|
||||||
|
Before=shutdown.target
|
||||||
|
Before=rescue.service
|
||||||
|
FailureAction=exit
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=false
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
|
parser.add_argument('--test-name', required=True)
|
||||||
|
parser.add_argument('--mkosi-image-name', required=True)
|
||||||
|
parser.add_argument('--mkosi-output-path', required=True, type=Path)
|
||||||
|
parser.add_argument('--test-number', required=True)
|
||||||
|
parser.add_argument('--no-emergency-exit',
|
||||||
|
dest='emergency_exit', default=True, action='store_false',
|
||||||
|
help="Disable emergency exit drop-ins for interactive debugging")
|
||||||
|
parser.add_argument('mkosi_args', nargs="*")
|
||||||
|
|
||||||
|
def main():
|
||||||
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
test_unit_name = f"testsuite-{args.test_number}.service"
|
||||||
|
# Machine names shouldn't have / since it's used as a file name
|
||||||
|
# and it must be a valid hostname so 64 chars max
|
||||||
|
machine_name = args.test_name.replace('/', '_')[:64]
|
||||||
|
|
||||||
|
logging.debug(f"test name: {args.test_name}\n"
|
||||||
|
f"test number: {args.test_number}\n"
|
||||||
|
f"image: {args.mkosi_image_name}\n"
|
||||||
|
f"mkosi output path: {args.mkosi_output_path}\n"
|
||||||
|
f"mkosi args: {args.mkosi_args}\n"
|
||||||
|
f"emergency exit: {args.emergency_exit}")
|
||||||
|
|
||||||
|
journal_file = Path(f"{machine_name}.journal").absolute()
|
||||||
|
logging.info(f"Capturing journal to {journal_file}")
|
||||||
|
|
||||||
|
mkosi_args = [
|
||||||
|
'mkosi',
|
||||||
|
'--directory', Path('..').resolve(),
|
||||||
|
'--output-dir', args.mkosi_output_path.absolute(),
|
||||||
|
'--machine', machine_name,
|
||||||
|
'--image', args.mkosi_image_name,
|
||||||
|
'--format=disk',
|
||||||
|
'--runtime-build-sources=no',
|
||||||
|
'--ephemeral',
|
||||||
|
'--forward-journal', journal_file,
|
||||||
|
*(
|
||||||
|
[
|
||||||
|
'--credential',
|
||||||
|
f"systemd.extra-unit.emergency-exit.service={shlex.quote(EMERGENCY_EXIT_SERVICE)} "
|
||||||
|
f"systemd.unit-dropin.emergency.target={shlex.quote(EMERGENCY_EXIT_DROPIN)}",
|
||||||
|
]
|
||||||
|
if args.emergency_exit
|
||||||
|
else []
|
||||||
|
),
|
||||||
|
f"--credential=systemd.unit-dropin.{test_unit_name}={shlex.quote(TEST_EXIT_DROPIN)}",
|
||||||
|
'--append',
|
||||||
|
'--kernel-command-line-extra',
|
||||||
|
' '.join([
|
||||||
|
'systemd.hostname=H',
|
||||||
|
f"SYSTEMD_UNIT_PATH=/usr/lib/systemd/tests/testdata/testsuite-{args.test_number}.units:/usr/lib/systemd/tests/testdata/units:",
|
||||||
|
'systemd.unit=testsuite.target',
|
||||||
|
f"systemd.wants={test_unit_name}",
|
||||||
|
]),
|
||||||
|
*args.mkosi_args,
|
||||||
|
]
|
||||||
|
|
||||||
|
mkosi_args += ['qemu']
|
||||||
|
|
||||||
|
logging.debug(f"Running {shlex.join(os.fspath(a) for a in mkosi_args)}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
subprocess.run(mkosi_args, check=True)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
if e.returncode not in (0, 77):
|
||||||
|
suggested_command = [
|
||||||
|
'journalctl',
|
||||||
|
'--all',
|
||||||
|
'--no-hostname',
|
||||||
|
'-o', 'short-monotonic',
|
||||||
|
'--file', journal_file,
|
||||||
|
f"_SYSTEMD_UNIT={test_unit_name}",
|
||||||
|
'+', f"SYSLOG_IDENTIFIER=testsuite-{args.test_number}.sh",
|
||||||
|
'+', 'PRIORITY=4',
|
||||||
|
'+', 'PRIORITY=3',
|
||||||
|
'+', 'PRIORITY=2',
|
||||||
|
'+', 'PRIORITY=1',
|
||||||
|
'+', 'PRIORITY=0',
|
||||||
|
]
|
||||||
|
logging.info("Test failed, relevant logs can be viewed with: "
|
||||||
|
f"{shlex.join(os.fspath(a) for a in suggested_command)}")
|
||||||
|
exit(e.returncode)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
@ -331,3 +331,44 @@ if want_tests != 'false' and conf.get('ENABLE_KERNEL_INSTALL') == 1
|
|||||||
depends : deps,
|
depends : deps,
|
||||||
suite : 'kernel-install')
|
suite : 'kernel-install')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
if get_option('integration-tests') != false
|
||||||
|
integration_test_wrapper = find_program('integration_test_wrapper.py')
|
||||||
|
integration_tests = {
|
||||||
|
'01': 'TEST-01-BASIC',
|
||||||
|
'02': 'TEST-02-UNITTESTS',
|
||||||
|
}
|
||||||
|
foreach test_number, dirname : integration_tests
|
||||||
|
test_unit_name = f'testsuite-@test_number@.service'
|
||||||
|
test_params = {
|
||||||
|
'test_name' : dirname,
|
||||||
|
'mkosi_image_name' : 'system',
|
||||||
|
'mkosi_output_path' : system_mkosi,
|
||||||
|
'test_number' : test_number,
|
||||||
|
'mkosi_args' : [],
|
||||||
|
'depends' : [system_mkosi],
|
||||||
|
'timeout' : 600,
|
||||||
|
}
|
||||||
|
|
||||||
|
# TODO: This fs.exists call isn't included in rebuild logic
|
||||||
|
# so if you add a new meson.build in a subdir
|
||||||
|
# you need to touch another build file to get it to reparse.
|
||||||
|
if fs.exists(dirname / 'meson.build')
|
||||||
|
subdir(dirname)
|
||||||
|
endif
|
||||||
|
args = ['--test-name', test_params['test_name'],
|
||||||
|
'--mkosi-image-name', test_params['mkosi_image_name'],
|
||||||
|
'--mkosi-output-path', test_params['mkosi_output_path'],
|
||||||
|
'--test-number', test_params['test_number']]
|
||||||
|
args += ['--'] + test_params['mkosi_args']
|
||||||
|
test(test_params['test_name'],
|
||||||
|
integration_test_wrapper,
|
||||||
|
env: test_env,
|
||||||
|
args : args,
|
||||||
|
depends : test_params['depends'],
|
||||||
|
timeout : test_params['timeout'],
|
||||||
|
suite : 'integration-tests')
|
||||||
|
endforeach
|
||||||
|
endif
|
||||||
|
Loading…
Reference in New Issue
Block a user