Add support for running tests that require a specific runner.
The test is specified via a tuple (name, runner, protocol), where name
is the test name as found in the tests/functional directory without the
'test_' prefix and the .py extension, runner is an array containing the
runner and any arguments required by the runner, and protocol is
the test protocol used by Meson to determine whether the test passed or
failed.
The test tuples are added to arrays that follow the current naming
logic but with the suffix '_with_runner' appended to their names. In
Meson it's not easy to select an element in an array at runtime based on
its type, so it's simpler to have a new array for these new test types
than use the current ones from the tests that don't require a runner,
and so avoid mixing strings and tuples in the same array.
Currently there is only one runner, the GDB runner, but more runners can
be defined and associated to a test via the tuple.
The GDB runner is only defined if GDB is detected. The probe is done
in 'configure' and the full path is passed to meson.build via the -Dgdb=
option.
Signed-off-by: Gustavo Romero <gustavo.romero@linaro.org>
---
configure | 2 ++
meson.build | 4 +++
meson_options.txt | 2 ++
scripts/meson-buildoptions.sh | 2 ++
tests/functional/meson.build | 65 +++++++++++++++++++++++++++++++++++
5 files changed, 75 insertions(+)
diff --git a/configure b/configure
index 274a778764..8e2e2cd562 100755
--- a/configure
+++ b/configure
@@ -1978,6 +1978,8 @@ if test "$skip_meson" = no; then
test -n "${LIB_FUZZING_ENGINE+xxx}" && meson_option_add "-Dfuzzing_engine=$LIB_FUZZING_ENGINE"
test "$plugins" = yes && meson_option_add "-Dplugins=true"
test "$tcg" != enabled && meson_option_add "-Dtcg=$tcg"
+ test -n "$gdb_bin" && meson_option_add "-Dgdb=$gdb_bin"
+
run_meson() {
NINJA=$ninja $meson setup "$@" "$PWD" "$source_path"
}
diff --git a/meson.build b/meson.build
index 0d42de61ae..7e0afe8288 100644
--- a/meson.build
+++ b/meson.build
@@ -75,6 +75,10 @@ have_user = have_linux_user or have_bsd_user
sh = find_program('sh')
python = import('python').find_installation()
+# Meson python.get_path() on 'purelib' or 'platlib' doesn't properly return the
+# site-packages dir in pyvenv, so it is built manually.
+python_ver = python.language_version()
+python_site_packages = meson.build_root() / 'pyvenv/lib/python' + python_ver / 'site-packages'
cc = meson.get_compiler('c')
all_languages = ['c']
diff --git a/meson_options.txt b/meson_options.txt
index fff1521e58..5bb41bcbc4 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -36,6 +36,8 @@ option('trace_file', type: 'string', value: 'trace',
option('coroutine_backend', type: 'combo',
choices: ['ucontext', 'sigaltstack', 'windows', 'wasm', 'auto'],
value: 'auto', description: 'coroutine backend to use')
+option('gdb', type: 'string', value: '',
+ description: 'Path to GDB')
# Everything else can be set via --enable/--disable-* option
# on the configure script command line. After adding an option
diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh
index 0ebe6bc52a..f4bd21220e 100644
--- a/scripts/meson-buildoptions.sh
+++ b/scripts/meson-buildoptions.sh
@@ -58,6 +58,7 @@ meson_options_help() {
printf "%s\n" ' --enable-ubsan enable undefined behaviour sanitizer'
printf "%s\n" ' --firmwarepath=VALUES search PATH for firmware files [share/qemu-'
printf "%s\n" ' firmware]'
+ printf "%s\n" ' --gdb=VALUE Path to GDB'
printf "%s\n" ' --iasl=VALUE Path to ACPI disassembler'
printf "%s\n" ' --includedir=VALUE Header file directory [include]'
printf "%s\n" ' --interp-prefix=VALUE where to find shared libraries etc., use %M for'
@@ -323,6 +324,7 @@ _meson_option_parse() {
--disable-fuzzing) printf "%s" -Dfuzzing=false ;;
--enable-gcrypt) printf "%s" -Dgcrypt=enabled ;;
--disable-gcrypt) printf "%s" -Dgcrypt=disabled ;;
+ --gdb=*) quote_sh "-Dgdb=$2" ;;
--enable-gettext) printf "%s" -Dgettext=enabled ;;
--disable-gettext) printf "%s" -Dgettext=disabled ;;
--enable-gio) printf "%s" -Dgio=enabled ;;
diff --git a/tests/functional/meson.build b/tests/functional/meson.build
index 2a0c5aa141..febd31a263 100644
--- a/tests/functional/meson.build
+++ b/tests/functional/meson.build
@@ -9,6 +9,25 @@ if get_option('tcg_interpreter')
subdir_done()
endif
+# Define the GDB runner if GDB is available.
+gdb = get_option('gdb')
+if gdb != ''
+ gdb_runner_script = meson.project_source_root() + '/tests/guest-debug/run-test.py'
+ gdb_runner = [gdb_runner_script, '--quiet', '--gdb', gdb, '--test']
+
+ message('GDB runner defined based on GDB found at: ', gdb)
+
+ # A test with a runner is a tuple (name, runner, protocol).
+ # The tests must be elements of an array named like:
+ #
+ # test_<arch>_<mode=[system|linuxuser|bsduser]>_<speed=[quick|thorough]>_with_runner = [
+ # ['test0', gdb_runner, 'exitcode'],
+ # ...
+ # ]
+else
+ message('GDB not found, skipping functional tests that rely on it.')
+endif
+
subdir('aarch64')
subdir('alpha')
subdir('arm')
@@ -61,9 +80,11 @@ foreach speed : ['quick', 'thorough']
suites = ['func-quick', 'func-' + target_base]
target_tests = get_variable('tests_' + target_base + '_' + sysmode + '_quick', []) \
+ get_variable('tests_generic_' + sysmode)
+ target_tests_r = get_variable('tests_' + target_base + '_' + sysmode + '_quick_with_runner', [])
else
suites = ['func-' + speed, 'func-' + target_base + '-' + speed, speed]
target_tests = get_variable('tests_' + target_base + '_' + sysmode + '_' + speed, [])
+ target_tests_r = get_variable('tests_' + target_base + '_' + sysmode + '_' + speed + '_with_runner', [])
endif
test_deps = [roms, keymap_targets]
@@ -121,6 +142,50 @@ foreach speed : ['quick', 'thorough']
priority: time_out,
suite: suites)
endforeach
+
+ # Prepare tests that require a specific runner.
+ foreach test : target_tests_r
+ testname = '@0@-@1@'.format(target_base, test[0])
+ testfile = target_base / 'test_' + test[0] + '.py'
+ testpath = meson.current_source_dir() / testfile
+ teststamp = testname + '.tstamp'
+ testrunner = test[1]
+ testproto = test[2]
+
+ # python_site_packages, i.e., site packages from Python in pyvenv, is
+ # added to PYTHONPATH because some runners can run a program that has its
+ # own Python hooks that, by its turn, will search for modules based on
+ # PYTHONPATH independently of the Python used by the runner, like, for
+ # example, GDB using libpython.
+ test_r_precache_env = test_precache_env
+ test_r_precache_env.append('PYTHONPATH', python_site_packages)
+ # For similar reasons, PYTHONPATH must also include the path to the test
+ # scripts, otherwise unittest's introspection will failed.
+ test_r_precache_env.append('PYTHONPATH', meson.current_source_dir() / target_base)
+
+ precache = custom_target('func-precache-' + testname,
+ output: teststamp,
+ command: [testrunner, testpath],
+ depend_files: files(testpath),
+ build_by_default: false,
+ env: test_r_precache_env)
+ precache_all += precache
+
+ # See comments above about PYTHONPATH in test_r_precache_env.
+ test_r_env = test_env
+ test_r_env.append('PYTHONPATH', python_site_packages)
+ test_r_env.append('PYTHONPATH', meson.current_source_dir() / target_base)
+
+ test('func-' + testname,
+ python,
+ depends: [test_deps, test_emulator, emulator_modules, plugin_modules],
+ env: test_r_env,
+ args: [testrunner, testpath],
+ protocol: testproto,
+ timeout: time_out,
+ priority: time_out,
+ suite: suites)
+ endforeach
endforeach
endforeach
--
2.34.1
© 2016 - 2025 Red Hat, Inc.