git mirror - github.com/owenewans/holy - branch master
clone: https://src.holypkg.eu/holy/

file tests/repo-closure.sh

#!/bin/sh
set -eu
bin=$(realpath "$1")
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT HUP INT TERM
mkdir -p "$tmp/root" "$tmp/repo" "$tmp/tree/HOLY" "$tmp/tree/DATA/usr/share"
build() {
    name=$1
    required=$2
    kind=${3:-package}
    printf 'format holy-package-1\nname %s\nversion 1\nrelease 1\nos linux\narch noarch\nlibc nolibc\n' "$name" > "$tmp/tree/HOLY/meta"
    if test "$name" = or-root; then
        printf 'x-version-family deb\n' >> "$tmp/tree/HOLY/meta"
    fi
    for field in files deps provides hooks origin transform; do : > "$tmp/tree/HOLY/$field"; done
    if test -n "$required"; then
        printf 'require dep-1 %s %s %s any any any - %s metadata\n' \
            "$name" "$kind" "$required" "$required" > "$tmp/tree/HOLY/deps"
    fi
    rm -f "$tmp/tree/DATA/usr/share/"*
    printf '%s\n' "$name" > "$tmp/tree/DATA/usr/share/$name"
    "$bin" manifest generate "$tmp/tree" --output "$tmp/files" > "$tmp/out"
    mv "$tmp/files" "$tmp/tree/HOLY/files"
    "$bin" pack "$tmp/tree" --output "$tmp/repo/$name.holy" > "$tmp/out"
}
build root dep
build dep leaf
build leaf ''
build file-root /usr/share/file-provider file
build file-provider ''
build unrelated ''
build foreign-root foreign-dep
build reuse-root foreign-dep
build foreign-dep ''
build foreign-unused ''
build local-root local-dep
build local-dep ''
build provider-root external-package
build external-package ''
build external-file-root /usr/share/external-file file
build external-file ''
build auto-root auto-child
build auto-child auto-leaf
build auto-leaf ''
build auto-file-root /usr/share/auto-file file
build auto-file ''
build missing-root absent-package
build or-root 'or-first@ge@2|or-second@any@-' package-or
build or-first ''
build or-second ''
mkdir -p "$tmp/other-repo"
mv "$tmp/repo/foreign-dep.holy" "$tmp/other-repo/foreign-dep.holy"
mv "$tmp/repo/foreign-unused.holy" "$tmp/other-repo/foreign-unused.holy"
mkdir -p "$tmp/local-artifacts"
mv "$tmp/repo/local-dep.holy" "$tmp/local-artifacts/local-dep.holy"
mv "$tmp/repo/external-package.holy" "$tmp/other-repo/external-package.holy"
mv "$tmp/repo/external-file.holy" "$tmp/other-repo/external-file.holy"
mv "$tmp/repo/auto-child.holy" "$tmp/other-repo/auto-child.holy"
mv "$tmp/repo/auto-leaf.holy" "$tmp/other-repo/auto-leaf.holy"
mv "$tmp/repo/auto-file.holy" "$tmp/other-repo/auto-file.holy"
mv "$tmp/repo/or-second.holy" "$tmp/other-repo/or-second.holy"
case "$(uname -m)" in
    x86_64)
        arch=x86_64
        printf '.global _start\n_start:\n mov $60, %%rax\n xor %%rdi, %%rdi\n syscall\n' > "$tmp/helper.s"
        ;;
    i?86)
        arch=x86
        printf '.global _start\n_start:\n mov $1, %%eax\n xor %%ebx, %%ebx\n int $0x80\n' > "$tmp/helper.s"
        ;;
    *) arch= ;;
esac
if test -n "$arch"; then
    "${CC:-cc}" -nostdlib -static -o "$tmp/helper" "$tmp/helper.s"
    rm -rf "$tmp/tree/DATA"
    mkdir -p "$tmp/tree/DATA/usr/bin"
    printf 'format holy-package-1\nname helper\nversion 1\nrelease 1\nos linux\narch %s\nlibc nolibc\n' "$arch" > "$tmp/tree/HOLY/meta"
    for field in files deps provides hooks origin transform; do : > "$tmp/tree/HOLY/$field"; done
    cp "$tmp/helper" "$tmp/tree/DATA/usr/bin/closure-helper"
    "$bin" manifest generate "$tmp/tree" --output "$tmp/files" > "$tmp/out"
    mv "$tmp/files" "$tmp/tree/HOLY/files"
    "$bin" pack "$tmp/tree" --output "$tmp/repo/helper.holy" > "$tmp/out"
    rm -rf "$tmp/tree/DATA"
    mkdir -p "$tmp/tree/DATA/usr/bin"
    printf 'format holy-package-1\nname script\nversion 1\nrelease 1\nos linux\narch noarch\nlibc nolibc\n' > "$tmp/tree/HOLY/meta"
    for field in files deps provides hooks origin transform; do : > "$tmp/tree/HOLY/$field"; done
    printf '#!/usr/bin/closure-helper\n' > "$tmp/tree/DATA/usr/bin/closure-script"
    chmod 755 "$tmp/tree/DATA/usr/bin/closure-script"
    "$bin" manifest generate "$tmp/tree" --output "$tmp/files" > "$tmp/out"
    mv "$tmp/files" "$tmp/tree/HOLY/files"
    "$bin" pack "$tmp/tree" --output "$tmp/repo/script.holy" > "$tmp/out"
    cat > "$tmp/foo.c" <<'C'
int foo(void) { return 2; }
C
    cat > "$tmp/wrong.c" <<'C'
int bar(void) { return 2; }
C
    cat > "$tmp/good.map" <<'MAP'
GOOD_1 { global: foo; };
MAP
    cat > "$tmp/bad.map" <<'MAP'
BAD_1 { global: foo; };
MAP
    cat > "$tmp/wrong.map" <<'MAP'
GOOD_1 { global: bar; };
MAP
    printf 'extern int foo(void); int consumer(void) { return foo(); }\n' > "$tmp/consumer.c"
    "${CC:-cc}" -shared -fPIC -o "$tmp/libgood.so" "$tmp/foo.c" \
        -Wl,-soname,libchoice.so.1 -Wl,--version-script="$tmp/good.map" \
        -Wl,--no-as-needed -lc
    "${CC:-cc}" -shared -fPIC -o "$tmp/libbad.so" "$tmp/foo.c" \
        -Wl,-soname,libchoice.so.1 -Wl,--version-script="$tmp/bad.map" \
        -Wl,--no-as-needed -lc
    "${CC:-cc}" -shared -fPIC -o "$tmp/libwrong.so" "$tmp/wrong.c" \
        -Wl,-soname,libchoice.so.1 -Wl,--version-script="$tmp/wrong.map" \
        -Wl,--no-as-needed -lc
    "${CC:-cc}" -shared -fPIC -o "$tmp/libconsumer.so" "$tmp/consumer.c" \
        -L"$tmp" -lgood -Wl,--no-as-needed -lc
    for name in good bad wrong consumer; do
        rm -rf "$tmp/tree/DATA"
        mkdir -p "$tmp/tree/DATA/usr/lib/holy/${arch}-linux-gnu"
        printf 'format holy-package-1\nname %s\nversion 1\nrelease 1\nos linux\narch %s\nlibc glibc\n' \
            "$name" "$arch" > "$tmp/tree/HOLY/meta"
        for field in files deps provides hooks origin transform; do : > "$tmp/tree/HOLY/$field"; done
        cp "$tmp/lib$name.so" "$tmp/tree/DATA/usr/lib/holy/${arch}-linux-gnu/lib$name.so"
        "$bin" manifest generate "$tmp/tree" --output "$tmp/files" > "$tmp/out"
        mv "$tmp/files" "$tmp/tree/HOLY/files"
        "$bin" pack "$tmp/tree" --output "$tmp/repo/$name.holy" > "$tmp/out"
    done
fi
if test -n "$arch"; then
    mv "$tmp/repo/helper.holy" "$tmp/other-repo/helper.holy"
fi
"$bin" repo index "$tmp/repo" > "$tmp/out"
if test -n "$arch"; then
    good_export=$(sha256sum "$tmp/repo/good.holy" | cut -d ' ' -f 1)
    grep -F "elf-export $good_export " "$tmp/repo/index" | grep -q '"foo" "GOOD_1"'
    cp "$tmp/repo/index" "$tmp/original-index"
    sed 's/"foo" "GOOD_1"/"forged" "GOOD_1"/' "$tmp/original-index" > "$tmp/repo/index"
    if "$bin" repo seal "$tmp/repo" > "$tmp/out" 2> "$tmp/err"; then exit 1; fi
    cp "$tmp/original-index" "$tmp/repo/index"
fi
"$bin" repo seal "$tmp/repo" > "$tmp/out"
"$bin" repo index "$tmp/other-repo" > "$tmp/out"
"$bin" repo seal "$tmp/other-repo" > "$tmp/out"
index=$(sed -n 's/^sha256 //p' "$tmp/repo/current")
other_index=$(sed -n 's/^sha256 //p' "$tmp/other-repo/current")
"$bin" db init --root "$tmp/root" > "$tmp/out"
printf '[source fixture]\ntype holy-http\nurl https://fixture.example/holy/\n[source other]\ntype holy-http\nurl https://other.example/holy/\n' > "$tmp/config"
"$bin" source plan --config "$tmp/config" --root "$tmp/root" > "$tmp/plan"
plan=$(sha256sum "$tmp/plan" | cut -d ' ' -f 1)
"$bin" source apply "$tmp/plan" --sha256 "$plan" --root "$tmp/root" > "$tmp/out"
"$bin" source list --root "$tmp/root" > "$tmp/out"
source_id=$(sed -n 's/^source \([0-9a-f]*\) "fixture" active$/\1/p' "$tmp/out")
other_id=$(sed -n 's/^source \([0-9a-f]*\) "other" active$/\1/p' "$tmp/out")
printf 'format holy-mirror-1\nurl "https://fixture.example/holy/"\nindex-sha256 %s\nverification digest-pinned-unsigned\nsource-id %s\n' \
    "$index" "$source_id" > "$tmp/repo/mirror-origin"
printf 'format holy-mirror-1\nurl "https://other.example/holy/"\nindex-sha256 %s\nverification digest-pinned-unsigned\nsource-id %s\n' \
    "$other_index" "$other_id" > "$tmp/other-repo/mirror-origin"
"$bin" source catalog bind fixture "$tmp/repo" --root "$tmp/root" > "$tmp/out"
"$bin" source catalog bind other "$tmp/other-repo" --root "$tmp/root" > "$tmp/out"
if "$bin" add fixture:missing-root --root "$tmp/root" --yes > "$tmp/out" 2> "$tmp/err"; then
    exit 1
else
    test "$?" -eq 4
fi
test ! -e "$tmp/root/usr/share/missing-root"
if "$bin" add fixture:foreign-root --candidate other:foreign-dep \
    --candidate other:foreign-unused --root "$tmp/root" \
    > "$tmp/out" 2> "$tmp/err" < /dev/null; then exit 1; else test "$?" -eq 3; fi
test ! -e "$tmp/root/usr/share/foreign-root"
"$bin" add fixture:foreign-root --candidate other:foreign-dep \
    --candidate other:foreign-unused --root "$tmp/root" --yes > "$tmp/out" 2> "$tmp/err"
foreign_hash=$(sha256sum "$tmp/other-repo/foreign-dep.holy" | cut -d ' ' -f 1)
test -f "$tmp/root/usr/share/foreign-root"
test -f "$tmp/root/usr/share/foreign-dep"
test ! -e "$tmp/root/usr/share/foreign-unused"
grep -q "$other_id" "$tmp/root/var/lib/holypkg/installed/$foreign_hash/source"
if "$bin" add fixture:local-root \
    --candidate-local "other=$tmp/local-artifacts/local-dep.holy" \
    --root "$tmp/root" > "$tmp/out" 2> "$tmp/err" < /dev/null; then
    exit 1
else
    test "$?" -eq 3
fi
test ! -e "$tmp/root/usr/share/local-root"
if "$bin" add fixture:local-root \
    --candidate-local "absent=$tmp/local-artifacts/local-dep.holy" \
    --root "$tmp/root" --yes > "$tmp/out" 2> "$tmp/err"; then
    exit 1
else
    test "$?" -eq 6
fi
"$bin" add fixture:local-root \
    --candidate-local "other=$tmp/local-artifacts/local-dep.holy" \
    --root "$tmp/root" --yes > "$tmp/out" 2> "$tmp/err"
test -f "$tmp/root/usr/share/local-root"
test -f "$tmp/root/usr/share/local-dep"
local_hash=$(sha256sum "$tmp/local-artifacts/local-dep.holy" | cut -d ' ' -f 1)
grep -q "$other_id" "$tmp/root/var/lib/holypkg/installed/$local_hash/source"
"$bin" db check --all --root "$tmp/root" > "$tmp/out"
mkdir -p "$tmp/third-repo"
cp "$tmp/other-repo/auto-child.holy" "$tmp/third-repo/auto-child.holy"
"$bin" repo index "$tmp/third-repo" > "$tmp/out"
"$bin" repo seal "$tmp/third-repo" > "$tmp/out"
third_index=$(sed -n 's/^sha256 //p' "$tmp/third-repo/current")
printf '[source fixture]\ntype holy-http\nurl https://fixture.example/holy/\n[source other]\ntype holy-http\nurl https://other.example/holy/\n[source third]\ntype holy-http\nurl https://third.example/holy/\n[source foreign]\ntype apk\nrepo main https://foreign.example/alpine/\n' > "$tmp/three-sources"
"$bin" source plan --config "$tmp/three-sources" --root "$tmp/root" > "$tmp/plan"
plan=$(sha256sum "$tmp/plan" | cut -d ' ' -f 1)
"$bin" source apply "$tmp/plan" --sha256 "$plan" --root "$tmp/root" > "$tmp/out"
"$bin" source list --root "$tmp/root" > "$tmp/out"
third_id=$(sed -n 's/^source \([0-9a-f]*\) "third" active$/\1/p' "$tmp/out")
test -n "$third_id"
printf 'format holy-mirror-1\nurl "https://third.example/holy/"\nindex-sha256 %s\nverification digest-pinned-unsigned\nsource-id %s\n' \
    "$third_index" "$third_id" > "$tmp/third-repo/mirror-origin"
"$bin" source catalog bind third "$tmp/third-repo" --root "$tmp/root" > "$tmp/out"
if "$bin" add fixture:auto-root --root "$tmp/root" --yes > "$tmp/out" 2> "$tmp/err"; then
    exit 1
else
    test "$?" -eq 3
fi
grep -q 'provider package:auto-child available from other' "$tmp/err"
grep -q 'provider package:auto-child available from third' "$tmp/err"
grep -q 'decision-required' "$tmp/err"
test ! -e "$tmp/root/usr/share/auto-root"
sed '/^\[source fixture\]$/a parent other' "$tmp/three-sources" > "$tmp/parent-sources"
mkdir -p "$tmp/parent-root"
"$bin" db init --root "$tmp/parent-root" > "$tmp/out"
"$bin" source plan --config "$tmp/parent-sources" --root "$tmp/parent-root" > "$tmp/parent-plan"
parent_plan=$(sha256sum "$tmp/parent-plan" | cut -d ' ' -f 1)
"$bin" source apply "$tmp/parent-plan" --sha256 "$parent_plan" --root "$tmp/parent-root" > "$tmp/out"
grep -q " $other_id \"-\" 0$" "$tmp/parent-root/var/lib/holypkg/sources"
for source in fixture other third; do
    case "$source" in
        fixture) parent_catalog=$tmp/repo ;;
        other) parent_catalog=$tmp/other-repo ;;
        third) parent_catalog=$tmp/third-repo ;;
    esac
    "$bin" source catalog bind "$source" "$parent_catalog" --root "$tmp/parent-root" > "$tmp/out"
done
mkdir -p "$tmp/renamed-parent-root"
cp -a "$tmp/parent-root/." "$tmp/renamed-parent-root/"
sed -e 's/^parent other$/parent preferred/' \
    -e 's/^\[source other\]$/[source preferred]/' \
    "$tmp/parent-sources" > "$tmp/renamed-parent-sources"
"$bin" source plan --config "$tmp/renamed-parent-sources" \
    --root "$tmp/renamed-parent-root" > "$tmp/renamed-parent-plan"
renamed_parent_plan=$(sha256sum "$tmp/renamed-parent-plan" | cut -d ' ' -f 1)
"$bin" source apply "$tmp/renamed-parent-plan" --sha256 "$renamed_parent_plan" \
    --root "$tmp/renamed-parent-root" > "$tmp/out"
"$bin" add fixture:auto-root --root "$tmp/renamed-parent-root" --yes --noninteractive \
    > "$tmp/out" 2> "$tmp/err"
grep -q 'selected preferred for package:auto-child by parent preference' "$tmp/err"
test -f "$tmp/renamed-parent-root/usr/share/auto-child"
"$bin" add fixture:auto-root --root "$tmp/parent-root" --yes --noninteractive \
    > "$tmp/out" 2> "$tmp/err"
grep -q 'selected other for package:auto-child by parent preference' "$tmp/err"
test -f "$tmp/parent-root/usr/share/auto-root"
test -f "$tmp/parent-root/usr/share/auto-child"
auto_child_hash=$(sha256sum "$tmp/other-repo/auto-child.holy" | cut -d ' ' -f 1)
grep -q "$other_id" "$tmp/parent-root/var/lib/holypkg/installed/$auto_child_hash/source"
"$bin" db check --all --root "$tmp/parent-root" > "$tmp/out"
for policy in family priority; do
    policy_root="$tmp/$policy-root"
    policy_config="$tmp/$policy-sources"
    if test "$policy" = family; then
        printf '[source fixture]\ntype holy-http\nurl https://fixture.example/holy/\nfamily workstation\n[source other]\ntype holy-http\nurl https://other.example/holy/\nfamily workstation\npriority -5\n[source third]\ntype holy-http\nurl https://third.example/holy/\nfamily unrelated\npriority 100\n' > "$policy_config"
    else
        printf '[source fixture]\ntype holy-http\nurl https://fixture.example/holy/\n[source other]\ntype holy-http\nurl https://other.example/holy/\npriority 10\n[source third]\ntype holy-http\nurl https://third.example/holy/\npriority 5\n' > "$policy_config"
    fi
    mkdir -p "$policy_root"
    "$bin" db init --root "$policy_root" > "$tmp/out"
    "$bin" source plan --config "$policy_config" --root "$policy_root" > "$tmp/policy-plan"
    policy_plan=$(sha256sum "$tmp/policy-plan" | cut -d ' ' -f 1)
    "$bin" source apply "$tmp/policy-plan" --sha256 "$policy_plan" --root "$policy_root" > "$tmp/out"
    for source in fixture other third; do
        case "$source" in
            fixture) policy_catalog=$tmp/repo ;;
            other) policy_catalog=$tmp/other-repo ;;
            third) policy_catalog=$tmp/third-repo ;;
        esac
        "$bin" source catalog bind "$source" "$policy_catalog" --root "$policy_root" > "$tmp/out"
    done
    "$bin" add fixture:auto-root --root "$policy_root" --yes --noninteractive \
        > "$tmp/out" 2> "$tmp/err"
    grep -q "selected other for package:auto-child by $policy preference" "$tmp/err"
    test -f "$policy_root/usr/share/auto-child"
    "$bin" db check --all --root "$policy_root" > "$tmp/out"
done
for target in choice-root answers-root; do
    mkdir -p "$tmp/$target"
    "$bin" db init --root "$tmp/$target" > "$tmp/out"
    "$bin" source plan --config "$tmp/three-sources" --root "$tmp/$target" > "$tmp/choice-plan"
    choice_plan=$(sha256sum "$tmp/choice-plan" | cut -d ' ' -f 1)
    "$bin" source apply "$tmp/choice-plan" --sha256 "$choice_plan" --root "$tmp/$target" > "$tmp/out"
    for source in fixture other third; do
        case "$source" in
            fixture) catalog=$tmp/repo ;;
            other) catalog=$tmp/other-repo ;;
            third) catalog=$tmp/third-repo ;;
        esac
        "$bin" source catalog bind "$source" "$catalog" --root "$tmp/$target" > "$tmp/out"
    done
done
python3 - "$bin" "$tmp/choice-root" <<'PY'
import os
import pty
import subprocess
import sys

master, slave = pty.openpty()
process = subprocess.Popen([sys.argv[1], "add", "fixture:auto-root",
                            "--root", sys.argv[2], "--yes"], stdin=slave,
                           stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                           text=True)
os.close(slave)
os.write(master, b"other\n")
stdout, stderr = process.communicate(timeout=30)
os.close(master)
assert process.returncode == 0, (process.returncode, stdout, stderr)
assert "Select source for package:auto-child" in stderr
PY
test -f "$tmp/choice-root/usr/share/auto-root"
test -f "$tmp/choice-root/usr/share/auto-child"
"$bin" db check --all --root "$tmp/choice-root" > "$tmp/out"
auto_root_hash=$(sha256sum "$tmp/repo/auto-root.holy" | cut -d ' ' -f 1)
printf 'format holy-answers-1\nsource %s dep-1 other\nsource %s dep-1 third\n' \
    "$auto_root_hash" "$auto_root_hash" > "$tmp/duplicate-answers"
if "$bin" add fixture:auto-root --root "$tmp/answers-root" --yes --noninteractive \
    --answers "$tmp/duplicate-answers" > "$tmp/out" 2> "$tmp/err"; then exit 1
else test "$?" -eq 2; fi
printf 'format holy-answers-1\nsource %s dep-1 absent\n' \
    "$auto_root_hash" > "$tmp/stale-answers"
if "$bin" add fixture:auto-root --root "$tmp/answers-root" --yes --noninteractive \
    --answers "$tmp/stale-answers" > "$tmp/out" 2> "$tmp/err"; then exit 1
else test "$?" -eq 3; fi
test ! -e "$tmp/answers-root/usr/share/auto-root"
printf 'format holy-answers-1\nsource %s dep-1 other' "$auto_root_hash" > "$tmp/answers"
if ! "$bin" add fixture:auto-root --root "$tmp/answers-root" --yes --noninteractive \
    --answers "$tmp/answers" > "$tmp/out" 2> "$tmp/err"; then
    cat "$tmp/err" >&2
    exit 1
fi
test -f "$tmp/answers-root/usr/share/auto-root"
test -f "$tmp/answers-root/usr/share/auto-child"
"$bin" db check --all --root "$tmp/answers-root" > "$tmp/out"
"$bin" source plan --config "$tmp/config" --root "$tmp/root" > "$tmp/plan"
plan=$(sha256sum "$tmp/plan" | cut -d ' ' -f 1)
"$bin" source apply "$tmp/plan" --sha256 "$plan" --root "$tmp/root" > "$tmp/out"
if "$bin" add fixture:auto-root --root "$tmp/root" \
    > "$tmp/out" 2> "$tmp/err" < /dev/null; then
    exit 1
else
    test "$?" -eq 3
fi
test ! -e "$tmp/root/usr/share/auto-root"
"$bin" add fixture:auto-root --root "$tmp/root" --yes > "$tmp/out" 2> "$tmp/err"
test -f "$tmp/root/usr/share/auto-child"
test -f "$tmp/root/usr/share/auto-leaf"
"$bin" add fixture:auto-file-root --root "$tmp/root" --yes > "$tmp/out" 2> "$tmp/err"
test -f "$tmp/root/usr/share/auto-file"
"$bin" add fixture:or-root --root "$tmp/root" --yes > "$tmp/out" 2> "$tmp/err"
test -f "$tmp/root/usr/share/or-root"
test -f "$tmp/root/usr/share/or-second"
test ! -e "$tmp/root/usr/share/or-first"
"$bin" db check --all --root "$tmp/root" > "$tmp/out"
"$bin" add fixture:provider-root --candidate-provider other:package:external-package \
    --root "$tmp/root" --yes > "$tmp/out" 2> "$tmp/err"
test -f "$tmp/root/usr/share/external-package"
if "$bin" add fixture:external-file-root \
    --candidate-provider other:file:/usr/share/missing-provider \
    --root "$tmp/root" --yes > "$tmp/out" 2> "$tmp/err"; then
    exit 1
else
    test "$?" -eq 4
fi
"$bin" add fixture:external-file-root \
    --candidate-provider other:file:/usr/share/external-file \
    --root "$tmp/root" --yes > "$tmp/out" 2> "$tmp/err"
test -f "$tmp/root/usr/share/external-file"
"$bin" db check --all --root "$tmp/root" > "$tmp/out"
if test -n "$arch"; then
    grep -q '"GOOD_1"' "$tmp/repo/index"
    grep -q '"BAD_1"' "$tmp/repo/index"
    bad=$(sha256sum "$tmp/repo/bad.holy" | cut -d ' ' -f 1)
    good=$(sha256sum "$tmp/repo/good.holy" | cut -d ' ' -f 1)
    wrong=$(sha256sum "$tmp/repo/wrong.holy" | cut -d ' ' -f 1)
    grep -F "elf-version $wrong " "$tmp/repo/index" | grep -q '"GOOD_1"'
    grep -F "soname $wrong " "$tmp/repo/index" | grep -q '"libchoice.so.1"'
    cp "$tmp/repo/bad.holy" "$tmp/bad.saved"
    printf 'corrupt\n' > "$tmp/repo/bad.holy"
    if "$bin" add fixture:consumer --root "$tmp/root" --yes > "$tmp/out" 2> "$tmp/err"; then exit 1; fi
    if grep -q 'invalid or stale repository index' "$tmp/err"; then cat "$tmp/err"; exit 1; fi
    test -f "$tmp/root/var/cache/holypkg/objects/sha256/$good.holy"
    test ! -e "$tmp/root/var/cache/holypkg/objects/sha256/$bad.holy"
    test ! -e "$tmp/root/var/cache/holypkg/objects/sha256/$wrong.holy"
    cp "$tmp/bad.saved" "$tmp/repo/bad.holy"
fi
cp "$tmp/repo/dep.holy" "$tmp/dep.saved"
printf 'corrupt\n' > "$tmp/repo/dep.holy"
if "$bin" add fixture:root --root "$tmp/root" --yes > "$tmp/out" 2> "$tmp/err"; then exit 1; fi
test ! -e "$tmp/root/usr/share/root"
cp "$tmp/dep.saved" "$tmp/repo/dep.holy"
unrelated=$(sha256sum "$tmp/repo/unrelated.holy" | cut -d ' ' -f 1)
printf 'corrupt\n' > "$tmp/repo/unrelated.holy"
"$bin" add fixture:root --root "$tmp/root" --yes > "$tmp/out" 2> "$tmp/err"
for name in root dep leaf; do
    test -f "$tmp/root/usr/share/$name"
    digest=$(sha256sum "$tmp/repo/$name.holy" | cut -d ' ' -f 1)
    test -f "$tmp/root/var/cache/holypkg/objects/sha256/$digest.holy"
done
test ! -e "$tmp/root/var/cache/holypkg/objects/sha256/$unrelated.holy"
"$bin" db check --all --root "$tmp/root" > "$tmp/out"
"$bin" add fixture:file-root --root "$tmp/root" --yes > "$tmp/out" 2> "$tmp/err"
test -f "$tmp/root/usr/share/file-root"
test -f "$tmp/root/usr/share/file-provider"
if test -n "$arch"; then
    "$bin" add fixture:script --candidate-provider other:command:closure-helper \
        --root "$tmp/root" --yes > "$tmp/out" 2> "$tmp/err"
    test -x "$tmp/root/usr/bin/closure-helper"
    test -x "$tmp/root/usr/bin/closure-script"
fi
printf '[source fixture]\ntype holy-http\nurl https://fixture.example/holy/\n' > "$tmp/fixture-only"
"$bin" source plan --config "$tmp/fixture-only" --root "$tmp/root" > "$tmp/plan"
plan=$(sha256sum "$tmp/plan" | cut -d ' ' -f 1)
"$bin" source apply "$tmp/plan" --sha256 "$plan" --root "$tmp/root" > "$tmp/out"
"$bin" add fixture:reuse-root --root "$tmp/root" --yes > "$tmp/out" 2> "$tmp/err"
test -f "$tmp/root/usr/share/reuse-root"
"$bin" db check --all --root "$tmp/root" > "$tmp/out"