mirror of
https://github.com/dynup/kpatch
synced 2024-12-27 15:52:02 +00:00
297 lines
6.3 KiB
Bash
Executable File
297 lines
6.3 KiB
Bash
Executable File
#!/bin/bash
|
|
#
|
|
# kpatch integration test framework
|
|
#
|
|
# Copyright (C) 2014 Josh Poimboeuf <jpoimboe@redhat.com>
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License
|
|
# as published by the Free Software Foundation; either version 2
|
|
# of the License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA,
|
|
# 02110-1301, USA.
|
|
#
|
|
#
|
|
# This is a basic integration test framework for kpatch, which tests building,
|
|
# loading, and unloading patches, as well as any other related custom tests.
|
|
#
|
|
# This script looks for test input files in the current directory. It expects
|
|
# certain file naming conventions:
|
|
#
|
|
# - foo.patch: patch that should build successfully
|
|
#
|
|
# - bar-FAIL.patch: patch that should fail to build
|
|
#
|
|
# - foo-LOADED.test: executable which tests whether the foo.patch module is
|
|
# loaded. It will be used to test that loading/unloading the patch module
|
|
# works as expected.
|
|
#
|
|
# Any other *.test files will be executed after all the patch modules have been
|
|
# built from the *.patch files. They can be used for more custom tests above
|
|
# and beyond the simple loading and unloading tests.
|
|
|
|
SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))"
|
|
ROOTDIR="$(readlink -f $SCRIPTDIR/../..)"
|
|
# TODO: option to use system-installed binaries instead
|
|
KPATCH="sudo $ROOTDIR/kpatch/kpatch"
|
|
RMMOD="sudo rmmod"
|
|
KPATCHBUILD="$ROOTDIR"/kpatch-build/kpatch-build
|
|
ERROR=0
|
|
LOG=test.log
|
|
rm -f $LOG
|
|
|
|
usage() {
|
|
echo "usage: $0 [options]" >&2
|
|
echo " -h, --help Show this help message" >&2
|
|
echo " -c, --cached Don't rebuild patch modules" >&2
|
|
echo " -q, --quick Just combine all patches into one module for testing" >&2
|
|
}
|
|
|
|
options=$(getopt -o hcq -l "help,cached,quick" -- "$@") || exit 1
|
|
|
|
eval set -- "$options"
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
-c|--cached)
|
|
SKIPBUILD=1
|
|
;;
|
|
-q|--quick)
|
|
QUICK=1
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
|
|
error() {
|
|
echo "ERROR: $@" |tee -a $LOG >&2
|
|
ERROR=$((ERROR + 1))
|
|
}
|
|
|
|
log() {
|
|
echo "$@" |tee -a $LOG
|
|
}
|
|
|
|
unload_all() {
|
|
for i in `lsmod |egrep '^kpatch' |awk '{print $1}'`; do
|
|
if [[ $i != kpatch ]]; then
|
|
$KPATCH unload $i >> $LOG 2>&1 || error "\"kpatch unload $i\" failed"
|
|
fi
|
|
done
|
|
if lsmod |egrep -q '^kpatch'; then
|
|
$RMMOD kpatch >> $LOG 2>&1 || error "\"rmmod kpatch\" failed"
|
|
fi
|
|
}
|
|
|
|
build_module() {
|
|
file=$1
|
|
prefix=${file%%.patch}
|
|
module=kpatch-$prefix.ko
|
|
|
|
[[ $prefix = COMBINED ]] && return
|
|
|
|
if [[ $prefix = *-FAIL ]]; then
|
|
shouldfail=1
|
|
else
|
|
shouldfail=0
|
|
fi
|
|
|
|
if [[ $SKIPBUILD -eq 1 ]]; then
|
|
skip=0
|
|
[[ $shouldfail -eq 1 ]] && skip=1
|
|
[[ -e $module ]] && skip=1
|
|
[[ $skip -eq 1 ]] && log "skipping build: $prefix" && return
|
|
fi
|
|
|
|
log "build: $prefix"
|
|
|
|
if ! $KPATCHBUILD $file >> $LOG 2>&1; then
|
|
[[ $shouldfail -eq 0 ]] && error "$prefix: build failed"
|
|
else
|
|
[[ $shouldfail -eq 1 ]] && error "$prefix: build succeeded when it should have failed"
|
|
fi
|
|
}
|
|
|
|
run_load_test() {
|
|
file=$1
|
|
prefix=${file%%.patch}
|
|
module=kpatch-$prefix.ko
|
|
testprog=$prefix-LOADED.test
|
|
|
|
[[ $prefix = COMBINED ]] && return
|
|
[[ $prefix = *-FAIL ]] && return
|
|
|
|
if [[ ! -e $module ]]; then
|
|
log "can't find $module, skipping"
|
|
return
|
|
fi
|
|
|
|
if [[ -e $testprog ]]; then
|
|
log "load test: $prefix"
|
|
else
|
|
log "load test: $prefix (no test prog)"
|
|
fi
|
|
|
|
|
|
if ! $KPATCH replace $module >> $LOG 2>&1; then
|
|
error "$prefix: kpatch replace failed"
|
|
return
|
|
fi
|
|
|
|
if [[ -e $testprog ]] && ! ./$testprog >> $LOG 2>&1; then
|
|
error "$prefix: $testprog failed after kpatch replace"
|
|
return
|
|
fi
|
|
|
|
if ! $KPATCH unload $module >> $LOG 2>&1; then
|
|
error "$prefix: kpatch unload failed"
|
|
return
|
|
fi
|
|
|
|
if [[ -e $testprog ]] && ./$testprog >> $LOG 2>&1; then
|
|
error "$prefix: $testprog succeeded after kpatch unload"
|
|
return
|
|
fi
|
|
|
|
if ! $KPATCH load $module >> $LOG 2>&1; then
|
|
error "$prefix: kpatch load failed"
|
|
return
|
|
fi
|
|
|
|
if [[ -e $testprog ]] && ! ./$testprog >> $LOG 2>&1; then
|
|
error "$prefix: $testprog failed after kpatch load"
|
|
return
|
|
fi
|
|
}
|
|
|
|
run_custom_test() {
|
|
testprog=$1
|
|
prefix=${file%%.test}
|
|
|
|
[[ $testprog = *-LOADED.test ]] && return
|
|
|
|
log "custom test: $prefix"
|
|
|
|
if ! ./$testprog >> $LOG 2>&1; then
|
|
error "$prefix: test failed"
|
|
fi
|
|
}
|
|
|
|
build_combined_module() {
|
|
|
|
if [[ $SKIPBUILD -eq 1 ]] && [[ -e kpatch-COMBINED.ko ]]; then
|
|
log "skipping build: combined"
|
|
return
|
|
fi
|
|
|
|
if ! which combinediff > /dev/null; then
|
|
log "patchutils not installed, skipping combined module build"
|
|
error "PLEASE INSTALL PATCHUTILS"
|
|
return
|
|
fi
|
|
|
|
rm -f COMBINED.patch
|
|
first=1
|
|
for file in *.patch; do
|
|
prefix=${file%%.patch}
|
|
|
|
[[ $prefix = *-FAIL ]] && continue
|
|
[[ $prefix = meminfo-cmdline ]] && continue # HACK
|
|
|
|
log "combine: $prefix"
|
|
|
|
if [[ $first -eq 1 ]]; then
|
|
cp -f $file COMBINED.patch
|
|
first=0
|
|
continue
|
|
fi
|
|
|
|
combinediff COMBINED.patch $file > TMP.patch
|
|
mv -f TMP.patch COMBINED.patch
|
|
done
|
|
|
|
log "build: combined module"
|
|
|
|
if ! $KPATCHBUILD COMBINED.patch >> $LOG 2>&1; then
|
|
error "combined build failed"
|
|
fi
|
|
}
|
|
|
|
run_combined_test() {
|
|
if [[ ! -e kpatch-COMBINED.ko ]]; then
|
|
log "can't find kpatch-COMBINED.ko, skipping"
|
|
return
|
|
fi
|
|
|
|
log "load test: combined module"
|
|
|
|
if ! $KPATCH replace kpatch-COMBINED.ko >> $LOG 2>&1; then
|
|
error "combined: kpatch replace failed"
|
|
return
|
|
fi
|
|
|
|
for testprog in *.test; do
|
|
[[ $testprog != *-LOADED.test ]] && continue
|
|
if ! ./$testprog >> $LOG 2>&1; then
|
|
error "combined: $testprog failed"
|
|
fi
|
|
done
|
|
}
|
|
|
|
echo "clearing printk buffer"
|
|
sudo dmesg -C
|
|
|
|
cd "$SCRIPTDIR"
|
|
|
|
if [[ $QUICK != 1 ]]; then
|
|
for file in *.patch; do
|
|
build_module $file
|
|
done
|
|
fi
|
|
|
|
build_combined_module
|
|
|
|
unload_all
|
|
|
|
if [[ $QUICK != 1 ]]; then
|
|
for file in *.patch; do
|
|
run_load_test $file
|
|
done
|
|
fi
|
|
|
|
run_combined_test
|
|
|
|
if [[ $QUICK != 1 ]]; then
|
|
for file in *.test; do
|
|
unload_all
|
|
run_custom_test $file
|
|
done
|
|
fi
|
|
|
|
|
|
unload_all
|
|
|
|
dmesg |grep -q "Call Trace" && error "kernel error detected in printk buffer"
|
|
|
|
if [[ $ERROR -gt 0 ]]; then
|
|
log "$ERROR errors encountered"
|
|
echo "see test.log for more information"
|
|
else
|
|
log "SUCCESS"
|
|
fi
|
|
|
|
exit $ERROR
|