On the pacman backend, an installed AUR helper (paru, else yay;
--aur-helper=paru|yay|none, --no-aur) adds the AUR updates to the review
list. The helper never runs as root: when the tool is root through sudo it
runs as SUDO_USER (runuser -u, else sudo -u, with that user's HOME, from
that home); unprivileged it runs as is; a root login gets no AUR, with a
warning. The banner names the helper ("+ AUR via paru").
- listing: <helper> -Qua (also with --no-refresh), rows with repository
"aur"; [ignored] is shown [held]; a failing -Qua warns and the session
goes on with the repository rows
- every row has a marker column after the number: "*" for AUR rows, a
space otherwise (on every backend)
- N?? merges pacman -Qi with <helper> -Sia; N?, N+, Nx stay with pacman;
N- excludes through the helper's --ignore
- <enter>: the repository step exactly as before, then <helper> -Sua
--ignore <excluded> as the invoking user (--noconfirm only when stdin is
not a terminal); pacman is skipped when only AUR rows are left; a helper
failure is reported and its status returned; --dry-run prints it
- other backends never run a helper; --aur-helper is ignored with a warning
paru 2.1.0 and yay 13.0.1 formats verified in discovery/pacman.md section
15 (proof: discovery/pacman/aur.sh). Unit tests replay the recorded output
(fake paru, yay, runuser, getent); the archlinux E2E run installs the
foreign su-dummy-aur and drives a fake paru through a fake sudo built on
passwordless su for wheel.
109 lines
4.0 KiB
Bash
109 lines
4.0 KiB
Bash
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
# Copyright (C) 2026 Bryan Joshua Pedini
|
|
|
|
# tests/unit/test_helper.bash - common setup for the unit tests (sourced via `load test_helper`).
|
|
# The applet runs with a hermetic PATH: fake package managers (tests/unit/fakes/<dir>) in front
|
|
# of a directory with symlinks to the few system tools it needs. No root, no network, no real
|
|
# package manager; everything is written under $BATS_TEST_TMPDIR.
|
|
# shellcheck shell=bash
|
|
|
|
load '../vendor/bats-support/load'
|
|
load '../vendor/bats-assert/load'
|
|
|
|
SU_BIN=$(cd "$BATS_TEST_DIRNAME/../.." && pwd)/skeptical-updater
|
|
FAKES=$BATS_TEST_DIRNAME/fakes
|
|
export FAKE_DATA=$BATS_TEST_DIRNAME/data
|
|
SYS_TOOLS=(bash env cat sort sed grep tr cut join awk mktemp mv mkdir chmod rm cp ln date ls head tail wc touch sleep kill flock readlink timeout stat sha256sum)
|
|
|
|
common_setup() {
|
|
SYSBIN=$BATS_TEST_TMPDIR/sysbin
|
|
mkdir -p "$SYSBIN"
|
|
local t p
|
|
for t in "${SYS_TOOLS[@]}"; do
|
|
p=$(type -P "$t") || continue
|
|
ln -sf "$p" "$SYSBIN/$t"
|
|
done
|
|
export FAKE_DIR=$BATS_TEST_TMPDIR/fake
|
|
mkdir -p "$FAKE_DIR"
|
|
: >"$FAKE_DIR/holds"
|
|
export FAKE_LOG=$FAKE_DIR/log
|
|
: >"$FAKE_LOG"
|
|
export STATE=$BATS_TEST_TMPDIR/state
|
|
export STATE_FILE=$STATE/trusted.tsv
|
|
export SKEPTICAL_UPDATER_STATE_DIR=$STATE
|
|
export SKEPTICAL_UPDATER_EUID=0
|
|
export SKEPTICAL_UPDATER_OS_RELEASE=$FAKE_DATA/os-release-debian12
|
|
export TMPDIR=$BATS_TEST_TMPDIR
|
|
export FAKE_PACMAN_DBPATH=$FAKE_DIR/pacman-db
|
|
mkdir -p "$FAKE_PACMAN_DBPATH/sync" "$FAKE_PACMAN_DBPATH/local"
|
|
unset NO_COLOR ZYPP_CONF COLUMNS SKEPTICAL_UPDATER_LOCK_WAIT SUDO_USER
|
|
use_fakes apt
|
|
}
|
|
|
|
# use_fakes DIR...: the applet sees only these fake dirs + the system tools
|
|
use_fakes() {
|
|
local d p=
|
|
for d in "$@"; do p+=$FAKES/$d:; done
|
|
TEST_PATH=$p$SYSBIN
|
|
}
|
|
|
|
# skup ARGS...: run the applet (use as `run skup ...`, stdin is passed through)
|
|
skup() { env PATH="$TEST_PATH" "$SU_BIN" "$@"; }
|
|
|
|
# pty_skup INPUT ARGS...: run the applet on a pseudo-terminal (script(1), util-linux/bsdutils) with
|
|
# INPUT typed in one go - readline consumes it as it reads, so no timing is involved; end INPUT with
|
|
# a line that ends the session (q or an empty line). Sets status, output and lines like `run`
|
|
# (output without the pty's CRs; NO_COLOR, as stdout is a terminal); the raw transcript stays in
|
|
# $PTY_RAW. Skips without script(1).
|
|
# shellcheck disable=SC2034 # status/lines are read by bats-assert
|
|
pty_skup() {
|
|
local input=$1 cmd
|
|
shift
|
|
command -v script >/dev/null 2>&1 || skip "script(1) (util-linux/bsdutils) not available: no pty to drive"
|
|
PTY_RAW=$BATS_TEST_TMPDIR/pty.raw
|
|
printf -v cmd '%q ' env PATH="$TEST_PATH" TERM=dumb NO_COLOR=1 "$SU_BIN" "$@"
|
|
status=0
|
|
printf '%s' "$input" | timeout 60 script -qfec "$cmd" /dev/null >"$PTY_RAW" 2>&1 || status=$?
|
|
output=$(tr -d '\r' <"$PTY_RAW")
|
|
mapfile -t lines <<<"$output"
|
|
}
|
|
# pty_bells: number of BEL bytes (readline's bell) in the raw transcript of the last pty_skup
|
|
pty_bells() { tr -cd '\a' <"$PTY_RAW" | wc -c; }
|
|
# count_lines LINE: number of output lines that are exactly LINE
|
|
count_lines() { grep -cxF -- "$1" <<<"$output" || true; }
|
|
|
|
# shellcheck disable=SC2034 # used by the .bats files
|
|
HEADER='# skeptical-updater trusted packages. Columns: backend package reason added(UTC ISO-8601)'
|
|
# shellcheck disable=SC2034
|
|
DATE_RE='[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z'
|
|
# shellcheck disable=SC2034
|
|
T=$'\t'
|
|
|
|
# write_state LINE...: create the statefile with exactly these lines
|
|
write_state() {
|
|
mkdir -p "$STATE"
|
|
printf '%s\n' "$@" >"$STATE_FILE"
|
|
}
|
|
|
|
# log_has LINE: the fake log contains exactly this line
|
|
log_has() {
|
|
grep -qxF -- "$1" "$FAKE_LOG" || {
|
|
printf 'expected log line: %s\n--- fake log:\n%s\n' "$1" "$(cat "$FAKE_LOG")" >&2
|
|
return 1
|
|
}
|
|
}
|
|
# log_matches REGEX: some fake log line matches
|
|
log_matches() {
|
|
grep -qE -- "$1" "$FAKE_LOG" || {
|
|
printf 'expected a log line matching: %s\n--- fake log:\n%s\n' "$1" "$(cat "$FAKE_LOG")" >&2
|
|
return 1
|
|
}
|
|
}
|
|
# log_lacks REGEX: no fake log line matches
|
|
log_lacks() {
|
|
if grep -qE -- "$1" "$FAKE_LOG"; then
|
|
printf 'unexpected log line matching: %s\n--- fake log:\n%s\n' "$1" "$(cat "$FAKE_LOG")" >&2
|
|
return 1
|
|
fi
|
|
}
|