From 718941f3cf7274288f249993c6f86a0230c797d6 Mon Sep 17 00:00:00 2001 From: Ciro Santilli Date: Tue, 22 Jan 2019 00:00:00 +0000 Subject: [PATCH] test-modules: convert to use LkmcCliFunction --- README.adoc | 18 ++++++----- rootfs_overlay/test_all.sh | 40 ++++++++++++----------- rootfs_overlay/test_fail.sh | 4 +++ run | 7 ++-- test | 4 +-- test-modules | 7 ---- test-user-mode | 64 +++++++++++++++++++++++++++++++++++++ test-userland | 45 ++++---------------------- 8 files changed, 112 insertions(+), 77 deletions(-) create mode 100755 rootfs_overlay/test_fail.sh delete mode 100755 test-modules create mode 100755 test-user-mode diff --git a/README.adoc b/README.adoc index cd38e00..bf4ab5d 100644 --- a/README.adoc +++ b/README.adoc @@ -3159,15 +3159,17 @@ Result on <> at bad30f513c46c1b0995d3a10c0d9bc2a33dc4fa0: === User mode tests -Automatically run non-interactive userland tests that don't depend on any kernel modules: +Automatically run non-interactive userland tests that can be run in user mode simulation: .... ./build-userland --all-archs --all-emulators ./build-userland --all-archs --all-emulators --static --userland-build-id static -./test-userland --all-archs --all-emulators +./test-user-mode --all-archs --all-emulators .... -Source: link:test-userland[] +Source: link:test-user-mode[] + +This testing excludes notably kernel module tests which depend on a full running kernel. The gem5 tests require building statically with build id `static`, see also: <>. TODO automate this better. @@ -11696,11 +11698,11 @@ They contain data structs and magic constant for kernel to userland communicatio Userland test programs. They can be used in the following ways: -* inside a full system simulation +* inside a full system simulation, e.g.: <> * inside <> -* directly on the host +* directly on the host: <> -For usage inside full system, first ensure that Buildroot has been built for the toolchain, and then build the examples with: +For usage inside full system simulation, first ensure that Buildroot has been built for the toolchain, and then build the examples with: .... ./build-userland @@ -11898,7 +11900,7 @@ Sources: * link:build-test[] * link:test[] -* link:test-modules[] +* link:test-userland[] * <> * <> @@ -11909,7 +11911,7 @@ See the sources of those test scripts to learn how to run more specialized tests One important tip is that you can select multiple archs and emulators of interest with a command such as: .... -./test-userland \ +./test-user-mode \ --arch x86_64 \ --arch aarch64 \ --emulator gem5 \ diff --git a/rootfs_overlay/test_all.sh b/rootfs_overlay/test_all.sh index 39b59b8..f28f2e8 100755 --- a/rootfs_overlay/test_all.sh +++ b/rootfs_overlay/test_all.sh @@ -1,25 +1,27 @@ #!/bin/sh +test_dir="${1:-.}" for test in \ - /anonymous_inode.sh \ - /character_device.sh \ - /character_device_create.sh \ - /debugfs.sh \ - /dep.sh \ - /fops.sh \ - /init_module.sh \ - /ioctl.sh \ - /kstrto.sh \ - /mmap.sh \ - /netlink.sh \ - /params.sh \ - /procfs.sh \ - /seq_file.sh \ - /seq_file_single_open.sh \ - /sysfs.sh \ + anonymous_inode.sh \ + character_device.sh \ + character_device_create.sh \ + debugfs.sh \ + dep.sh \ + fops.sh \ + init_module.sh \ + ioctl.sh \ + kstrto.sh \ + mmap.sh \ + netlink.sh \ + params.sh \ + procfs.sh \ + seq_file.sh \ + seq_file_single_open.sh \ + sysfs.sh \ ; do - if ! "$test"; then - echo "lkmc_test_fail: ${test}" + if ! "${test_dir}/${test}"; then + echo "Test failed: ${test}" + test_fail.sh exit 1 fi done -echo lkmc_test_pass +echo 'All tests passed.' diff --git a/rootfs_overlay/test_fail.sh b/rootfs_overlay/test_fail.sh new file mode 100755 index 0000000..9a4c3c1 --- /dev/null +++ b/rootfs_overlay/test_fail.sh @@ -0,0 +1,4 @@ +#!/bin/sh +# Print the magic fail string that our scripts detect +# as a simulation failure. +echo lkmc_test_fail diff --git a/run b/run index 172300c..a54c618 100755 --- a/run +++ b/run @@ -618,9 +618,10 @@ Run QEMU with VNC instead of the default SDL. Connect to it with: if not self.env['userland']: if os.path.exists(self.env['guest_terminal_file']): with open(self.env['guest_terminal_file'], 'br') as logfile: - lines = logfile.readlines() - if lines and lines[-1].rstrip() == self.env['magic_fail_string']: - exit_status = 1 + for line in logfile.readlines(): + if line.rstrip() == self.env['magic_fail_string']: + exit_status = 1 + break if exit_status != 0: self.log_error('simulation error detected by parsing logs') return exit_status diff --git a/test b/test index 96c423c..5b58182 100755 --- a/test +++ b/test @@ -10,7 +10,7 @@ while [ $# -gt 0 ]; do esac done ./bench-boot --size "$test_size" -./test-modules +./test-modules --all-archs --all-emulators ./test-gdb --all-archs --all-emulators ./test-baremetal --all-archs --all-emulators -./test-userland --all-archs --all-emulators +./test-user-mode --all-archs --all-emulators diff --git a/test-modules b/test-modules deleted file mode 100755 index 83a539a..0000000 --- a/test-modules +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash -set -eu -root_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)" -getvar="${root_dir}/getvar" -termout_file="$("$getvar" termout_file)" -./run --eval-busybox '/test_all.sh;/poweroff.out' --kvm -grep -q lkmc_test_pass "$termout_file" diff --git a/test-user-mode b/test-user-mode new file mode 100755 index 0000000..0f01d15 --- /dev/null +++ b/test-user-mode @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 + +import os +import sys + +import common + +class Main(common.LkmcCliFunction): + def __init__(self): + super().__init__( + defaults={ + 'print_time': False, + }, + description='''\ +https://github.com/cirosantilli/linux-kernel-module-cheat#user-mode-tests +''' + , + ) + self.add_argument( + 'tests', + nargs='*', + help='''\ +If given, run only the given tests. Otherwise, run all tests. +''' + ) + + def timed_main(self): + run = self.import_path_main('run') + run_args = self.get_common_args() + if self.env['emulator'] == 'gem5': + run_args['userland_build_id'] = 'static' + if self.env['tests'] == []: + sources = [ + 'add.c', + 'hello.c', + 'hello_cpp.cpp', + 'print_argv.c', + ] + if self.env['arch'] == 'x86_64': + arch_sources = [ + 'asm_hello' + ] + elif self.env['arch'] == 'aarch64': + arch_sources = [ + 'asm_hello' + ] + else: + arch_sources = [] + arch_sources[:] = [os.path.join('arch', self.env['arch'], arch_source) for arch_source in arch_sources] + sources.extend(arch_sources) + else: + sources = self.env['tests'] + for source in sources: + run_args['userland'] = source + run_args['background'] = True + test_id_string = self.test_setup(run_args, source) + exit_status = run(**run_args) + self.test_teardown(run) + if exit_status != 0: + self.log_error('test failed, program exit status: {} test id: {}'.format(exit_status, test_id_string)) + sys.exit(1) + +if __name__ == '__main__': + Main().cli() diff --git a/test-userland b/test-userland index cbe80f9..bb6c66c 100755 --- a/test-userland +++ b/test-userland @@ -11,50 +11,19 @@ class Main(common.LkmcCliFunction): defaults={ 'print_time': False, }, - ) - self.add_argument( - 'tests', - nargs='*', - help='''\ -If given, run only the given tests. Otherwise, run all tests. + description='''\ +Boot Linux and run all non-interactive userland tests, including those +for kernel modules. + +Detect failure based on the magic terminal failure string. ''' ) def timed_main(self): run = self.import_path_main('run') run_args = self.get_common_args() - if self.env['emulator'] == 'gem5': - run_args['userland_build_id'] = 'static' - if self.env['tests'] == []: - sources = [ - 'add.c', - 'hello.c', - 'hello_cpp.cpp', - 'print_argv.c', - ] - if self.env['arch'] == 'x86_64': - arch_sources = [ - 'asm_hello' - ] - elif self.env['arch'] == 'aarch64': - arch_sources = [ - 'asm_hello' - ] - else: - arch_sources = [] - arch_sources[:] = [os.path.join('arch', self.env['arch'], arch_source) for arch_source in arch_sources] - sources.extend(arch_sources) - else: - sources = self.env['tests'] - for source in sources: - run_args['userland'] = source - run_args['background'] = True - test_id_string = self.test_setup(run_args, source) - exit_status = run(**run_args) - self.test_teardown(run) - if exit_status != 0: - self.log_error('test failed, program exit status: {} test id: {}'.format(exit_status, test_id_string)) - sys.exit(1) + run_args['eval_after'] = '/test_all.sh;/poweroff.out' + run(**run_args) if __name__ == '__main__': Main().cli()