A week or so ago, I read a bug report on this list with a simple reproducer + fix that was just begging for a test suite addition. This change adds framework to make that easy, and adds the first test. I uncovered problems in tests/Makefile.am along the way and just posted a patch for that. This adds most of a portable (bourne-shell-based) test framework that also provides for convenient isolation of individual tests (so we can easily parallelize them without worrying one will tromp on files of another). In a couple years when running "make check" runs hundreds of tests, you'll definitely want them to run in parallel. The mktempd script is not new. I first used it in coreutils and parted, but removed it from coreutils after that package acquired its own C-based implementation. test-lib.sh is from coreutils, but was inspired by the file by the same name in git.git's own t/ (tests) directory. Add new testing framework and the first test to use it. * tests/Makefile.am (test_scripts): Add vcpupin. (EXTRA_DIST): Add test-lib.sh. * tests/test-lib.sh: Testing framework, from coreutils. * tests/vcpupin: New file. * build-aux/mktempd: New file, from gnulib. * bootstrap: Add posix-shell and mktempd to the list of imported modules. * gnulib/m4/posix-shell.m4: New file, from gnulib. This also updates lots of files from gnulib, as you can see from the diffstat output. The diffs below include everything not under gnulib/. --- bootstrap | 2 + build-aux/.cvsignore | 1 + build-aux/mktempd | 132 ++++++++++++++++++++++++++++++++ build-aux/useless-if-before-free | 6 +- gnulib/lib/Makefile.am | 37 +++++++--- gnulib/lib/alloca.in.h | 4 +- gnulib/lib/getaddrinfo.c | 2 +- gnulib/lib/getdelim.c | 6 +- gnulib/lib/unistd.in.h | 22 +++++- gnulib/lib/xsize.h | 2 +- gnulib/m4/absolute-header.m4 | 49 ------------ gnulib/m4/fseeko.m4 | 8 ++- gnulib/m4/gnulib-cache.m4 | 6 +- gnulib/m4/gnulib-comp.m4 | 6 +- gnulib/m4/include_next.m4 | 7 +- gnulib/m4/lib-link.m4 | 66 ++++++++++++----- gnulib/m4/posix-shell.m4 | 58 ++++++++++++++ gnulib/m4/unistd_h.m4 | 6 +- gnulib/tests/Makefile.am | 2 +- tests/Makefile.am | 7 ++- tests/test-lib.sh | 155 ++++++++++++++++++++++++++++++++++++++ tests/vcpupin | 37 +++++++++ 22 files changed, 521 insertions(+), 100 deletions(-) create mode 100755 build-aux/mktempd delete mode 100644 gnulib/m4/absolute-header.m4 create mode 100644 gnulib/m4/posix-shell.m4 create mode 100644 tests/test-lib.sh create mode 100755 tests/vcpupin diff --git a/bootstrap b/bootstrap index d8b79d9..f7b6aec 100755 --- a/bootstrap +++ b/bootstrap @@ -79,6 +79,8 @@ $gnulib_tool \ sys_stat vasprintf strndup \ strsep poll gettext getpass \ useless-if-before-free \ + posix-shell \ + mktempd \ vc-list-files rm -f \ diff --git a/build-aux/.cvsignore b/build-aux/.cvsignore index 1798f40..096cccb 100644 --- a/build-aux/.cvsignore +++ b/build-aux/.cvsignore @@ -7,3 +7,4 @@ install-sh ltmain.sh missing mkinstalldirs +mktempd diff --git a/build-aux/mktempd b/build-aux/mktempd new file mode 100755 index 0000000..7ac914b --- /dev/null +++ b/build-aux/mktempd @@ -0,0 +1,132 @@ +#!/bin/sh +# Create a temporary directory, much like mktemp -d does. + +# Copyright (C) 2007-2008 Free Software Foundation, Inc. + +# 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 3 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, see <http://www.gnu.org/licenses/>. + +# Written by Jim Meyering. + +# Usage: mktempd /tmp phoey.XXXXXXXXXX + +# First, try to use the mktemp program. +# Failing that, we'll roll our own mktemp-like function: +# - try to get random bytes from /dev/urandom +# - failing that, generate output from a combination of quickly-varying +# sources and gzip. Ignore non-varying gzip header, and extract +# "random" bits from there. +# - given those bits, map to file-name bytes using tr, and try to create +# the desired directory. +# - make only $MAX_TRIES attempts + +ME=`basename "$0"` +die() { echo >&2 "$ME: $@"; exit 1; } + +MAX_TRIES=4 + +rand_bytes() +{ + n=$1 + + chars=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 + + dev_rand=/dev/urandom + if test -r "$dev_rand"; then + # Note: 256-length($chars) == 194; 3 copies of $chars is 186 + 8 = 194. + head -c$n "$dev_rand" | tr -c $chars 01234567$chars$chars$chars + return + fi + + cmds='date; date +%N; free; who -a; w; ps auxww; ps ef; netstat -n' + data=` (eval "$cmds") 2>&1 | gzip ` + + n_plus_50=`expr $n + 50` + + # Ensure that $data has length at least 50+$n + while :; do + len=`echo "$data"|wc -c` + test $n_plus_50 -le $len && break; + data=` (echo "$data"; eval "$cmds") 2>&1 | gzip ` + done + + echo "$data" \ + | dd bs=1 skip=50 count=$n 2>/dev/null \ + | tr -c $chars 01234567$chars$chars$chars +} + +mktempd() +{ + case $# in + 2);; + *) die "Usage: $ME DIR TEMPLATE";; + esac + + destdir=$1 + template=$2 + + # Disallow any trailing slash on specified destdir: + # it would subvert the post-mktemp "case"-based destdir test. + case $destdir in + /) ;; + */) die "invalid destination dir: remove trailing slash(es)";; + esac + + case $template in + *XXXX) ;; + *) die "invalid template: $template (must have a suffix of at least 4 X's)";; + esac + + fail=0 + + # First, try to use mktemp. + d=`env -u TMPDIR mktemp -d -t -p "$destdir" "$template" 2>/dev/null` \ + || fail=1 + + # The resulting name must be in the specified directory. + case $d in "$destdir"*);; *) fail=1;; esac + + # It must have created the directory. + test -d "$d" || fail=1 + + # It must have 0700 permissions. Handle sticky "S" bits. + perms=`ls -dgo "$d" 2>/dev/null|tr S -` || fail=1 + case $perms in drwx------*) ;; *) fail=1;; esac + + test $fail = 0 && { + echo "$d" + return + } + + # If we reach this point, we'll have to create a directory manually. + + # Get a copy of the template without its suffix of X's. + base_template=`echo "$template"|sed 's/XX*$//'` + + # Calculate how many X's we've just removed. + nx=`expr length "$template" - length "$base_template"` + + err= + i=1 + while :; do + X=`rand_bytes $nx` + candidate_dir="$destdir/$base_template$X" + err=`mkdir -m 0700 "$candidate_dir" 2>&1` \ + && { echo "$candidate_dir"; return; } + test $MAX_TRIES -le $i && break; + i=`expr $i + 1` + done + die "$err" +} + +mktempd "$@" diff --git a/build-aux/useless-if-before-free b/build-aux/useless-if-before-free index eb18483..626d19a 100755 --- a/build-aux/useless-if-before-free +++ b/build-aux/useless-if-before-free @@ -2,7 +2,7 @@ # Detect instances of "if (p) free (p);". # Likewise for "if (p != NULL) free (p);". And with braces. -my $VERSION = '2008-02-11 08:08'; # UTC +my $VERSION = '2008-03-12 13:06'; # UTC # The definition above must lie within the first 8 lines in order # for the Emacs time-stamp write hook (at end) to update it. # If you change this file with Emacs, please let the write hook @@ -123,8 +123,8 @@ EOF { if ($line =~ /\b(if\s*\(\s*(\S+?)(?:\s*!=\s*NULL)?\s*\) - (?: \s*$regexp\s*\(\s*\2\s*\)| - \s*\{\s*$regexp\s*\(\s*\2\s*\)\s*;\s*\}))/sx) + (?: \s*$regexp\s*\((?:\s*\([^)]+\))\s*\2\s*\)| + \s*\{\s*$regexp\s*\((?:\s*\([^)]+\))\s*\2\s*\)\s*;\s*\}))/sx) { $found_match = 1; $list diff --git a/tests/test-lib.sh b/tests/test-lib.sh new file mode 100644 index 0000000..cdbea5d --- /dev/null +++ b/tests/test-lib.sh @@ -0,0 +1,155 @@ +# source this file; set up for tests + +# Skip this test if the shell lacks support for functions. +unset function_test +eval 'function_test() { return 11; }; function_test' +if test $? != 11; then + echo "$0: /bin/sh lacks support for functions; skipping this test." 1>&2 + (exit 77); exit 77 +fi + +skip_test_() +{ + echo "$0: skipping test: $@" 1>&2 + (exit 77); exit 77 +} + +require_acl_() +{ + getfacl --version < /dev/null > /dev/null 2>&1 \ + && setfacl --version < /dev/null > /dev/null 2>&1 \ + || skip_test_ "This test requires getfacl and setfacl." + + id -u bin > /dev/null 2>&1 \ + || skip_test_ "This test requires a local user named bin." +} + +require_ulimit_() +{ + ulimit_works=yes + # Expect to be able to exec a program in 10MB of virtual memory, + # but not in 20KB. I chose "date". It must not be a shell built-in + # function, so you can't use echo, printf, true, etc. + # Of course, in coreutils, I could use $top_builddir/src/true, + # but this should be able to work for other projects, too. + ( ulimit -v 10000; date ) > /dev/null 2>&1 || ulimit_works=no + ( ulimit -v 20; date ) > /dev/null 2>&1 && ulimit_works=no + + test $ulimit_works = no \ + && skip_test_ "this shell lacks ulimit support" +} + +require_readable_root_() +{ + test -r / || skip_test_ "/ is not readable" +} + +# Skip the current test if strace is not available or doesn't work. +require_strace_() +{ + strace -V < /dev/null > /dev/null 2>&1 || + skip_test_ 'no strace program' + + strace -qe unlink echo > /dev/null 2>&1 || + skip_test_ 'strace does not work' +} + +require_built_() +{ + skip_=no + for i in "$@"; do + case " $built_programs " in + *" $i "*) ;; + *) echo "$i: not built" 1>&2; skip_=yes ;; + esac + done + + test $skip_ = yes && skip_test_ "required program(s) not built" +} + +uid_is_privileged_() +{ + # Make sure id -u succeeds. + my_uid=$(id -u) \ + || { echo "$0: cannot run \`id -u'" 1>&2; return 1; } + + # Make sure it gives valid output. + case $my_uid in + 0) ;; + *[!0-9]*) + echo "$0: invalid output (\`$my_uid') from \`id -u'" 1>&2 + return 1 ;; + *) return 1 ;; + esac +} + +skip_if_() +{ + case $1 in + root) skip_test_ must be run as root ;; + non-root) skip_test_ must be run as non-root ;; + *) ;; # FIXME? + esac +} + +require_selinux_() +{ + case `ls -Zd .` in + '? .'|'unlabeled .') + skip_test_ "this system (or maybe just" \ + "the current file system) lacks SELinux support" + ;; + esac +} + +very_expensive_() +{ + if test "$RUN_VERY_EXPENSIVE_TESTS" != yes; then + skip_test_ ' +This test is very expensive, so it is disabled by default. +To run it anyway, rerun make check with the RUN_VERY_EXPENSIVE_TESTS +environment variable set to yes. E.g., + + env RUN_VERY_EXPENSIVE_TESTS=yes make check +' + fi +} + +require_root_() { uid_is_privileged_ || skip_test_ "must be run as root"; } +skip_if_root_() { uid_is_privileged_ && skip_test_ "must be run as non-root"; } +error_() { echo "$0: $@" 1>&2; (exit 1); exit 1; } +framework_failure() { error_ 'failure in testing framework'; } + +test_dir_=$(pwd) + +this_test_() { echo "./$0" | sed 's,.*/,,'; } +this_test=$(this_test_) + +# This is a stub function that is run upon trap (upon regular exit and +# interrupt). Override it with a per-test function, e.g., to unmount +# a partition, or to undo any other global state changes. +cleanup_() { :; } + +mktempd="$abs_top_srcdir/build-aux/mktempd" +t_=$("$SHELL" "$mktempd" "$test_dir_" lv-$this_test.XXXXXXXXXX) \ + || error_ "failed to create temporary directory in $test_dir_" + +# Run each test from within a temporary sub-directory named after the +# test itself, and arrange to remove it upon exception or normal exit. +trap 'st=$?; cleanup_; d='"$t_"'; + cd '"$test_dir_"' && chmod -R u+rwx "$d" && rm -rf "$d" && exit $st' 0 +trap '(exit $?); exit $?' 1 2 13 15 + +cd "$t_" || error_ "failed to cd to $t_" + +if ( diff --version < /dev/null 2>&1 | grep GNU ) 2>&1 > /dev/null; then + compare() { diff -u "$@"; } +elif ( cmp --version < /dev/null 2>&1 | grep GNU ) 2>&1 > /dev/null; then + compare() { cmp -s "$@"; } +else + compare() { cmp "$@"; } +fi + +# Local Variables: +# indent-tabs-mode: nil +# End: diff --git a/tests/vcpupin b/tests/vcpupin new file mode 100755 index 0000000..b56c7f2 --- /dev/null +++ b/tests/vcpupin @@ -0,0 +1,37 @@ +#!/bin/sh +# ensure that an invalid CPU spec elicits a diagnostic + +# Copyright (C) 2008 Free Software Foundation, Inc. + +# 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 3 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, see <http://www.gnu.org/licenses/>. + +if test "$VERBOSE" = yes; then + set -x + virsh --version +fi + +. $srcdir/test-lib.sh + +fail=0 +virsh --connect test:///default vcpupin test a 0,1 > out 2>&1 +test $? = 1 || fail=1 + +cat <<\EOF > exp || fail=1 +error: vcpupin: Invalid or missing vCPU number. + +EOF + +compare out exp || fail=1 + +(exit $fail); exit $fail -- 1.5.4.4.482.g16f99 -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list