diff options
Diffstat (limited to 'test-logic.sh')
| -rwxr-xr-x | test-logic.sh | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/test-logic.sh b/test-logic.sh new file mode 100755 index 0000000..13d97f8 --- /dev/null +++ b/test-logic.sh @@ -0,0 +1,111 @@ +#!/bin/bash +# +# Logic self-check for sbo-batch-test. Covers the pure, VM-independent parts: +# dependency resolution (topo order, %README%, unmet-dep, cycles) and +# BLOCKED-BY-DEP propagation (depends_on_failed). No overlay, no chroot. +# +# Run: bash test-logic.sh +# +set -uo pipefail + +SCRIPT="$(dirname "$0")/sbo-batch-test" +T=$(mktemp -d) +BASE=$(mktemp -d); mkdir -p "$BASE/var/log/packages" + +cleanup() { rm -rf "$T" "$BASE"; } +trap cleanup EXIT + +# Fake SBo tree under one category. mk <prog> "<REQUIRES>". +mk() { mkdir -p "$T/cat/$1"; echo "REQUIRES=\"$2\"" > "$T/cat/$1/$1.info"; } + +# Graph: +# c (no deps) +# b -> c +# a -> b, %README% +# d -> nonexistentpkg (unmet) +# e -> f, f -> e (cycle) +# g -> b (for blocked-by-dep: if b fails, g blocks) +mk c "" +mk b "c" +mk a "b %README%" +mk d "nonexistentpkg" +mk e "f" +mk f "e" +mk g "b" + +# Source the script without running main(), then override config AFTER the +# source (sourcing re-runs the CONFIG block, which would clobber test vars). +LIB=$(mktemp) +sed '/^main "\$@"$/d' "$SCRIPT" > "$LIB" +# shellcheck disable=SC1090 +source "$LIB" 2>/dev/null +rm -f "$LIB" +SBO_TREE_ROOTS=("$T") +SLACKWARE_BASE="$BASE" + +pass=0; fail=0 +ok() { echo " ok: $1"; ((pass++)); return 0; } +bad() { echo " FAIL: $1"; ((fail++)); return 0; } + +# --- resolution ------------------------------------------------------------- +resolve_target "$T/cat/a" +order=""; for x in "${RESOLVED_ORDER[@]}"; do order+="$(basename "$x") "; done +order="${order% }" # trim trailing space +[[ "$order" == "c b a" ]] && ok "topo order c b a" || bad "topo order, got: [$order]" +[[ "${HAS_README[$T/cat/a]:-}" == "1" ]] && ok "%README% recorded" || bad "%README% not recorded" +[[ ${#UNMET[@]} -eq 0 ]] && ok "no false unmet" || bad "unexpected unmet" + +resolve_target "$T/cat/d" +[[ ${#UNMET[@]} -eq 1 ]] && ok "unmet-dep caught" || bad "unmet-dep missed" + +resolve_target "$T/cat/e" +[[ ${#CYCLES[@]} -ge 1 ]] && ok "cycle caught" || bad "cycle missed" + +# --- BLOCKED-BY-DEP (depends_on_failed) ------------------------------------- +# depends_on_failed <slackbuild-dir> <nameref-to-dead-prog-array> +# returns 0 if the dir directly REQUIRES any prog in the dead list. + +dead=(b) +if depends_on_failed "$T/cat/g" dead; then ok "g blocked when b dead"; else bad "g should block on b"; fi +if depends_on_failed "$T/cat/a" dead; then ok "a blocked when b dead (direct dep)"; else bad "a should block on b"; fi + +dead=(c) +# a does NOT directly require c (a->b->c). One-hop check must say no here. +if depends_on_failed "$T/cat/a" dead; then bad "a wrongly blocked on c (not a direct dep)"; else ok "a not directly blocked by c"; fi +# but b DOES directly require c. +if depends_on_failed "$T/cat/b" dead; then ok "b blocked when c dead"; else bad "b should block on c"; fi + +dead=() +if depends_on_failed "$T/cat/a" dead; then bad "a blocked with empty dead list"; else ok "no block when nothing dead"; fi + +# %README% token in REQUIRES must not be treated as a dead dep. +dead=("%README%") +if depends_on_failed "$T/cat/a" dead; then bad "%README% treated as dep"; else ok "%README% not treated as dep"; fi + +# Propagation invariant note: depends_on_failed is a DIRECT-requires check only. +# Transitive blocking works because run_target iterates in topo order and adds +# each blocked package's own prog name to `dead`, so the failure of c blocks b +# (direct), then b's name enters `dead`, which then blocks a (direct on b). +# Simulate that one-hop cascade here: +dead=(c) +# topo order for a is: c b a. c "fails" -> seed dead=(c). +chain=(c b a) +declare -A blocked=() +for p in "${chain[@]}"; do + [[ "$p" == "c" ]] && continue # c is the original failure, already in dead + if depends_on_failed "$T/cat/$p" dead; then + blocked[$p]=1 + dead+=("$p") # mark dependents-of-this as blockable next hop + fi +done +if [[ "${blocked[b]:-}" == "1" && "${blocked[a]:-}" == "1" ]]; then + ok "transitive cascade c->b->a via one-hop propagation" +else + bad "cascade dead: b=${blocked[b]:-0} a=${blocked[a]:-0}" +fi + +# --- result ----------------------------------------------------------------- +echo +echo "$pass passed, $fail failed" +[[ $fail -eq 0 ]] || exit 1 +echo "ALL LOGIC CHECKS PASS" |
