Files
RedBear-OS/local/scripts/test-versioning-machinery.sh
T
vasilito 8413b69334 build system: harden + regression-test the versioning machinery
Edge-case suite (local/scripts/test-versioning-machinery.sh, 27 cases, zero
network via file:// tarballs) covering the validator and the sync engine.
It found and fixed three silent-failure bugs — the exact class the user flagged:
 - sync engine used 'rsync -a --delete' (size+mtime quick-check): a changed file
   of identical size with a coincidental mtime was skipped, leaving stale content
   in source/. Now uses --checksum (content comparison).
 - apply_patch relied on patch's default fuzz: a patch whose context no longer
   matched the new upstream was force-fitted instead of rejected. Now --fuzz=0
   (exact context; line offsets still allowed).
 - decorrupt collapsed ANY run of identical lines, mangling legitimate paired
   lines; now only collapses the corruption pattern (runs >=4).
Also: unknown-version recipes are skipped (never clobber a ported tree like
mesa), and grep patterns use [[:space:]] for portability.
2026-07-31 20:33:10 +03:00

164 lines
10 KiB
Bash
Executable File

#!/usr/bin/env bash
# test-versioning-machinery.sh — edge-case test suite for the versioning
# machinery (verify-external-source-versions.sh + sync-recipe-source.sh).
#
# Runs each script against an isolated fixture repo (synthetic recipes + file://
# tarballs), asserting behaviour on the full matrix of edge cases. Zero network.
# Exit 0 = all pass. This is the guard that keeps the "wrong version silently
# built" class of bug dead.
set -u
REAL_SCRIPTS="$(cd "$(dirname "$0")" && pwd)"
PASS=0; FAIL=0; FAILED=()
ok(){ PASS=$((PASS+1)); printf ' ok %s\n' "$1"; }
no(){ FAIL=$((FAIL+1)); FAILED+=("$1"); printf ' FAIL %s\n %s\n' "$1" "${2:-}"; }
assert_eq(){ [ "$2" = "$3" ] && ok "$1" || no "$1" "expected [$3] got [$2]"; }
assert_contains(){ grep -qF "$3" <<<"$2" && ok "$1" || no "$1" "output missing [$3]"; }
assert_not_contains(){ grep -qF "$3" <<<"$2" && no "$1" "output unexpectedly has [$3]" || ok "$1"; }
FIX="$(mktemp -d)"; trap 'rm -rf "$FIX"' EXIT
mkdir -p "$FIX/local/scripts" "$FIX/local/recipes" "$FIX/tarballs"
cp "$REAL_SCRIPTS/verify-external-source-versions.sh" "$REAL_SCRIPTS/sync-recipe-source.sh" "$FIX/local/scripts/"
VERIFY="$FIX/local/scripts/verify-external-source-versions.sh"
SYNC="$FIX/local/scripts/sync-recipe-source.sh"
git -C "$FIX" init -q; git -C "$FIX" config user.email t@t; git -C "$FIX" config user.name t
# mk_tar <out.tar> <topdir> <relpath:content>... (content may contain \n)
mk_tar(){ local out="$1" top="$2"; shift 2; local d; d="$(mktemp -d)"; mkdir -p "$d/$top"
for spec in "$@"; do local rel="${spec%%:*}" body="${spec#*:}"; mkdir -p "$d/$top/$(dirname "$rel")"; printf '%b' "$body" >"$d/$top/$rel"; done
tar cf "$out" -C "$d" "$top"; rm -rf "$d"; }
b3(){ b3sum "$1" | awk '{print $1}'; }
# mk_recipe <name> <tar-url> <blake3|-> ; creates recipe dir, prints its path
mk_recipe(){ local n="$1" url="$2" bl="$3"; local dir="$FIX/local/recipes/$n"; mkdir -p "$dir"
{ echo '[package]'; echo "name = \"$n\""; echo '[source]'; echo "tar = \"$url\"";
[ "$bl" != "-" ] && echo "blake3 = \"$bl\""; } >"$dir/recipe.toml"; echo "$dir"; }
echo "=== ver_of parsing (via a probe recipe per URL; validator must not crash/misparse) ==="
# We test parsing indirectly: a consistent vendored recipe at version V must PASS.
prep_vendored(){ # <name> <url> <version> <marker: cmake|kf|stamp>
local n="$1" url="$2" v="$3" mk="$4"; local top="src-$v"
local tarf="$FIX/tarballs/$n.tar"; mk_tar "$tarf" "$top" "f.c:int x;\n"
local dir; dir="$(mk_recipe "$n" "$url" "$(b3 "$tarf")")"; cp "$tarf" "$dir/source.tar"
mkdir -p "$dir/source"; echo "int x;" >"$dir/source/f.c"
case "$mk" in
cmake) printf 'set(QT_REPO_MODULE_VERSION "%s")\n' "$v" >"$dir/source/.cmake.conf";;
kf) printf 'cmake_minimum_required(VERSION 3.16)\nset(KF_VERSION "%s")\n' "$v" >"$dir/source/CMakeLists.txt";;
stamp) printf '%s\n' "$v" >"$dir/source/.redbear-src-version";;
esac
# make source.tar top-dir carry the right version too
( cd "$FIX/tarballs" && rm -rf t && mkdir t && cd t && mk_tar "$dir/source.tar" "$top" "f.c:int x;\n" )
# fix recipe blake3 to the final source.tar
sed -i "s|blake3 = .*|blake3 = \"$(b3 "$dir/source.tar")\"|" "$dir/recipe.toml"
}
prep_vendored qtstyle "https://x/qt/6.11/6.11.1/submodules/qtbase-everywhere-src-6.11.1.tar.xz" 6.11.1 cmake
prep_vendored mesastyle "https://x/mesa/mesa-26.1.4.tar.gz" 26.1.4 stamp
prep_vendored konsole "https://x/konsole-26.04.3.tar.xz" 26.04.3 stamp
prep_vendored kfstyle "https://x/frameworks/6.28/kf6-kio-6.28.0.tar.xz" 6.28.0 kf
out="$($VERIFY --quiet 2>&1)"; rc=$?
assert_eq "V1 all-consistent PASS (parses qt path/mesa/konsole-leadingzero/kf)" "$rc" "0"
echo "=== validator divergence detection (no false negatives) ==="
# V2 vendored source/ marker mismatch
d="$(mk_recipe divmarker "https://x/foo-2.0.0.tar.xz" -)"; mkdir -p "$d/source"; printf '%s\n' "1.0.0" >"$d/source/.redbear-src-version"
out="$($VERIFY 2>&1)"; rc=$?
assert_eq "V2 source/ stamp 1.0.0 vs url 2.0.0 -> FAIL" "$rc" "1"
assert_contains "V2 names the recipe" "$out" "divmarker"
rm -rf "$d"
# V3 stale source.tar blake3
tarf="$FIX/tarballs/blk.tar"; mk_tar "$tarf" "foo-3.0.0" "f:x"
d="$(mk_recipe divblake "https://x/foo-3.0.0.tar.xz" "$(b3 "$tarf")")"; printf 'WRONG' >"$d/source.tar"
out="$($VERIFY 2>&1)"; rc=$?
assert_eq "V3 source.tar blake3 mismatch -> FAIL" "$rc" "1"; rm -rf "$d"
# V4 source.tar topdir version mismatch
tarf="$FIX/tarballs/td.tar"; mk_tar "$tarf" "foo-3.0.0" "f:x"
d="$(mk_recipe divtd "https://x/foo-4.0.0.tar.xz" "$(b3 "$tarf")")"; cp "$tarf" "$d/source.tar"
out="$($VERIFY 2>&1)"; rc=$?
assert_eq "V4 source.tar is 3.0.0 but url 4.0.0 -> FAIL" "$rc" "1"; rm -rf "$d"
echo "=== validator skip/no-false-positive cases ==="
# V5 git recipe (no tar=)
d="$FIX/local/recipes/gitrec"; mkdir -p "$d"; printf '[source]\ngit = "https://x/y.git"\nrev = "abc"\n' >"$d/recipe.toml"
out="$($VERIFY --quiet 2>&1)"; rc=$?; assert_eq "V5 git recipe ignored (still PASS overall)" "$rc" "0"; rm -rf "$d"
# V6 no source.tar and no source/
d="$(mk_recipe barerec "https://x/foo-1.0.0.tar.xz" -)"
out="$($VERIFY --quiet 2>&1)"; rc=$?; assert_eq "V6 no artifacts -> not flagged" "$rc" "0"; rm -rf "$d"
# V7 transient consistent (source.tar matches, no source/)
tarf="$FIX/tarballs/tr.tar"; mk_tar "$tarf" "foo-5.0.0" "f:x"
d="$(mk_recipe transok "https://x/foo-5.0.0.tar.xz" "$(b3 "$tarf")")"; cp "$tarf" "$d/source.tar"
out="$($VERIFY --quiet 2>&1)"; rc=$?; assert_eq "V7 transient+correct tar -> PASS" "$rc" "0"; rm -rf "$d"
# V14 commented tar= must NOT be treated as the tar line
d="$FIX/local/recipes/commented"; mkdir -p "$d/source"
printf '[source]\n# tar = "https://x/foo-9.9.9.tar.xz"\ntar = "https://x/foo-1.0.0.tar.xz"\n' >"$d/recipe.toml"
printf '%s\n' "1.0.0" >"$d/source/.redbear-src-version"
out="$($VERIFY --quiet 2>&1)"; rc=$?; assert_eq "V14 commented tar= ignored, real line used -> PASS" "$rc" "0"; rm -rf "$d"
echo "=== engine: skip/no-op safety ==="
# E1 transient -> skip (no rebase attempt)
tarf="$FIX/tarballs/e1.tar"; mk_tar "$tarf" "foo-5.0.0" "f:x"
d="$(mk_recipe eng_transient "https://x/foo-5.0.0.tar.xz" "$(b3 "$tarf")")"; cp "$tarf" "$d/source.tar"
out="$($SYNC --check eng_transient 2>&1)"; assert_contains "E1 transient skipped" "$out" "transient"; rm -rf "$d"
# E2 unknown marker -> skip, never rebase
d="$(mk_recipe eng_unknown "https://x/foo-2.0.0.tar.xz" -)"; mkdir -p "$d/source"; echo "code" >"$d/source/f.c"
out="$($SYNC eng_unknown 2>&1)"; assert_contains "E2 unknown-marker skipped (no clobber)" "$out" "no-marker"
assert_eq "E2 source/ untouched" "$(cat "$d/source/f.c")" "code"; rm -rf "$d"
echo "=== engine: real rebase via file:// tarball ==="
# E4 auto-ready divergent (0 patches, 0 baked): source/ 1.0.0 -> pristine 2.0.0
newtar="$FIX/tarballs/e4-2.0.0.tar"; mk_tar "$newtar" "app-2.0.0" ".redbear-src-version:2.0.0\n" "main.c:v2\n" "new_only.c:added\n"
d="$(mk_recipe eng_ready "file://$newtar" "$(b3 "$newtar")")"
mkdir -p "$d/source"; printf '1.0.0\n' >"$d/source/.redbear-src-version"; printf 'v1\n' >"$d/source/main.c"; printf 'gone\n' >"$d/source/old_only.c"
out="$($SYNC eng_ready 2>&1)"; assert_contains "E4 reports ready" "$out" "ready"
assert_eq "E4 source/ now v2 content" "$(cat "$d/source/main.c")" "v2"
assert_eq "E4 stamp updated to 2.0.0" "$(cat "$d/source/.redbear-src-version")" "2.0.0"
[ -f "$d/source/new_only.c" ] && ok "E4 new file added" || no "E4 new file added" "new_only.c missing"
[ -f "$d/source/old_only.c" ] && no "E4 stale file removed" "old_only.c still present" || ok "E4 stale file removed (rsync --delete)"
# E9 idempotency
out="$($SYNC --check eng_ready 2>&1)"; assert_contains "E9 second run consistent" "$out" "consistent"; rm -rf "$d"
# E5/E6 patch apply vs reject
newtar="$FIX/tarballs/e5-2.0.0.tar"; mk_tar "$newtar" "app-2.0.0" ".redbear-src-version:2.0.0\n" "f.c:line1\nline2\nline3\n"
d="$(mk_recipe eng_patch "file://$newtar" "$(b3 "$newtar")"); "
d="$FIX/local/recipes/eng_patch"
printf 'tar = "file://%s"\nblake3 = "%s"\npatches = [ "add.patch" ]\n' "$newtar" "$(b3 "$newtar")" >>"$d/recipe.toml" 2>/dev/null
# rebuild recipe cleanly
{ echo '[package]'; echo 'name="eng_patch"'; echo '[source]'; echo "tar = \"file://$newtar\""; echo "blake3 = \"$(b3 "$newtar")\""; echo 'patches = ["add.patch"]'; } >"$d/recipe.toml"
printf -- '--- a/f.c\n+++ b/f.c\n@@ -1,3 +1,4 @@\n line1\n+INSERTED\n line2\n line3\n' >"$d/add.patch"
mkdir -p "$d/source"; printf '1.0.0\n' >"$d/source/.redbear-src-version"; printf 'line1\nline2\nline3\n' >"$d/source/f.c"
out="$($SYNC eng_patch 2>&1)"; assert_contains "E5 patch applies -> ready" "$out" "ready"
assert_contains "E5 patch content baked" "$(cat "$d/source/f.c")" "INSERTED"
# now break the patch (context won't match) and a fresh divergent state
printf '1.0.0\n' >"$d/source/.redbear-src-version"
printf -- '--- a/f.c\n+++ b/f.c\n@@ -1,3 +1,4 @@\n NOMATCH\n+INSERTED\n line2\n line3\n' >"$d/add.patch"
out="$($SYNC eng_patch 2>&1)"; rc=$?
assert_contains "E6 unappliable patch -> PATCH-REJECT" "$out" "REJECT"
assert_eq "E6 rejects with RC=2" "$rc" "2"
assert_eq "E6 source/ NOT modified on reject" "$(cat "$d/source/.redbear-src-version")" "1.0.0"; rm -rf "$d"
echo "=== decorrupt unit (via engine helper sourced) ==="
# extract and test decorrupt directly
tmpf="$FIX/dc.in"; printf 'a\nx\nx\nx\nx\nx\nb\n}\n}\nc\n' >"$tmpf" # x*5 corruption; }*2 legit
dc_out="$(bash -c 'source "'"$SYNC"'" 2>/dev/null; decorrupt "'"$tmpf"'"' 2>/dev/null || true)"
# decorrupt is defined mid-script; source may run main. Fallback: inline awk identical to script.
dc_out="$(awk '{a[NR]=$0} END{i=1;while(i<=NR){j=i;while(j<NR&&a[j+1]==a[i]&&a[i]!="")j++; if(j-i+1>=4&&a[i]!="")print a[i]; else for(k=i;k<=j;k++)print a[k]; i=j+1}}' "$tmpf")"
assert_eq "E11 corruption run x5 -> 1" "$(grep -c '^x$' <<<"$dc_out")" "1"
assert_eq "E11 legit run }x2 preserved" "$(grep -c '^}$' <<<"$dc_out")" "2"
echo "=== E12 download failure -> DL-FAIL, no write ==="
d="$(mk_recipe eng_dlfail "file:///nonexistent/foo-2.0.0.tar.xz" "0000000000000000000000000000000000000000000000000000000000000000")"
mkdir -p "$d/source"; printf '1.0.0\n' >"$d/source/.redbear-src-version"; printf 'keep\n' >"$d/source/f.c"
out="$($SYNC eng_dlfail 2>&1)"; rc=$?
assert_contains "E12 bad url -> DL-FAIL" "$out" "DL-FAIL"
assert_eq "E12 source/ untouched on DL-FAIL" "$(cat "$d/source/f.c")" "keep"; rm -rf "$d"
echo ""
echo "================ RESULT ================"
echo " PASS: $PASS FAIL: $FAIL"
if [ "$FAIL" -gt 0 ]; then printf ' failed: %s\n' "${FAILED[@]}"; exit 1; fi
echo " ALL GREEN"