test(installer): make state fixture CI-portable
ci/woodpecker/pr/ci Pipeline failed
ci/woodpecker/pr/greenfield-install Pipeline was successful

This commit is contained in:
2026-08-05 13:46:46 -05:00
parent 999b7e0862
commit 8b0678393d
+66 -9
View File
@@ -11,6 +11,22 @@ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
TMP="$(mktemp -d "${TMPDIR:-/tmp}/mosaic-install-state-test.XXXXXX")"
trap 'rm -rf "$TMP"' EXIT
failures=0
COMPAT_BIN="$TMP/compat-bin"
mkdir -p "$COMPAT_BIN"
cat > "$COMPAT_BIN/realpath" <<'REALPATH'
#!/usr/bin/env python3
import os
import sys
args = sys.argv[1:]
mode = args.pop(0) if args and args[0] in ("-e", "-m") else "-m"
if args and args[0] == "--":
args.pop(0)
if len(args) != 1 or (mode == "-e" and not os.path.exists(args[0])):
raise SystemExit(1)
print(os.path.realpath(args[0]))
REALPATH
chmod 0755 "$COMPAT_BIN/realpath"
fail_case() { printf '[test] FAIL: %s\n' "$*" >&2; failures=$((failures + 1)); }
pass_case() { printf '[test] PASS: %s\n' "$*"; }
@@ -18,11 +34,28 @@ pass_case() { printf '[test] PASS: %s\n' "$*"; }
fingerprint() {
local dir="$1"
if [[ ! -d "$dir" ]]; then printf 'ABSENT\n'; return; fi
(
cd "$dir" || exit 1
find . -mindepth 1 -printf '%P|%y|%m|%u|%g|%l\n' | LC_ALL=C sort
find . -type f -print0 | LC_ALL=C sort -z | xargs -0 -r sha256sum
) | sha256sum | awk '{print $1}'
python3 - "$dir" <<'PY'
import hashlib
import os
import stat
import sys
root = os.path.abspath(sys.argv[1])
rows = []
for current, dirs, files in os.walk(root, topdown=True, followlinks=False):
for name in dirs + files:
path = os.path.join(current, name)
rel = os.path.relpath(path, root)
meta = os.lstat(path)
target = os.readlink(path) if stat.S_ISLNK(meta.st_mode) else ""
digest = ""
if stat.S_ISREG(meta.st_mode):
with open(path, "rb") as handle:
digest = hashlib.sha256(handle.read()).hexdigest()
rows.append((rel, stat.S_IFMT(meta.st_mode), stat.S_IMODE(meta.st_mode), meta.st_uid, meta.st_gid, target, digest))
payload = "\n".join("|".join(map(str, row)) for row in sorted(rows)).encode()
print(hashlib.sha256(payload).hexdigest())
PY
}
make_fake_npm() {
@@ -97,6 +130,30 @@ good_prefix="$good_home/.npm-global"
good_mosaic="$good_home/.config/mosaic"
mkdir -p "$good_bin" "$good_prefix/bin" "$good_mosaic/skills/declared-skill"
make_fake_npm "$good_bin"
cp "$COMPAT_BIN/realpath" "$good_bin/realpath"
cat > "$good_bin/id" <<'ID'
#!/bin/bash
case "${1:-}" in
-u) echo 1001 ;;
-g) echo 1001 ;;
-un) echo fixture-user ;;
*) exec /bin/id "$@" ;;
esac
ID
cat > "$good_bin/stat" <<'STAT'
#!/bin/bash
if [[ "${1:-} ${2:-}" == '-c %u' ]]; then echo 1001; exit 0; fi
exec /bin/stat "$@"
STAT
cat > "$good_bin/curl" <<'CURL'
#!/bin/bash
exit 0
CURL
cat > "$good_bin/ldd" <<'LDD'
#!/bin/bash
echo 'ldd (GNU libc) 2.36'
LDD
chmod 0755 "$good_bin/id" "$good_bin/stat" "$good_bin/curl" "$good_bin/ldd"
cat > "$good_prefix/bin/mosaic" <<'CLI'
#!/usr/bin/env bash
printf '0.0.50-next.999\n'
@@ -175,7 +232,7 @@ for phase in P2 P3 P4 P5 P6 P7 P8; do
set +e
HOME="$home" MOSAIC_HOME="$home/.config/mosaic" MOSAIC_PREFIX="$home/.npm-global" \
MOSAIC_INSTALL_STATE_DIR="$state" MOSAIC_INSTALL_FAULT_AFTER="$phase" \
MOSAIC_NO_COLOR=1 bash "$ROOT/tools/install.sh" --state-machine-self-test \
MOSAIC_NO_COLOR=1 PATH="$COMPAT_BIN:$PATH" bash "$ROOT/tools/install.sh" --state-machine-self-test \
>"$TMP/fault-$phase.log" 2>&1
status=$?
set -e
@@ -205,7 +262,7 @@ for case_name in root-target home-target overlap-target; do
before="$(fingerprint "$unsafe_home")"
set +e
HOME="$unsafe_home" MOSAIC_HOME="$unsafe_mosaic" MOSAIC_PREFIX="$unsafe_prefix" \
MOSAIC_NO_COLOR=1 PATH="$check_bin:/usr/local/bin:/usr/bin:/bin" \
MOSAIC_NO_COLOR=1 PATH="$good_bin:/usr/local/bin:/usr/bin:/bin" \
bash "$ROOT/tools/install.sh" --check --next >"$TMP/$case_name.log" 2>&1
status=$?
set -e
@@ -222,7 +279,7 @@ mkdir -p "$symlink_home" "$symlink_outside"
ln -s "$symlink_outside" "$symlink_home/.config"
set +e
HOME="$symlink_home" MOSAIC_HOME="$symlink_home/.config/mosaic" MOSAIC_PREFIX="$symlink_home/.npm-global" \
MOSAIC_NO_COLOR=1 PATH="$check_bin:/usr/local/bin:/usr/bin:/bin" \
MOSAIC_NO_COLOR=1 PATH="$good_bin:/usr/local/bin:/usr/bin:/bin" \
bash "$ROOT/tools/install.sh" --check --next >"$TMP/symlink-target.log" 2>&1
status=$?
set -e
@@ -240,7 +297,7 @@ printf '{"status":"in-progress","journal":"%s"}\n' "$stale_state/dead-run/journa
set +e
HOME="$stale_home" MOSAIC_HOME="$stale_home/.config/mosaic" MOSAIC_PREFIX="$stale_home/.npm-global" \
MOSAIC_INSTALL_STATE_DIR="$stale_state" MOSAIC_INSTALL_FAULT_AFTER=P2 MOSAIC_NO_COLOR=1 \
bash "$ROOT/tools/install.sh" --state-machine-self-test >"$TMP/stale.log" 2>&1
PATH="$COMPAT_BIN:$PATH" bash "$ROOT/tools/install.sh" --state-machine-self-test >"$TMP/stale.log" 2>&1
status=$?
set -e
[[ "$status" -eq 97 ]] || fail_case "stale projection recovery expected injected status 97, got $status"