N?? and `show PKG` now print the installed record in the package
manager's own key/value layout, after one line explaining the format:
# lines starting with > come from the upstream candidate: a differing
value, or a field the installed record lacks
After each field whose candidate value differs comes the candidate's
line prefixed with "> "; fields only the candidate has are appended the
same way; installed-only fields stay; identical fields print once.
Multi-line values (pacman Optional Deps, dnf Description, RFC-822
continuation lines) are compared as blocks and a differing candidate
block gets "> " on every line. A package that is not installed shows the
candidate alone ("# not installed: this is the upstream candidate").
Merged where the backend gives comparable records for both sides:
- pacman: -Qi vs -Si REPO/PKG, REPO = the first repository -Sl lists
- apt: dpkg-query -s (Status, Conffiles, the long description; richer
than apt-cache show PKG=<installed>, which gives the archive record
when that version is still listed) vs apt-cache show --no-all-versions;
Description-xx pairs with Description and a one-line candidate
Description equal to the installed first line counts as identical
(the archives ship the long text in Translation files)
- dnf: info --installed vs info --upgrades (--available lists other
architectures first and nothing for an up-to-date package); not
installed: --available; dnf5's differently padded keys are re-padded
zypper keeps `zypper info --requires`: rpm -qi and zypper info share
almost no keys and zypper cannot print the installed record itself.
No candidate, or not exactly one record per side, keeps the old output.
Formats verified in containers and recorded in discovery/*.md. Unit
tests replay recorded pacman, apt, dnf4 and dnf5 records; the E2E suite
checks 2?? on su-dummy-b on all 12 distros.
430 lines
18 KiB
Bash
430 lines
18 KiB
Bash
#!/usr/bin/env bats
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
# Copyright (C) 2026 Bryan Joshua Pedini
|
|
|
|
# E2E: skeptical-updater against the REAL package manager of the container
|
|
# (apt, pacman, dnf or zypper), on the su-dummy-{a,b,c} fixture: 1.0 installed,
|
|
# 2.0 available, su-dummy-a depends on su-dummy-b. Every test starts from that
|
|
# state (e2e_reset) with no statefile and no holds/locks.
|
|
|
|
load helpers
|
|
|
|
setup_file() { e2e_setup_file; }
|
|
setup() { e2e_reset; }
|
|
|
|
# shellcheck source=/dev/null
|
|
zypper_verb() { case $(. /etc/os-release && printf '%s' "$ID") in opensuse-tumbleweed | opensuse-slowroll) echo dist-upgrade ;; *) echo update ;; esac; }
|
|
|
|
@test "banner shows the detected backend and the distro, refresh succeeds" {
|
|
run skeptical-updater list
|
|
assert_success
|
|
assert_line --index 0 "Backend: $BE ($(pretty_name))"
|
|
assert_line --index 1 "Refreshing package lists... done."
|
|
}
|
|
|
|
@test "list shows exactly the three dummies 1.0 -> 2.0" {
|
|
run skeptical-updater list --no-refresh
|
|
assert_success
|
|
assert_line "3 upgradable, 0 trusted (hidden, use --all to show), 3 to review:"
|
|
assert_line --regexp '^ \[1\] su-dummy-a +1\.0(-1)? +-> +2\.0(-1)? +[^ ]+$'
|
|
assert_line --regexp '^ \[2\] su-dummy-b +1\.0(-1)? +-> +2\.0(-1)? +[^ ]+$'
|
|
assert_line --regexp '^ \[3\] su-dummy-c +1\.0(-1)? +-> +2\.0(-1)? +[^ ]+$'
|
|
refute_line --regexp '^.\[4\]'
|
|
}
|
|
|
|
@test "N? prints the description, the install reason and who requires it" {
|
|
local -a lines_=()
|
|
local i a=-1 b=-1
|
|
run skeptical-updater --no-refresh <<<$'1?\n2?\nq'
|
|
assert_success
|
|
assert_line --regexp '^su-dummy-a: .*([Dd]ummy|skeptical-updater).*$'
|
|
assert_line --regexp '^su-dummy-b: .*([Dd]ummy|skeptical-updater).*$'
|
|
# [1] su-dummy-a was installed explicitly and nothing needs it; [2] su-dummy-b was installed as
|
|
# a dependency of su-dummy-a - the two lines right under each description, no indentation
|
|
mapfile -t lines_ <<<"$output"
|
|
for i in "${!lines_[@]}"; do
|
|
case ${lines_[i]} in
|
|
'su-dummy-a: '*) a=$i ;;
|
|
'su-dummy-b: '*) b=$i ;;
|
|
esac
|
|
done
|
|
[[ ${lines_[a + 1]} == 'reason: explicitly installed' && ${lines_[a + 2]} == 'required by: nothing' ]] ||
|
|
fail "1? (su-dummy-a): got '${lines_[a + 1]}' / '${lines_[a + 2]}'"
|
|
[[ ${lines_[b + 1]} == 'reason: installed as a dependency' && ${lines_[b + 2]} == 'required by: su-dummy-a' ]] ||
|
|
fail "2? (su-dummy-b): got '${lines_[b + 1]}' / '${lines_[b + 2]}'"
|
|
refute_output --partial 'required by (installed)'
|
|
assert_line 'Quit: nothing was upgraded.'
|
|
}
|
|
|
|
@test "N?? shows the installed record merged with the upstream candidate (zypper: zypper info)" {
|
|
run skeptical-updater --no-refresh <<<$'2??\nq'
|
|
assert_success
|
|
if [[ $BE == zypper ]]; then # no comparable records: the plain zypper info --requires
|
|
assert_line 'Information for package su-dummy-b:'
|
|
refute_line --partial '# lines starting with >'
|
|
return 0
|
|
fi
|
|
assert_line '# lines starting with > come from the upstream candidate: a differing value, or a field the installed record lacks'
|
|
case $BE in
|
|
apt)
|
|
assert_line 'Package: su-dummy-b'
|
|
assert_line 'Status: install ok installed'
|
|
assert_output --partial "$(printf '%s\n' 'Version: 1.0' '> Version: 2.0')"
|
|
assert_line --regexp '^> Filename: .*su-dummy-b_2\.0_all\.deb$'
|
|
;;
|
|
pacman)
|
|
assert_output --partial "$(printf '%s\n' 'Version : 1.0-1' '> Version : 2.0-1')"
|
|
assert_line 'Install Reason : Installed as a dependency for another package'
|
|
assert_line '> Repository : su-dummy'
|
|
;;
|
|
dnf)
|
|
assert_output --partial "$(printf '%s\n' 'Version : 1.0' '> Version : 2.0')"
|
|
assert_output --partial "$(printf '%s\n' 'Repository : @System' '> Repository : su-dummy')"
|
|
;;
|
|
esac
|
|
[[ $(grep -c '^> ' <<<"$output") -ge 2 ]]
|
|
}
|
|
|
|
@test "N+ writes the user row and the dep row; list hides both and counts them" {
|
|
run skeptical-updater --no-refresh <<<$'1+\nq'
|
|
assert_success
|
|
assert_line 'trusted su-dummy-a (+1 dependency: su-dummy-b)'
|
|
[[ -f $STATE_FILE ]]
|
|
[[ $(stat -c %a "$STATE_DIR") == 755 ]]
|
|
run cat "$STATE_FILE"
|
|
assert_line --index 0 '# skeptical-updater trusted packages. Columns: backend package reason added(UTC ISO-8601)'
|
|
assert_line --index 1 --regexp "^$BE"$'\t'"su-dummy-a"$'\t'"user"$'\t''[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9:]{8}Z$'
|
|
assert_line --index 2 --regexp "^$BE"$'\t'"su-dummy-b"$'\t'"dep:su-dummy-a"$'\t''[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9:]{8}Z$'
|
|
run skeptical-updater list --no-refresh
|
|
assert_success
|
|
assert_line "3 upgradable, 2 trusted (hidden, use --all to show), 1 to review:"
|
|
refute_output --partial 'su-dummy-a'
|
|
refute_output --partial 'su-dummy-b'
|
|
assert_line --regexp '^ \[1\] su-dummy-c '
|
|
run skeptical-updater list --no-refresh --all
|
|
assert_success
|
|
assert_line "3 upgradable, 2 trusted (marked with =), 1 to review:"
|
|
assert_line --regexp '^=\[1\] su-dummy-a '
|
|
assert_line --regexp '^=\[2\] su-dummy-b '
|
|
assert_line --regexp '^ \[3\] su-dummy-c '
|
|
}
|
|
|
|
@test "trust / trusted / refresh / untrust from the command line" {
|
|
run skeptical-updater trust su-dummy-a
|
|
assert_success
|
|
assert_output 'trusted su-dummy-a (+1 dependency: su-dummy-b)'
|
|
run skeptical-updater trusted
|
|
assert_success
|
|
assert_line --partial "$BE"$'\t'"su-dummy-a"$'\t'"user"$'\t'
|
|
assert_line --partial "$BE"$'\t'"su-dummy-b"$'\t'"dep:su-dummy-a"$'\t'
|
|
# refresh recomputes the closure: a removed dep row comes back
|
|
sed -i '/dep:su-dummy-a/d' "$STATE_FILE"
|
|
run skeptical-updater refresh
|
|
assert_success
|
|
assert_output 'refreshed the dependency closures of 1 trusted root: 1 added, 0 removed'
|
|
run grep -c $'\tdep:su-dummy-a\t' "$STATE_FILE"
|
|
assert_output 1
|
|
run skeptical-updater untrust su-dummy-a
|
|
assert_success
|
|
assert_output 'untrusted su-dummy-a (2 rows removed)'
|
|
run skeptical-updater trusted
|
|
assert_success
|
|
assert_output '# skeptical-updater trusted packages. Columns: backend package reason added(UTC ISO-8601)'
|
|
}
|
|
|
|
@test "excluding su-dummy-b (2- then enter) upgrades the others" {
|
|
before=$(holds_snapshot)
|
|
run skeptical-updater <<<$'2-\n'
|
|
assert_success
|
|
assert_line 'excluded from this run: su-dummy-b'
|
|
assert_line 'Excluded from this run: su-dummy-b'
|
|
assert_line 'Upgrade finished.'
|
|
[[ $(versions) == "a=2.0 b=1.0 c=2.0" ]] || fail "versions after the run: $(versions)"
|
|
[[ $(holds_snapshot) == "$before" ]] || fail "hold/lock state changed: $(holds_snapshot)"
|
|
run skeptical-updater list --no-refresh
|
|
assert_line --regexp '^ \[1\] su-dummy-b +1\.0'
|
|
}
|
|
|
|
@test "a pre-existing hold/lock/IgnorePkg on su-dummy-c survives a run that excludes su-dummy-b" {
|
|
hold_c
|
|
before=$(holds_snapshot)
|
|
[[ -n $before ]]
|
|
run skeptical-updater list --no-refresh
|
|
assert_line --regexp '^ \[2\] su-dummy-b '
|
|
run skeptical-updater <<<$'2-\n'
|
|
assert_success
|
|
assert_line 'Excluded from this run: su-dummy-b'
|
|
[[ $(versions) == "a=2.0 b=1.0 c=1.0" ]] || fail "versions after the run: $(versions)"
|
|
after=$(holds_snapshot)
|
|
[[ $after == "$before" ]] || fail $'hold/lock state changed.\nbefore:\n'"$before"$'\nafter:\n'"$after"
|
|
if [[ $BE == apt ]]; then [[ ! -e $STATE_DIR/holds.added ]]; fi
|
|
}
|
|
|
|
@test "trusting a package re-includes its excluded dependency" {
|
|
run skeptical-updater <<<$'2-\n1+\n'
|
|
assert_success
|
|
assert_line ' (su-dummy-b is trusted now: no longer excluded from this run)'
|
|
assert_line 'Excluded from this run: none'
|
|
[[ $(versions) == "a=2.0 b=2.0 c=2.0" ]] || fail "versions after the run: $(versions)"
|
|
}
|
|
|
|
@test "enter upgrades everything" {
|
|
run skeptical-updater <<<''
|
|
assert_success
|
|
assert_line 'Excluded from this run: none'
|
|
[[ $(versions) == "a=2.0 b=2.0 c=2.0" ]] || fail "versions after the run: $(versions)"
|
|
run skeptical-updater list --no-refresh
|
|
assert_success
|
|
assert_output --partial 'Nothing to upgrade.'
|
|
}
|
|
|
|
@test "Nx purges su-dummy-c after a y confirmation" {
|
|
run skeptical-updater --no-refresh <<<$'3x\ny\nl\nq'
|
|
assert_success
|
|
assert_line 'Purge su-dummy-c now? [y/N] y'
|
|
assert_line 'purged: su-dummy-c'
|
|
assert_line '2 upgradable, 0 trusted (hidden, use --all to show), 2 to review:'
|
|
[[ $(versions) == "a=1.0 b=1.0 c=absent" ]] || fail "versions after the run: $(versions)"
|
|
[[ $(pkg_ver su-dummy-orphan) == 1.0 ]] || fail "the unrelated orphan was removed"
|
|
}
|
|
|
|
@test "Nx on su-dummy-b is refused: su-dummy-a depends on it; both stay, the row stays listed" {
|
|
run skeptical-updater --no-refresh <<<$'2x\nl\nq'
|
|
assert_success
|
|
assert_line 'not purged: su-dummy-b is required by: su-dummy-a - purge the dependents first'
|
|
refute_output --partial '[y/N]'
|
|
[[ $(grep -c '^ \[2\] su-dummy-b ' <<<"$output") -eq 2 ]] || fail "row 2 left the list"
|
|
[[ $(versions) == "a=1.0 b=1.0 c=1.0" ]] || fail "versions after the run: $(versions)"
|
|
}
|
|
|
|
@test "Nx on su-dummy-a removes su-dummy-b with it (its dependency, nothing else needs it); the orphan survives" {
|
|
run skeptical-updater --no-refresh <<<$'1x\ny\nl\nq'
|
|
assert_success
|
|
assert_line 'Purge su-dummy-a now? This also removes: su-dummy-b [y/N] y'
|
|
assert_line 'purged: su-dummy-a su-dummy-b'
|
|
assert_line '1 upgradable, 0 trusted (hidden, use --all to show), 1 to review:'
|
|
[[ $(versions) == "a=absent b=absent c=1.0" ]] || fail "versions after the run: $(versions)"
|
|
[[ $(pkg_ver su-dummy-orphan) == 1.0 ]] || fail "the unrelated orphan was removed"
|
|
}
|
|
|
|
@test "purging every package ends the session cleanly" {
|
|
run skeptical-updater --no-refresh <<<$'1x\ny\n3x\ny'
|
|
assert_success
|
|
assert_line 'Nothing left to upgrade.'
|
|
[[ $(versions) == "a=absent b=absent c=absent" ]] || fail "versions after the run: $(versions)"
|
|
[[ $(pkg_ver su-dummy-orphan) == 1.0 ]] || fail "the unrelated orphan was removed"
|
|
}
|
|
|
|
@test "Nx answered with anything but y keeps the package" {
|
|
run skeptical-updater --no-refresh <<<$'3x\nn\nq'
|
|
assert_success
|
|
assert_line 'not purged: su-dummy-c'
|
|
[[ $(versions) == "a=1.0 b=1.0 c=1.0" ]]
|
|
}
|
|
|
|
@test "q leaves everything untouched" {
|
|
before=$(holds_snapshot)
|
|
run skeptical-updater <<<$'2-\n1-\nq'
|
|
assert_success
|
|
assert_line 'Quit: nothing was upgraded.'
|
|
[[ $(versions) == "a=1.0 b=1.0 c=1.0" ]]
|
|
[[ $(holds_snapshot) == "$before" ]]
|
|
[[ ! -e $STATE_FILE ]]
|
|
}
|
|
|
|
@test "EOF aborts with exit 2 and changes nothing" {
|
|
before=$(holds_snapshot)
|
|
run skeptical-updater <<<'2-'
|
|
assert_failure 2
|
|
assert_output --partial 'end of input: aborted, nothing was upgraded'
|
|
[[ $(versions) == "a=1.0 b=1.0 c=1.0" ]]
|
|
[[ $(holds_snapshot) == "$before" ]]
|
|
[[ ! -e $STATE_FILE ]]
|
|
}
|
|
|
|
@test "on a terminal, Up recalls the previous line (readline, history of this session only)" {
|
|
pty_session $'1?\r\e[A\rq\r' --no-refresh
|
|
assert_success
|
|
[[ $(grep -c '^su-dummy-a: ' <<<"$output") -eq 2 ]] || fail "1? should have run twice (Up + Enter)"
|
|
assert_line 'Quit: nothing was upgraded.'
|
|
[[ $(versions) == "a=1.0 b=1.0 c=1.0" ]]
|
|
}
|
|
|
|
@test "--dry-run: enter prints the native upgrade command and changes nothing" {
|
|
before=$(holds_snapshot)
|
|
run skeptical-updater --dry-run <<<''
|
|
assert_success
|
|
assert_line --regexp "$(native_upgrade_regex)"
|
|
assert_line 'Dry run: nothing was changed.'
|
|
# (3+: trusting su-dummy-a would hide su-dummy-b and so re-include it)
|
|
run skeptical-updater --dry-run <<<$'2-\n3+\n'
|
|
assert_success
|
|
case $BE in
|
|
apt)
|
|
assert_line '+ apt-mark hold su-dummy-b'
|
|
assert_line '+ apt-mark unhold su-dummy-b'
|
|
;;
|
|
pacman)
|
|
assert_line --regexp '^\+ cp -p -- /tmp/skeptical-updater-db\.[0-9]+\.[A-Za-z0-9]+/sync/su-dummy\.db /var/lib/pacman/sync/$'
|
|
assert_line '+ pacman -Su --noconfirm --ignore su-dummy-b'
|
|
;;
|
|
dnf) assert_line --regexp '^\+ (dnf|yum) -y --setopt=skip_if_unavailable=0 --setopt=\\\*\.metadata_expire=-1 upgrade --exclude=su-dummy-b$' ;;
|
|
zypper)
|
|
assert_line --regexp '^\+ env ZYPP_CONF=.*/zypp\.conf zypper --non-interactive --quiet addlock su-dummy-b$'
|
|
assert_line --regexp "^\+ env ZYPP_CONF=.*/zypp\.conf zypper --non-interactive --no-refresh $(zypper_verb)\$"
|
|
;;
|
|
esac
|
|
assert_line --partial "+ $STATE_FILE add: $BE su-dummy-c user"
|
|
[[ $(versions) == "a=1.0 b=1.0 c=1.0" ]]
|
|
[[ $(holds_snapshot) == "$before" ]]
|
|
[[ ! -e $STATE_DIR ]]
|
|
}
|
|
|
|
@test "read-only commands work unprivileged" {
|
|
if command -v setpriv >/dev/null 2>&1; then
|
|
asuser() { setpriv --reuid=65534 --regid=65534 --clear-groups -- env TMPDIR=/tmp "$@"; }
|
|
elif command -v python3 >/dev/null 2>&1; then # almalinux:10 has neither setpriv nor runuser/su
|
|
asuser() { python3 -c 'import os, sys; os.setgroups([]); os.setgid(65534); os.setuid(65534); os.execvp(sys.argv[1], sys.argv[1:])' env TMPDIR=/tmp "$@"; }
|
|
else
|
|
skip "neither setpriv nor python3 available to drop privileges"
|
|
fi
|
|
skeptical-updater trust su-dummy-c >/dev/null
|
|
run asuser skeptical-updater trusted
|
|
assert_success
|
|
assert_line --partial "$BE"$'\t'"su-dummy-c"$'\t'"user"
|
|
run asuser skeptical-updater info su-dummy-b
|
|
assert_success
|
|
assert_line 'reason: installed as a dependency'
|
|
assert_line 'required by: su-dummy-a'
|
|
run asuser skeptical-updater info su-dummy-a
|
|
assert_success
|
|
assert_line 'reason: explicitly installed'
|
|
run asuser skeptical-updater --dry-run --no-refresh <<<''
|
|
assert_success
|
|
assert_line --regexp "$(native_upgrade_regex)"
|
|
run asuser skeptical-updater upgrade-me-please
|
|
assert_failure 1
|
|
# a real upgrade without root and without sudo is refused
|
|
if ! command -v sudo >/dev/null 2>&1; then
|
|
run asuser skeptical-updater <<<''
|
|
assert_failure 1
|
|
assert_output --partial 'upgrading needs root and sudo is not available'
|
|
fi
|
|
[[ $(versions) == "a=1.0 b=1.0 c=1.0" ]]
|
|
# a state directory an unprivileged user cannot enter is an error, not "no trusted packages"
|
|
chmod 0000 /var/lib/skeptical-updater
|
|
run asuser skeptical-updater trusted
|
|
chmod 0755 /var/lib/skeptical-updater
|
|
assert_failure 1
|
|
assert_output --partial 'cannot access the state directory /var/lib/skeptical-updater (permission denied)'
|
|
}
|
|
|
|
@test "pacman: list, q, end of input and --dry-run never touch the real sync database" {
|
|
[[ $BE == pacman ]] || skip "pacman only"
|
|
before=$(pacman_sync_snapshot)
|
|
run skeptical-updater list
|
|
assert_success
|
|
run skeptical-updater <<<'q'
|
|
assert_success
|
|
run skeptical-updater <<<'2-'
|
|
assert_failure 2
|
|
run skeptical-updater --dry-run <<<''
|
|
assert_success
|
|
assert_line 'Checking the reviewed transaction (pacman -Sup)... ok.'
|
|
assert_line '+ pacman -Su --noconfirm'
|
|
after=$(pacman_sync_snapshot)
|
|
[[ $after == "$before" ]] || fail $'the real sync database changed.\nbefore:\n'"$before"$'\nafter:\n'"$after"
|
|
run ls /tmp
|
|
refute_output --partial 'skeptical-updater-db.'
|
|
}
|
|
|
|
@test "apt: temporary holds wait for a busy dpkg lock instead of failing" {
|
|
[[ $BE == apt ]] || skip "apt only"
|
|
command -v perl >/dev/null 2>&1 || skip "perl not available"
|
|
# hold dpkg's frontend lock for 4 s (fcntl, as dpkg does), starting now
|
|
perl -e 'use Fcntl; open(my $f, ">>", "/var/lib/dpkg/lock-frontend") or die; my $l = pack("s s l l i", F_WRLCK, 0, 0, 0, 0); fcntl($f, F_SETLKW, $l) or die; sleep 4;' &
|
|
locker=$!
|
|
sleep 0.5
|
|
run skeptical-updater --no-refresh <<<$'2-\n'
|
|
wait "$locker" || true
|
|
assert_success
|
|
assert_line 'Excluded from this run: su-dummy-b'
|
|
[[ $(versions) == "a=2.0 b=1.0 c=2.0" ]] || fail "versions after the run: $(versions)"
|
|
[[ -z $(apt-mark showhold) ]]
|
|
}
|
|
|
|
@test "zypper: a lock whose locksfile.path comes from a zypp.conf.d drop-in is honoured" {
|
|
[[ $BE == zypper ]] || skip "zypper only"
|
|
mkdir -p /etc/zypp/zypp.conf.d
|
|
printf '[main]\nlocksfile.path = /etc/zypp/locks-su-e2e\n' >/etc/zypp/zypp.conf.d/50-su-e2e.conf
|
|
zypper --non-interactive --quiet addlock su-dummy-c >/dev/null
|
|
grep -q 'solvable_name: su-dummy-c' /etc/zypp/locks-su-e2e
|
|
before=$(cat /etc/zypp/locks-su-e2e)
|
|
run skeptical-updater <<<$'2-\n'
|
|
assert_success
|
|
assert_line 'Excluded from this run: su-dummy-b'
|
|
[[ $(versions) == "a=2.0 b=1.0 c=1.0" ]] || fail "versions after the run: $(versions)"
|
|
[[ $(cat /etc/zypp/locks-su-e2e) == "$before" ]]
|
|
}
|
|
|
|
@test "zypper: the reviewed metadata is applied (no refresh between review and upgrade)" {
|
|
[[ $BE == zypper ]] || skip "zypper only (libdnf reads file:// repositories live; apt never refreshes on upgrade)"
|
|
mkfifo "$BATS_TEST_TMPDIR/in"
|
|
skeptical-updater <"$BATS_TEST_TMPDIR/in" >"$BATS_TEST_TMPDIR/out" 2>&1 &
|
|
pid=$!
|
|
exec {w}>"$BATS_TEST_TMPDIR/in" # (fd 3 belongs to bats)
|
|
for _ in $(seq 1 600); do
|
|
grep -q '^<enter> upgrade' "$BATS_TEST_TMPDIR/out" && break
|
|
sleep 0.1
|
|
done
|
|
# a newer su-dummy-c appears in the repository after the review
|
|
rpm_publish su-dummy-c 3.0
|
|
echo >&"$w"
|
|
exec {w}>&-
|
|
rc=0
|
|
wait "$pid" || rc=$?
|
|
rpm_unpublish su-dummy-c 3.0
|
|
[[ $rc -eq 0 ]] || fail "exit $rc: $(cat "$BATS_TEST_TMPDIR/out")"
|
|
[[ $(versions) == "a=2.0 b=2.0 c=2.0" ]] || fail "versions after the run: $(versions)"
|
|
}
|
|
|
|
@test "pacman: package databases synced elsewhere during the review: refused (exit 2), nothing changed" {
|
|
[[ $BE == pacman ]] || skip "pacman only"
|
|
session_start
|
|
sleep 1
|
|
pacman_publish su-dummy-c 3.0
|
|
pacman -Sy >/dev/null 2>&1 # another terminal: the system's database is now newer than the reviewed one
|
|
synced=$(sha256sum /var/lib/pacman/sync/su-dummy.db | cut -d' ' -f1)
|
|
session_finish ''
|
|
pacman_unpublish
|
|
pacman -Sy >/dev/null 2>&1
|
|
[[ $SESSION_RC -eq 2 ]] || fail "exit $SESSION_RC: $(cat "$BATS_TEST_TMPDIR/out")"
|
|
grep -q 'package databases changed since the review (su-dummy); run skeptical-updater again' "$BATS_TEST_TMPDIR/out"
|
|
[[ $(versions) == "a=1.0 b=1.0 c=1.0" ]] || fail "versions after the run: $(versions)"
|
|
[[ ! -e /var/lib/pacman/db.lck ]]
|
|
[[ -n $synced ]]
|
|
}
|
|
|
|
@test "pacman: <enter> installs exactly the reviewed metadata (the real sync DB becomes the reviewed one)" {
|
|
[[ $BE == pacman ]] || skip "pacman only"
|
|
# the system's database is older than what the review will see (su-dummy-c 3.0) ...
|
|
# (1 s apart from the previous repo rebuild: pacman compares database mtimes in seconds)
|
|
sleep 1
|
|
pacman_publish su-dummy-c 3.0
|
|
session_start
|
|
reviewed=$(sha256sum /tmp/skeptical-updater-db."$SESSION_PID".*/sync/su-dummy.db | cut -d' ' -f1)
|
|
# ... and su-dummy-c 4.0 appears in the repository after the review
|
|
sleep 1
|
|
pacman_publish su-dummy-c 4.0
|
|
session_finish ''
|
|
pacman_unpublish
|
|
[[ $SESSION_RC -eq 0 ]] || fail "exit $SESSION_RC: $(cat "$BATS_TEST_TMPDIR/out")"
|
|
grep -qE '^\+ cp -p -- /tmp/skeptical-updater-db\.[0-9]+\.[A-Za-z0-9]+/sync/su-dummy\.db /var/lib/pacman/sync/$' "$BATS_TEST_TMPDIR/out"
|
|
[[ -n $reviewed ]]
|
|
[[ $(sha256sum /var/lib/pacman/sync/su-dummy.db | cut -d' ' -f1) == "$reviewed" ]] || fail "the system's su-dummy.db is not the reviewed one"
|
|
[[ $(versions) == "a=2.0 b=2.0 c=3.0" ]] || fail "versions after the run: $(versions)"
|
|
[[ ! -e /var/lib/pacman/db.lck ]]
|
|
run ls /tmp
|
|
refute_output --partial 'skeptical-updater-db.'
|
|
}
|