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.

Signed-off-by: Gustavo Romero <gustavo.rom...@linaro.org>
---
 meson.build                  |  4 +++
 tests/functional/meson.build | 62 ++++++++++++++++++++++++++++++++++++
 2 files changed, 66 insertions(+)

diff --git a/meson.build b/meson.build
index 50c774a195..8d482f0809 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/tests/functional/meson.build b/tests/functional/meson.build
index 311c6f1806..1f70b70fd4 100644
--- a/tests/functional/meson.build
+++ b/tests/functional/meson.build
@@ -349,6 +349,23 @@ tests_xtensa_system_thorough = [
   'xtensa_replay',
 ]
 
+# Tests that require a specific runner.
+gdb = find_program('gdb-multiarch', required: false)
+if gdb.found()
+    gdb_runner_script =  meson.project_source_root() + 
'/tests/guest-debug/run-test.py'
+    gdb_runner = [gdb_runner_script, '--gdb', gdb, '--test']
+
+    # 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 multiarch not found, skipping functional tests that rely on 
it.')
+endif
+
 precache_all = []
 foreach speed : ['quick', 'thorough']
   foreach dir : target_dirs
@@ -372,9 +389,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]
@@ -423,6 +442,49 @@ foreach speed : ['quick', 'thorough']
            priority: test_timeouts.get(test, 90),
            suite: suites)
     endforeach
+
+    # Prepare tests that require a specific runner.
+    foreach test : target_tests_r
+      testname = '@0@-@1@'.format(target_base, test[0])
+      testfile = 'test_' + test[0] + '.py'
+      testpath = meson.current_source_dir() / testfile
+      teststamp = testname + '.tstamp'
+      testrunner  = test[1]
+      testproto = test[2]
+
+      test_precache_env = environment()
+      test_precache_env.set('QEMU_TEST_PRECACHE', meson.current_build_dir() / 
teststamp)
+      # 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_precache_env.set('PYTHONPATH', meson.project_source_root() / 
'python' +
+                                          ':' + meson.current_source_dir() +
+                                          ':' + python_site_packages)
+      precache = custom_target('func-precache-' + testname,
+                               output: teststamp,
+                               command: [testrunner, testpath],
+                               depend_files: files(testpath),
+                               build_by_default: false,
+                               env: test_precache_env)
+      precache_all += precache
+
+      # See comment above about python_site_packages in test_precache_env.
+      # Don't append to test_env since it will affect previous uses of it.
+      test_r_env = test_env
+      test_r_env.append('PYTHONPATH', python_site_packages)
+
+      test('func-' + testname,
+           python,
+           depends: [test_deps, test_emulator, emulator_modules, 
plugin_modules],
+           env: test_r_env,
+           args: [testrunner, testpath],
+           protocol: testproto,
+           timeout: test_timeouts.get(test[0], 90),
+           priority: test_timeouts.get(test[0], 90),
+           suite: suites)
+    endforeach
   endforeach
 endforeach
 
-- 
2.34.1


Reply via email to