first commit

This commit is contained in:
bryanpedini committed 2026-10-10 10:37:53 +02:00
commit 1354db6c39
90 files changed
+13123

No files matched your search

+158
View File
@@ -0,0 +1,158 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright (C) 2026 Bryan Joshua Pedini
# fixture.sh - deterministic E2E fixture for RPM distros (dnf: Alma/Rocky/..., zypper: openSUSE)
#
# Builds three dummy packages with rpmbuild, installs version 1.0 of each, publishes
# version 2.0 in a local file:// repo and registers that repo, so that the package
# manager reports exactly these upgrades:
#
# su-dummy-a 1.0-1 -> 2.0-1 (noarch, Requires: su-dummy-b)
# su-dummy-b 1.0-1 -> 2.0-1 (noarch)
# su-dummy-c 1.0-1 -> 2.0-1 (ARCH-SPECIFIC, so the ".x86_64" suffix path is exercised)
#
# Optional (SU_FIXTURE_EXTRAS=1):
# - installs su-dummy-d 1.0 (NOT upgradable): Requires su-dummy-a, /bin/sh (file dep),
# "su-dummy-b >= 1.0" (versioned), "(su-dummy-c if su-dummy-b)" (rich dep) and rpmlib(...)
# -> for reverse-dep / dependency-closure tests;
# - publishes su-dummy-r 1.0 (Requires su-dummy-s) and su-dummy-s 1.0 in the repo, NOT installed
# -> for install/remove/--clean-deps tests.
#
# Re-runnable: re-running resets everything to the "1.0 installed, 2.0 available" state.
#
# Usage (inside the container, as root): bash fixture.sh
# docker run --rm -i -v <project>/discovery/rpm:/d:ro <image> bash /d/fixture.sh
set -euo pipefail
export LC_ALL=C
T0=$SECONDS
log() { printf '[fixture] %s\n' "$*" >&2; }
die() { printf '[fixture] ERROR: %s\n' "$*" >&2; exit 1; }
[ "$(id -u)" -eq 0 ] || die "must run as root"
# ---- 1. backend detection ---------------------------------------------------
BACKEND=
if command -v zypper >/dev/null 2>&1; then BACKEND=zypper
elif command -v dnf >/dev/null 2>&1; then BACKEND=dnf
elif command -v yum >/dev/null 2>&1; then BACKEND=yum
else die "neither zypper nor dnf/yum found"; fi
log "backend=$BACKEND"
TOP=/var/tmp/su-fixture # rpmbuild topdir
REPO=/var/lib/su-dummy-repo # file:// repo (only 2.0 packages)
SPEC_DIR=$TOP/SPECS
# ---- 2. build tools ---------------------------------------------------------
t=$SECONDS
case $BACKEND in
zypper) zypper --non-interactive --quiet install --no-recommends rpm-build createrepo_c >/dev/null ;;
dnf|yum) "$BACKEND" -y -q install --setopt=install_weak_deps=False rpm-build createrepo_c >/dev/null ;;
esac
command -v rpmbuild >/dev/null || die "rpmbuild missing after install"
command -v createrepo_c >/dev/null || die "createrepo_c missing after install"
log "build tools installed in $((SECONDS - t))s"
# ---- 3. build RPMs ----------------------------------------------------------
rm -rf "$TOP" "$REPO"
mkdir -p "$TOP"/{BUILD,BUILDROOT,RPMS,SRPMS,SOURCES,SPECS} "$REPO"
# mkspec <name> <version> <arch|noarch> <extra spec header lines...>
mkspec() {
local name=$1 ver=$2 arch=$3; shift 3
local f=$SPEC_DIR/$name-$ver.spec
{
echo "Name: $name"
echo "Version: $ver"
echo "Release: 1"
echo "Summary: skeptical-updater dummy $name (v$ver)"
echo "License: MIT"
[ "$arch" = noarch ] && echo "BuildArch: noarch"
local l; for l in "$@"; do echo "$l"; done
echo "%global debug_package %{nil}"
echo "%description"
echo "Dummy package $name version $ver for skeptical-updater tests."
echo ""
echo "Second paragraph of $name $ver (blank line above on purpose)."
echo "%install"
echo "mkdir -p %{buildroot}/usr/share/su-dummy"
echo "echo '$name $ver' > %{buildroot}/usr/share/su-dummy/$name"
echo "%files"
echo "/usr/share/su-dummy/$name"
} > "$f"
printf '%s\n' "$f"
}
build() { rpmbuild -bb --quiet --define "_topdir $TOP" "$1" >/dev/null 2>"$TOP/rpmbuild.err" \
|| { cat "$TOP/rpmbuild.err" >&2; die "rpmbuild failed for $1"; }; }
t=$SECONDS
for v in 1.0 2.0; do
build "$(mkspec su-dummy-a $v noarch 'Requires: su-dummy-b')"
build "$(mkspec su-dummy-b $v noarch)"
build "$(mkspec su-dummy-c $v arch)"
done
if [ "${SU_FIXTURE_EXTRAS:-0}" = 1 ]; then
build "$(mkspec su-dummy-s 1.0 noarch)" # published in the repo, NOT installed
build "$(mkspec su-dummy-r 1.0 noarch 'Requires: su-dummy-s')" # (used to test remove/--clean-deps)
build "$(mkspec su-dummy-d 1.0 noarch \
'Requires: su-dummy-a' \
'Requires: /bin/sh' \
'Requires: su-dummy-b >= 1.0' \
'Requires: (su-dummy-c if su-dummy-b)' \
'Requires: rpmlib(CompressedFileNames)')"
fi
log "rpmbuild done in $((SECONDS - t))s"
# ---- 4. install 1.0 (rpm directly: distro-agnostic, resets to 1.0 on re-run) ----
shopt -s nullglob
v1=( "$TOP"/RPMS/*/su-dummy-[abc]-1.0-1.*.rpm )
[ "${#v1[@]}" -eq 3 ] || die "expected 3 built 1.0 rpms, got ${#v1[@]}"
rpm -Uvh --oldpackage --replacepkgs "${v1[@]}" >/dev/null
if [ "${SU_FIXTURE_EXTRAS:-0}" = 1 ]; then
rpm -Uvh --oldpackage --replacepkgs "$TOP"/RPMS/noarch/su-dummy-d-1.0-1.*.rpm >/dev/null
fi
# ---- 5. publish 2.0 as a local repo -------------------------------------------
v2=( "$TOP"/RPMS/*/su-dummy-[abc]-2.0-1.*.rpm )
[ "${#v2[@]}" -eq 3 ] || die "expected 3 built 2.0 rpms, got ${#v2[@]}"
cp "${v2[@]}" "$REPO"/
if [ "${SU_FIXTURE_EXTRAS:-0}" = 1 ]; then cp "$TOP"/RPMS/noarch/su-dummy-[rs]-1.0-1.*.rpm "$REPO"/; fi
createrepo_c --quiet "$REPO" >/dev/null
# ---- 6. register repo ---------------------------------------------------------
case $BACKEND in
zypper)
zypper --non-interactive --quiet removerepo su-dummy >/dev/null 2>&1 || true
zypper --non-interactive --quiet addrepo --no-gpgcheck --no-check --refresh "file://$REPO" su-dummy >/dev/null
t=$SECONDS
zypper --non-interactive --quiet refresh su-dummy >/dev/null
;;
dnf|yum)
cat > /etc/yum.repos.d/su-dummy.repo <<REPOEOF
[su-dummy]
name=skeptical-updater dummy packages
baseurl=file://$REPO
enabled=1
gpgcheck=0
repo_gpgcheck=0
metadata_expire=0
REPOEOF
t=$SECONDS
"$BACKEND" -q makecache --repo su-dummy >/dev/null
;;
esac
log "repo refresh in $((SECONDS - t))s"
# ---- 7. verify: the three must be listed as upgradable --------------------------
want="su-dummy-a su-dummy-b su-dummy-c"
case $BACKEND in
zypper) listing=$(zypper --non-interactive --quiet list-updates 2>&1 || true) ;;
dnf|yum) listing=$("$BACKEND" -q check-update 2>&1 || true) ;;
esac
bad=0
for p in $want; do
printf '%s\n' "$listing" | grep -Eq "(^|[| ])$p([. ]|$)" || { log "NOT listed as upgradable: $p"; bad=1; }
done
if [ "$bad" -ne 0 ]; then printf '%s\n' "$listing" >&2; die "fixture verification failed"; fi
log "OK: su-dummy-{a,b,c} 1.0 installed and 2.0 offered by repo 'su-dummy' (total ${SECONDS}s, since start $((SECONDS - T0))s)"