| git.druid.rocks | index | druid520 | mp | test/ | lib.sh |
test/lib.sh
# mp/mpx regression test framework -- sourced by test/run.sh, not run
# directly. Provides:
# - environment setup (MP_BIN/WD/PORTS_DIR/MP_PREFIX/MP_BACKEND/SCRATCH),
# adjust these if your build lives somewhere other than /root/mpbuildtest.
# - t_begin/t_pass/t_fail + assert_* for one test's pass/fail bookkeeping.
# - mkport/reset_state, the two helpers every test uses to build a
# throwaway scratch port and get a fully clean slate beforehand.
# - lib_start/lib_finish, the run-wide setup/teardown a suite runner
# calls once at the very start and very end.
#
# every test is fully self-contained: its own scratch port names (the
# "rtNN..." prefix convention just keeps them from colliding within one
# suite file, not that it would matter -- reset_state wipes the whole
# scratch tree before every test regardless), and reset_state gives it a
# fresh WD/MP_PREFIX/mp.conf before it runs. Suites can therefore run
# standalone, in any order, or all together.
set -u
MP_BIN=/root/mpbuildtest/mp
export PATH="/usr/local/bin:$PATH"
export WD=/usr/mp-test-regress
export PORTS_DIR=/usr/ports
export MP_PREFIX=/usr/local-test-regress
export MP_BACKEND=/root/mpbuildtest/mpx
SCRATCH=/usr/ports/ports/scratch
CONF=/etc/mp.conf
CONF_ORIG=/etc/mp.conf.regress-orig
CONF_PREEXISTING=/etc/mp.conf.regress-preexisting
PASS=0
FAIL=0
FAILED_NAMES=""
CUR_TEST=""
CUR_SUITE=""
# --- one test's pass/fail bookkeeping -----------------------------------
t_begin() {
CUR_TEST="$1"
printf '[%s] %s ... ' "$CUR_SUITE" "$1"
}
t_pass() {
PASS=$((PASS + 1))
echo "PASS"
}
t_fail() {
FAIL=$((FAIL + 1))
FAILED_NAMES="$FAILED_NAMES $CUR_TEST"
echo "FAIL: $1"
}
# assert_contains <haystack> <needle> <failure-message>
assert_contains() {
case "$1" in
*"$2"*) return 0 ;;
*) t_fail "$3 (expected to contain: $2)"; return 1 ;;
esac
}
assert_not_contains() {
case "$1" in
*"$2"*) t_fail "$3 (expected NOT to contain: $2)"; return 1 ;;
*) return 0 ;;
esac
}
assert_file_exists() {
if [ -e "$1" ]; then return 0; else t_fail "$2 (expected file: $1)"; return 1; fi
}
assert_file_absent() {
if [ ! -e "$1" ]; then return 0; else t_fail "$2 (expected NO file: $1)"; return 1; fi
}
assert_exit0() {
if [ "$1" -eq 0 ]; then return 0; else t_fail "$2 (exit code $1)"; return 1; fi
}
assert_exit_nonzero() {
if [ "$1" -ne 0 ]; then return 0; else t_fail "$2 (expected nonzero exit, got 0)"; return 1; fi
}
# --- scratch port / clean-slate helpers ---------------------------------
# mkport <name> -- pkg.conf content on stdin. Lands under
# $PORTS_DIR/ports/scratch/<name>, the category find_portdir expects.
mkport() {
mkdir -p "$SCRATCH/$1"
cat > "$SCRATCH/$1/pkg.conf"
}
# reset_state -- full isolation between tests: fresh WD/MP_PREFIX/scratch
# ports dir/mp.conf. Call this first in every single test.
reset_state() {
rm -rf "$SCRATCH"
mkdir -p "$SCRATCH"
rm -rf "$WD" "$MP_PREFIX"
mkdir -p "$WD" "$MP_PREFIX"
cp "$CONF_ORIG" "$CONF"
}
mp() {
"$MP_BIN" "$@"
}
# --- run-wide setup/teardown --------------------------------------------
# lib_start -- one-time setup for the whole suite run. writes a
# deterministic, hermetic baseline mp.conf instead of trusting whatever
# ambient /etc/mp.conf this machine happens to already have: TARGET_*
# pinned to ports/meta/null (a real, harmless no-op stub port, not a
# fake/nonexistent name) for libc/shell/coreutils/cc, and GLOBAL_DEPS
# blanked, so no test anywhere in the suite can accidentally trigger a
# REAL toolchain/libc build (musl, gcc, ...) just from GLOBAL_DEPS' own
# automatic %libc/%shell/%coreutils/%cc resolution -- a genuine, slow
# (and, outside a throwaway chroot, unwanted-side-effect) build, not
# just a slow test. individual tests still often blank GLOBAL_DEPS
# again themselves (harmless, redundant with this) for cases that also
# need a non-default GLOBAL_DEPS of their own. the real pre-existing
# /etc/mp.conf (if any) is preserved separately, in $CONF_PREEXISTING,
# and restored by lib_finish -- never overwritten by, or confused with,
# the deterministic test baseline in $CONF_ORIG itself.
lib_start() {
if [ -f "$CONF" ]; then
cp "$CONF" "$CONF_PREEXISTING"
else
rm -f "$CONF_PREEXISTING"
fi
cat > "$CONF_ORIG" <<-EOF
TARGET_libc=meta/null
TARGET_shell=meta/null
TARGET_coreutils=meta/null
TARGET_cc=meta/null
GLOBAL_DEPS=" "
EOF
}
# lib_finish -- final cleanup, then a full mp verify + mp dryrun sweep
# against the REAL ports tree (a separate WD from every test's own scratch
# ports, so it can never see them) as a closing sanity check that nothing
# above left the real tree in a broken state. Always prints a summary and
# sets the process exit status, regardless of which suites ran.
lib_finish() {
rm -rf "$SCRATCH" "$WD" "$MP_PREFIX"
mkdir -p "$SCRATCH"
if [ -f "$CONF_PREEXISTING" ]; then
cp "$CONF_PREEXISTING" "$CONF"
rm -f "$CONF_PREEXISTING"
else
rm -f "$CONF"
fi
rm -f "$CONF_ORIG"
CUR_SUITE="sweep"
t_begin "full_tree_verify_and_dryrun"
export WD=/usr/mp-test-regress-sweep
export MP_PREFIX=/usr/local-test-regress-sweep
rm -rf "$WD" "$MP_PREFIX"
mkdir -p "$WD" "$MP_PREFIX"
mp verify >/tmp/rt_sweep_verify.out 2>&1
verify_rc=$?
mp dryrun --force all >/tmp/rt_sweep_dryrun.out 2>&1
dryrun_rc=$?
rm -rf "$WD" "$MP_PREFIX" /tmp/rt_sweep_verify.out /tmp/rt_sweep_dryrun.out
if [ "$verify_rc" -ne 0 ] || [ "$dryrun_rc" -ne 0 ]; then
t_fail "full_tree_verify_and_dryrun (verify_rc=$verify_rc dryrun_rc=$dryrun_rc)"
else
t_pass
fi
echo "results: $PASS passed, $FAIL failed."
if [ "$FAIL" -ne 0 ]; then
echo "failed tests:$FAILED_NAMES"
exit 1
fi
exit 0
}