From 06eb27d50324223ef2d3a7f9cd0addaa721841de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 10 Dec 2021 23:49:48 +0100 Subject: [PATCH] tests: Run KMS tests inside a QEMU virtual machine This commit makes it possible to run test executables in a test environment constructed of a virtual machine running the Linux kernel with the virtual KMS driver enabled, and a mocked system environment using meta-dbus-runner.py/python-dbusmock. The qemu machine is configured to use 256M of memory, as the default 128M was not enough for the tests to pass. Using qemu is also only made possible on x86_64; more changes are needed for it to be runnable on aarch64, so add a warning if it was enabled on any other architecture. Part-of: --- meson.build | 11 +++++ meson_options.txt | 12 ++++++ src/tests/kvm/README.md | 29 +++++++++++++ src/tests/kvm/build-linux.sh | 74 ++++++++++++++++++++++++++++++++ src/tests/kvm/kernel-version.txt | 1 + src/tests/kvm/meson.build | 48 +++++++++++++++++++++ src/tests/kvm/run-kvm-test.sh | 23 ++++++++++ src/tests/kvm/virtme-run.sh | 25 +++++++++++ src/tests/meson.build | 19 +++++--- 9 files changed, 235 insertions(+), 7 deletions(-) create mode 100644 src/tests/kvm/README.md create mode 100755 src/tests/kvm/build-linux.sh create mode 100644 src/tests/kvm/kernel-version.txt create mode 100644 src/tests/kvm/meson.build create mode 100755 src/tests/kvm/run-kvm-test.sh create mode 100755 src/tests/kvm/virtme-run.sh diff --git a/meson.build b/meson.build index 2cadd4987..63372c2ba 100644 --- a/meson.build +++ b/meson.build @@ -57,6 +57,7 @@ sysprof_req = '>= 3.37.2' gnome = import('gnome') pkg = import('pkgconfig') i18n = import('i18n') +fs = import('fs') cc = meson.get_compiler('c') prefix = get_option('prefix') @@ -269,6 +270,7 @@ have_core_tests = false have_cogl_tests = false have_clutter_tests = false have_native_tests = false +have_kvm_tests = false have_installed_tests = false if have_tests @@ -287,6 +289,15 @@ if have_tests error('Native tests require remote desktop') endif endif + have_kvm_tests = get_option('kvm_tests') + if have_kvm_tests + if not have_native_backend + error('KVM tests need the native backend tests') + endif + if host_machine.cpu_family() != 'x86_64' + error('KVM tests are only supported on x86_64') + endif + endif have_cogl_tests = get_option('cogl_tests') have_clutter_tests = get_option('clutter_tests') diff --git a/meson_options.txt b/meson_options.txt index 6609e4332..12457d261 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -141,6 +141,18 @@ option('tests', description: 'Enable tests globally. Specific test suites can be controlled with core_tests, clutter_tests, and cogl_tests' ) +option('kvm_tests', + type: 'boolean', + value: false, + description: 'Enable running certain tests in a virtual machine with a custom built kernel' +) + +option('kvm_kernel_image', + type: 'string', + value: '', + description: 'Path to a Linux kernel image to be used for KVM testing' +) + option('profiler', type: 'boolean', value: true, diff --git a/src/tests/kvm/README.md b/src/tests/kvm/README.md new file mode 100644 index 000000000..336b3df5e --- /dev/null +++ b/src/tests/kvm/README.md @@ -0,0 +1,29 @@ +## High level description of the files in this directory. + +### build-linux.sh + +Builds a Linux kernel image meant to be launched using qemu. Doesn't make any +assumptions about configuration other than that. It uses the drm kernel tree. +It's used from meson.build. + +### kernel-version.txt + +Describes the version of the Linux kernel to use; usually a tag. It's a +separate file so that changing the version will make meson build a new kernel +image. + +### virtme-run.sh + +A helper script that uses 'virtme' to launch a qemu virtual machine with the +host filesystem exposed inside the virtual machine. + +### run-kvm-test.sh + +Runs the passed test executable in a mocked environment using +'meta-dbus-runner.py' (which uses python-dbusmock to create a mocked system +environment. + +### meson.build + +Contains one rule for building the Linux kernel image, and meson test cases +that launches tests inside virtual machines. diff --git a/src/tests/kvm/build-linux.sh b/src/tests/kvm/build-linux.sh new file mode 100755 index 000000000..49f622a56 --- /dev/null +++ b/src/tests/kvm/build-linux.sh @@ -0,0 +1,74 @@ +#!/bin/bash +# +# Script for building the Linux kernel from git. It aims to build a kernel image +# that is suitable for running in a virtual machine and is aimed to used for +# testing. +# +# Usage: build-linux.sh [REPO-URL] [BRANCH|TAG] [OUTPUT-FILE] [...CONFIGS] +# +# Where [..CONFIGS] can be any number of configuration options, e.g. +# --enable CONFIG_DRM_VKMS + +set -e + +# From scripts/subarch.include in linux +function get-subarch() +{ + uname -m | sed -e s/i.86/x86/ \ + -e s/x86_64/x86/ \ + -e s/sun4u/sparc64/ \ + -e s/arm.*/arm/ -e s/sa110/arm/ \ + -e s/s390x/s390/ -e s/parisc64/parisc/ \ + -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ + -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ \ + -e s/riscv.*/riscv/ +} + +REPO="$1" +BRANCH_OR_TAG="$(cat $2)" +IMAGE="$3" + +ARCH=$(uname -m) +SUBARCH=$(get-subarch) + +shift +shift +shift + +# ./scripts/config --enable CONFIG_DRM_VKMS +CONFIGS=() +while [[ "x$1" != "x" ]]; do + CONFIGS+=( "$1" ) + shift +done + +echo Building Linux for $ARCH \($SUBARCH\)... + +set -x + +if [ -d linux ]; then + pushd linux + git fetch $REPO $BRANCH_OR_TAG + git checkout FETCH_HEAD +else + git clone --depth=1 --branch=$BRANCH_OR_TAG $REPO linux + pushd linux +fi + +make defconfig +sync +make kvm_guest.config + +echo Enabling ${CONFIGS[@]}... +./scripts/config ${CONFIGS[@]/#/--enable } + +make oldconfig +make -j8 + +popd + +TARGET_DIR="$(dirname "$IMAGE")" +mkdir -p "$TARGET_DIR" +mv linux/arch/$SUBARCH/boot/bzImage "$IMAGE" +mv linux/.config $TARGET_DIR/.config +#rm -rf linux diff --git a/src/tests/kvm/kernel-version.txt b/src/tests/kvm/kernel-version.txt new file mode 100644 index 000000000..5aeaf910f --- /dev/null +++ b/src/tests/kvm/kernel-version.txt @@ -0,0 +1 @@ +drm-next-2021-11-12 diff --git a/src/tests/kvm/meson.build b/src/tests/kvm/meson.build new file mode 100644 index 000000000..cd8725912 --- /dev/null +++ b/src/tests/kvm/meson.build @@ -0,0 +1,48 @@ +build_linux = find_program('build-linux.sh') + +kernel_image_path = get_option('kvm_kernel_image') +if kernel_image_path != '' + if not fs.is_absolute(kernel_image_path) + error('Kernel image path @0@ must be absolute'.format(kernel_image_path)) + endif + if not fs.is_file(kernel_image_path) + error('Kernel image @0@ does not exist'.format(kernel_image_path)) + endif + kernel_image_target = [] +else + kernel_image_target = custom_target('linux-kernel', + output: 'bzImage', + input: 'kernel-version.txt', + console: true, + command: [ + build_linux, + 'https://anongit.freedesktop.org/git/drm/drm.git', + '@INPUT@', + '@OUTPUT@', + '--enable', 'CONFIG_DRM_VKMS', + ] + ) + kernel_image_path = kernel_image_target.full_path() +endif + +virtme_run = find_program('virtme-run.sh') + +foreach test: privileged_tests + test_name = test[0] + test_executable = test[1] + + test('kvm-' + test_name, virtme_run, + suite: ['core', 'mutter/native/kvm'], + depends: [ + kernel_image_target, + ], + workdir: mutter_srcdir, + args: [ + kernel_image_path, + meta_dbus_runner.full_path(), + '--kvm', + test_executable.full_path(), + meson.current_build_dir(), + ] + ) +endforeach diff --git a/src/tests/kvm/run-kvm-test.sh b/src/tests/kvm/run-kvm-test.sh new file mode 100755 index 000000000..a6fa901ec --- /dev/null +++ b/src/tests/kvm/run-kvm-test.sh @@ -0,0 +1,23 @@ +#!/usr/bin/bash + +set -e + +WRAPPER="$1" +WRAPPER_ARGS="$2" +TEST_EXECUTABLE="$3" +TEST_RESULT="$4" + +export XDG_RUNTIME_DIR="/tmp/sub-runtime-dir-$UID" +export GSETTINGS_SCHEMA_DIR="$PWD/build/data" +export G_SLICE="always-malloc" +export MALLOC_CHECK_="3" +export NO_AT_BRIDGE="1" +export MALLOC_PERTURB_="123" + +mkdir -p -m 700 $XDG_RUNTIME_DIR + +glib-compile-schemas $GSETTINGS_SCHEMA_DIR + +"$WRAPPER" $WRAPPER_ARGS "$TEST_EXECUTABLE" + +echo $? > $TEST_RESULT diff --git a/src/tests/kvm/virtme-run.sh b/src/tests/kvm/virtme-run.sh new file mode 100755 index 000000000..6b877f1d6 --- /dev/null +++ b/src/tests/kvm/virtme-run.sh @@ -0,0 +1,25 @@ +#!/usr/bin/bash + +set -e + +DIRNAME="$(dirname "$0")" +IMAGE="$1" +WRAPPER="$2" +WRAPPER_ARGS="$3" +TEST_EXECUTABLE="$4" +TEST_BUILD_DIR="$5" + +TEST_RESULT_FILE=$(mktemp -p "$TEST_BUILD_DIR" -t test-result-XXXXXX) +echo 1 > "$TEST_RESULT_FILE" + +virtme-run \ + --memory=256M \ + --rw \ + --pwd \ + --kimg "$IMAGE" \ + --script-sh "sh -c \"env HOME=$HOME $DIRNAME/run-kvm-test.sh \\\"$WRAPPER\\\" \\\"$WRAPPER_ARGS\\\" \\\"$TEST_EXECUTABLE\\\" \\\"$TEST_RESULT_FILE\\\"\"" + +TEST_RESULT="$(cat "$TEST_RESULT_FILE")" +rm "$TEST_RESULT_FILE" + +exit "$TEST_RESULT" diff --git a/src/tests/meson.build b/src/tests/meson.build index 02460b5f3..0a0fa7a80 100644 --- a/src/tests/meson.build +++ b/src/tests/meson.build @@ -117,6 +117,8 @@ test_runner = executable('mutter-test-runner', install_dir: mutter_installed_tests_libexecdir, ) +meta_dbus_runner = find_program('meta-dbus-runner.py') + if have_installed_tests install_data('meta-dbus-runner.py', install_dir: mutter_installed_tests_libexecdir, @@ -391,11 +393,14 @@ if have_native_tests is_parallel: false, timeout: 60, ) - - test('native-kms-render', native_kms_render_tests, - suite: ['core', 'mutter/native/kms/render'], - env: test_env, - is_parallel: false, - timeout: 60, - ) +endif + +if have_kvm_tests + privileged_tests = [ + [ 'kms-render', native_kms_render_tests ], + ] + + if have_kvm_tests + subdir('kvm') + endif endif