[mutter] tests: Run KMS tests inside a QEMU virtual machine



commit 06eb27d50324223ef2d3a7f9cd0addaa721841de
Author: Jonas Ã…dahl <jadahl gmail com>
Date:   Fri Dec 10 23:49:48 2021 +0100

    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: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2151>

 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            | 17 +++++----
 9 files changed, 234 insertions(+), 6 deletions(-)
---
diff --git a/meson.build b/meson.build
index 2cadd49877..63372c2ba5 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 6609e43321..12457d2614 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 0000000000..336b3df5e4
--- /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 0000000000..49f622a567
--- /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 0000000000..5aeaf910f3
--- /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 0000000000..cd87259129
--- /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 0000000000..a6fa901ec4
--- /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 0000000000..6b877f1d63
--- /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 02460b5f35..0a0fa7a804 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,
   )
+endif
 
-  test('native-kms-render', native_kms_render_tests,
-    suite: ['core', 'mutter/native/kms/render'],
-    env: test_env,
-    is_parallel: false,
-    timeout: 60,
-  )
+if have_kvm_tests
+  privileged_tests = [
+    [ 'kms-render', native_kms_render_tests ],
+  ]
+
+  if have_kvm_tests
+    subdir('kvm')
+  endif
 endif


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]