--- Makefile.am | 6 +- configure.ac | 2 + test/makepkg/Makefile.am | 9 +++ test/makepkg/README | 15 ++++ test/makepkg/test_functions.sh | 143 ++++++++++++++++++++++++++++++++++++ test/makepkg/tests/Makefile.am | 7 ++ test/makepkg/tests/TESTS | 4 + test/makepkg/tests/dbfiles.sh | 35 +++++++++ test/makepkg/tests/dotfiles.sh | 33 +++++++++ test/makepkg/tests/pkgbuild.sh | 53 +++++++++++++ test/makepkg/tests/util-pkgbuild.sh | 35 +++++++++ 11 files changed, 341 insertions(+), 1 deletion(-) create mode 100644 test/makepkg/Makefile.am create mode 100644 test/makepkg/README create mode 100644 test/makepkg/test_functions.sh create mode 100644 test/makepkg/tests/Makefile.am create mode 100644 test/makepkg/tests/TESTS create mode 100755 test/makepkg/tests/dbfiles.sh create mode 100755 test/makepkg/tests/dotfiles.sh create mode 100755 test/makepkg/tests/pkgbuild.sh create mode 100755 test/makepkg/tests/util-pkgbuild.sh diff --git a/Makefile.am b/Makefile.am index 67ffc6b4..7b877a6c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = lib/libalpm src/util src/pacman scripts etc test/pacman test/util test/scripts +SUBDIRS = lib/libalpm src/util src/pacman scripts etc test/makepkg test/pacman test/util test/scripts if WANT_DOC SUBDIRS += doc endif @@ -26,11 +26,15 @@ dist_pkgdata_DATA = \ $(top_srcdir)/test/pacman/tests/TESTS: $(wildcard test/pacman/tests/*.py) @printf "TESTS += %s\n" $^ | LC_ALL=C sort -u > "$@" +$(top_srcdir)/test/makepkg/tests/TESTS: $(wildcard test/makepkg/tests/*.sh) + @printf "TESTS += %s\n" $^ | LC_ALL=C sort -u > "$@" + TESTS = test/scripts/parseopts_test.sh \ test/scripts/human_to_size_test.sh \ test/scripts/makepkg-template_test.sh \ test/scripts/pacman-db-upgrade-v9.py \ test/util/vercmptest.sh +include $(top_srcdir)/test/makepkg/tests/TESTS include $(top_srcdir)/test/pacman/tests/TESTS TEST_SUITE_LOG = test/test-suite.log diff --git a/configure.ac b/configure.ac index 10e4415c..d7e2c9ff 100644 --- a/configure.ac +++ b/configure.ac @@ -530,6 +530,8 @@ scripts/Makefile scripts/po/Makefile.in doc/Makefile etc/Makefile +test/makepkg/Makefile +test/makepkg/tests/Makefile test/pacman/Makefile test/pacman/tests/Makefile test/scripts/Makefile diff --git a/test/makepkg/Makefile.am b/test/makepkg/Makefile.am new file mode 100644 index 00000000..835030c0 --- /dev/null +++ b/test/makepkg/Makefile.am @@ -0,0 +1,9 @@ +SUBDIRS = tests + +check_SCRIPTS = test_functions.sh + +noinst_SCRIPTS = $(check_SCRIPTS) + +EXTRA_DIST = $(check_SCRIPTS) + +# vim:set noet: diff --git a/test/makepkg/README b/test/makepkg/README new file mode 100644 index 00000000..70c6872b --- /dev/null +++ b/test/makepkg/README @@ -0,0 +1,15 @@ +README +====== + +Running Tests +------------- + +Environment Variables +--------------------- + +PMTEST_SCRIPT_DIR - location of the makepkg executable; defaults to "$(dirname "$0")/../../../scripts)" +PMTEST_LIBMAKEPKG_DIR - base directory of the makepkg library; defaults to "$PMTEST_SCRIPT_DIR/libmakepkg" +VERBOSE - enable additional test output for debugging + +Adding New Tests +---------------- diff --git a/test/makepkg/test_functions.sh b/test/makepkg/test_functions.sh new file mode 100644 index 00000000..a6f07bcd --- /dev/null +++ b/test/makepkg/test_functions.sh @@ -0,0 +1,143 @@ +# basic setup to run before every test +# tap_init +tap_init() { + set +e + set -u + set -o pipefail +} + +# wrapper around tap_bail that immediately causes the test to exit non-zero +# tap_xbail $reason... +tap_xbail() { + tap_bail "$@" + exit 1; +} + +# read from stdin and reprint as diagnostic messages if VERBOSE is set and +# non-zero, otherwise, discard +# $command |& tap_filter +tap_filter() { + local v=${VERBOSE:-0} + if (( $v )); then + while IFS= read line; do + tap_diag "$line" + done + else + while IFS= read line; do + : + done + fi +} + +# locate the script that should be tested +locate_bin() { + local scriptdir="${PMTEST_SCRIPT_DIR:-"$(dirname "$0")/../../../scripts"}" + local script="$(realpath "${1:-"$scriptdir/makepkg-wrapper"}")" + if ! type -p "$script" &>/dev/null; then + tap_xbail "makepkg executable (%s) could not be located" "${script}" + exit 1 + fi + printf "%s" "$script" +} + +# locate an source libmakepkg files +source_libmakepkg_file() { + local file=$1; shift 1 + local scriptdir="${PMTEST_SCRIPT_DIR:-"$(dirname "$0")/../../../scripts"}" + local libdir="${PMTEST_LIBMAKEPKG_DIR:-"$scriptdir/libmakepkg"}" + source "$(realpath "$libdir/$file")" +} + +# eval a piece of code and test the return value +# tap_eval $code $test_name... +tap_eval() { + local t=$1; shift 1 + eval "$t" + tap_ok $? "$@" +} + +# extract ls-style information about a file: +# mode nhardlinks user group size month date time/year filename +_ar_stat() { + local ar=$1 path=$2; shift 2 + bsdtar --fast-read -tvf "$ar" "$@" "$path" 2>/dev/null +} + +# same as _ar_stat but with numeric owner ids +_ar_nstat() { + local ar=$1 path=$2; shift 2 + _ar_stat "$ar" "$path" --numeric-owner "$@" +} + +# check the owner of a given file, owner may be a numeric id or user name +# tap_ar_is_owner $path_to_archive $file $expected_owner $test_name... +tap_ar_is_owner() { + local ar=$1 path=$2 expect=$3; shift 3 + local statfun="_ar_stat" owner unused + [[ $expect =~ ^[0-9]+$ ]] && statfun="_ar_nstat" + if ! read -r unused unused owner unused < <($statfun "$ar" "$path"); then + tap_ok 1 "$@" + tap_diag " got: invalid path" + tap_diag " expected: '%s'" "$expect" + elif [[ $owner != $expect ]]; then + tap_ok 1 "$@" + tap_diag " got: '%s'" "$owner" + tap_diag " expected: '%s'" "$expect" + else + tap_ok 0 "$@" + fi +} + +# check the group of a given file, group may be a numeric id or user name +# tap_ar_is_group $path_to_archive $file $expected_group $test_name... +tap_ar_is_group() { + local ar=$1 path=$2 expect=$3; shift 3 + local statfun="_ar_stat" group unused + [[ $expect =~ ^[0-9]+$ ]] && statfun="_ar_nstat" + if ! read -r unused unused unused group unused < <($statfun "$ar" "$path"); then + tap_ok 1 "$@" + tap_diag " got: invalid path" + tap_diag " expected: '%s'" "$expect" + elif [[ $group != $expect ]]; then + tap_ok 1 "$@" + tap_diag " got: '%s'" "$group" + tap_diag " expected: '%s'" "$expect" + else + tap_ok 0 "$@" + fi +} + +# check if a path within an archive refers to a file +# tap_ar_is_file $path_to_archive $file $test_name... +tap_ar_is_file() { + local ar=$1 path=$2; shift 2 + local stat="$(_ar_stat "$ar" "$path")" + if [[ ${stat:0:1} != '-' ]]; then + tap_ok 1 "$@" + tap_diag " got: not a file" + tap_diag " expected: '%s'" "$path" + else + tap_ok 0 "$@" + fi +} + +# check if a path within an archive refers to a symbolic link +# tap_ar_is_link $path_to_archive $file $expected_destination $test_name... +tap_ar_is_link() { + local ar=$1 path=$2 dest=$3; shift 3 + local stat="$(_ar_stat "$ar" "$path")" + if [[ ${stat:0:1} != 'l' ]]; then + tap_ok 1 "$@" + tap_diag " got: not a link" + tap_diag " expected: '%s'" "$dest" + elif [[ ${stat##*$path -> } != $dest ]]; then + tap_ok 1 "$@" + tap_diag " got: '%s'" "${stat##*$path -> }" + tap_diag " expected: '%s'" "$dest" + else + tap_ok 0 "$@" + fi +} + +source "$(dirname "$0")"/../../tap.sh || exit 1 +tap_init diff --git a/test/makepkg/tests/Makefile.am b/test/makepkg/tests/Makefile.am new file mode 100644 index 00000000..fb59d11c --- /dev/null +++ b/test/makepkg/tests/Makefile.am @@ -0,0 +1,7 @@ +check_SCRIPTS = $(wildcard *.sh) + +noinst_SCRIPTS = $(check_SCRIPTS) + +EXTRA_DIST = $(check_SCRIPTS) + +# vim:set noet: diff --git a/test/makepkg/tests/TESTS b/test/makepkg/tests/TESTS new file mode 100644 index 00000000..f167e594 --- /dev/null +++ b/test/makepkg/tests/TESTS @@ -0,0 +1,4 @@ +TESTS += test/makepkg/tests/dbfiles.sh +TESTS += test/makepkg/tests/dotfiles.sh +TESTS += test/makepkg/tests/pkgbuild.sh +TESTS += test/makepkg/tests/util-pkgbuild.sh diff --git a/test/makepkg/tests/dbfiles.sh b/test/makepkg/tests/dbfiles.sh new file mode 100755 index 00000000..72e196ef --- /dev/null +++ b/test/makepkg/tests/dbfiles.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +source "$(dirname "$0")"/../test_functions.sh || exit 1 + +script="$(locate_bin "${1:-}")" + +TMPDIR="$(mktemp -d --tmpdir "${0##*/}.XXXXXX")" +trap "rm -rf '${TMPDIR}'" EXIT TERM + +tap_note "check that required metadata files are created" +tap_note "testing '%s'" "$script" +tap_note "using test dir '%s'" "$TMPDIR" + +( + set -e + cd "$TMPDIR" + cat >PKGBUILD <<-'PKGBUILD' + pkgname=foo + pkgver=1 + pkgrel=1 + arch=(any) + PKGBUILD + MAKEPKG_CONF="/dev/null" PKGEXT=".pkg.tar" $script +) |& tap_filter +[[ $? -eq 0 ]] || tap_xbail "test setup failed" + +pkgfile="$TMPDIR/foo-1-1-any.pkg.tar" + +tap_plan 10 +for f in .BUILDINFO .PKGINFO .MTREE; do + tap_ar_is_file "$pkgfile" "$f" "pkg contains %s" "$f" + tap_ar_is_owner "$pkgfile" "$f" "0" "%s owner is root" "$f" + tap_ar_is_group "$pkgfile" "$f" "0" "%s group is root" "$f" +done +tap_is_int "$(bsdtar -tf "$pkgfile" | wc -l)" 3 "pkg only contains known metainfo files" diff --git a/test/makepkg/tests/dotfiles.sh b/test/makepkg/tests/dotfiles.sh new file mode 100755 index 00000000..9fa81258 --- /dev/null +++ b/test/makepkg/tests/dotfiles.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +source "$(dirname "$0")"/../test_functions.sh || exit 1 + +script="$(locate_bin "${1:-}")" + +TMPDIR="$(mktemp -d --tmpdir "${0##*/}.XXXXXX")" +[[ ${KEEPFILES:-0} == 0 ]] || trap "rm -rf '${TMPDIR}'" EXIT TERM + +tap_note "test that dotfiles don't make it into the package root" +tap_note "testing '%s'" "$script" +tap_note "using test dir '%s'" "$TMPDIR" + +output="$( + set -e + cd "$TMPDIR" + cat >PKGBUILD <<-'PKGBUILD' + pkgname=foo + pkgver=1 + pkgrel=1 + arch=(any) + package() { + touch "$pkgdir"/.dotfile + } + PKGBUILD + MAKEPKG_CONF="/dev/null" PKGEXT=".pkg.tar" $script 2>&1 +)" +ret=$? + +tap_plan 3 +tap_eval "[[ '$ret' -ne 0 ]]" "makepkg exited non-zero" +tap_eval "[[ ! -f '$TMPDIR/foo-1-1-any.pkg.tar' ]]" "no package was built" +tap_eval "[[ '$output' = *'Dotfile found in package root'* ]]" "error message references dotfile" diff --git a/test/makepkg/tests/pkgbuild.sh b/test/makepkg/tests/pkgbuild.sh new file mode 100755 index 00000000..5dc8d46f --- /dev/null +++ b/test/makepkg/tests/pkgbuild.sh @@ -0,0 +1,53 @@ +#!/bin/bash + +source "$(dirname "$0")"/../test_functions.sh || exit 1 + +script="$(locate_bin "${1:-}")" + +TMPDIR="$(mktemp -d --tmpdir "${0##*/}.XXXXXX")" +trap "rm -rf '${TMPDIR}'" EXIT TERM + +tap_note "basic package building test" +tap_note "testing '%s'" "$script" +tap_note "using test dir '%s'" "$TMPDIR" + +( + set -e + cd "$TMPDIR" + cat >PKGBUILD <<-'PKGBUILD' + pkgname=foo + pkgver=1 + pkgrel=1 + arch=(any) + package() { + touch "$pkgdir/!first" + touch "$pkgdir/target" + ln -s target "$pkgdir/link" + mkdir "$pkgdir/dir" + touch "$pkgdir/dir/.dotfile" + } + PKGBUILD + MAKEPKG_CONF="/dev/null" PKGEXT=".pkg.tar" $script +) |& tap_filter +[[ $? -eq 0 ]] || tap_xbail "test setup failed" + +pkgfile="$TMPDIR/foo-1-1-any.pkg.tar" + +tap_plan 10 +tap_ar_is_file "$pkgfile" "!first" "pkg contains !first" +tap_ar_is_file "$pkgfile" "target" "pkg contains target" +tap_ar_is_file "$pkgfile" "dir/.dotfile" "pkg contains dir/.dotfile" +tap_ar_is_link "$pkgfile" "link" "target" "pkg contains link to target" +tap_ar_is_owner "$pkgfile" "target" "0" "target owner is root" +tap_ar_is_group "$pkgfile" "target" "0" "target group is root" + +tap_eval "! bsdtar -tf '$pkgfile' | grep -qE '^\\.?\\.?/'" \ + "package paths are relative without leading dot dirs" +tap_eval "bsdtar -tf '$pkgfile' | grep -v '^\\.' | LANG=C sort -Cu" \ + "package files are sorted" +tap_eval "bsdtar -tf '$pkgfile' | LANG=C sort | LANG=C sort -Cu" \ + "package files are unique" +tap_eval "bsdtar -tf '$pkgfile' | head -n1 | grep -q '^\\.'" \ + "db files are placed at the beginning of the package" + +tap_finish diff --git a/test/makepkg/tests/util-pkgbuild.sh b/test/makepkg/tests/util-pkgbuild.sh new file mode 100755 index 00000000..3fd970c8 --- /dev/null +++ b/test/makepkg/tests/util-pkgbuild.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +source "$(dirname "$0")"/../test_functions.sh || exit 1 + +tap_note "testing libmakepkg/util/pkgbuild.sh" + +source_libmakepkg_file 'util/pkgbuild.sh' + +test_foo() { + myarray=(foo bar) + myarray+=(baz) + #myarray+=(this should be ignored) + myscalar=baz + myscalar=quux + #myscalar=ignored +} + +declare -a oarray +declare oscalar + +tap_plan 9 + +tap_eval 'have_function test_foo' 'detected existing function test_foo' +tap_eval '! have_function test_bar' 'detected missing function test_bar' + +tap_eval 'extract_function_variable test_foo myarray 1 oarray' 'extract array variable' +tap_is_int "${#oarray[@]}" 3 'extracted array length' +tap_is_str "${oarray[0]}" 'foo' 'extracted array contents' +tap_is_str "${oarray[1]}" 'bar' 'extracted array contents' +tap_is_str "${oarray[2]}" 'baz' 'extracted array contents' + +tap_eval 'extract_function_variable test_foo myscalar 0 oscalar' 'extract scalar variable' +tap_is_str "$oscalar" 'quux' 'extracted scalar value' + +tap_finish -- 2.11.1