2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-09-25 09:14:05 +00:00
Files
xcat-core/xCAT-test/bats/postscripts_otherpkgs.bats
T
Daniel Hilst e19a10396e test(xcat-core): the otherpkgs zypper test deletes the repository in both cases
run_zypper_local_repo extracted six lines of the zypper branch of otherpkgs and
evaluated each one in turn. The branch it measures is an if/else: the repository
is deleted only when the refresh fails. Evaluating the lines separately ran the
delete every time, so the test showed that zypper sd is reachable and never that
a repository which refreshes is kept.

The helper now evaluates the whole branch, from the #use zypper comment to the
apt branch that follows, with pmatch lifted from the same file. The success case
asserts rc=0 and no zypper sd; the failure case keeps its delete assertion.

Flipping the refresh test in otherpkgs to "if [ $? -ne 0 ]" turns both cases
red. The same mutation left the previous helper green, because it never
evaluated that line.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-17 07:34:03 -03:00

453 lines
15 KiB
Bash

#!/usr/bin/env bats
load 'helpers/shell_source'
setup()
{
OTHERPKGS="$(repo_path 'xCAT/postscripts/otherpkgs')"
[ -r "$OTHERPKGS" ] || skip "$OTHERPKGS is required"
LOGGER_LOG="${BATS_TEST_TMPDIR}/logger.log"
CMD_LOG="${BATS_TEST_TMPDIR}/cmd.log"
: >"$LOGGER_LOG"
: >"$CMD_LOG"
export OTHERPKGS LOGGER_LOG CMD_LOG
}
# logger writes one line per message it sends. A message that carries newlines stays on one
# line, with the newlines shown as "\n", so the line count is the message count.
shadow_logger()
{
logger()
{
local msg=""
while [ $# -gt 0 ]; do
case "$1" in
-p | -t) shift 2 ;;
*)
msg="$*"
break
;;
esac
done
if [ -n "$msg" ]; then
printf '%s\n' "${msg//$'\n'/\\n}" >>"$LOGGER_LOG"
else
local line
while IFS= read -r line; do
printf '%s\n' "$line" >>"$LOGGER_LOG"
done
fi
}
}
logger_call()
{
sed -n "${1}p" "$LOGGER_LOG"
}
logger_calls()
{
wc -l <"$LOGGER_LOG" | tr -d ' '
}
cmd_call()
{
sed -n "${1}p" "$CMD_LOG"
}
# A package manager that answers with PKG_STATUS and prints a three line transaction.
shadow_pkg_manager()
{
fake_pkg()
{
printf '%s\n' "$*" >>"$CMD_LOG"
printf -- '--> Running transaction check\n'
printf 'Installed: foo-1.0\n'
printf 'Error: nothing provides bar\n'
return "${PKG_STATUS:-0}"
}
zypper() { fake_pkg "$@"; }
apt-get() { fake_pkg "$@"; }
xcat_apt_get() { fake_pkg "$@"; }
apt_get_update_if_repos_changed() { :; }
}
# otherpkgs_block ANCHOR START [NTH TOTAL]
# Answers with the shell if-block that starts at the first line after the anchor. NTH and TOTAL
# go to extract_shell_if_block, which counts START in the text from the anchor to the end of the
# file. Name a START that occurs once where one exists; pass NTH and TOTAL where the candidate
# lines are the same text.
otherpkgs_block()
{
local tail="${BATS_TEST_TMPDIR}/tail-$$"
awk -v anchor="$1" 'index($0, anchor) { copy = 1 } copy { print }' "$OTHERPKGS" >"$tail"
extract_shell_if_block "$tail" "$2" "$3" "$4"
}
run_upgrade_block()
{
local block
# The upgrade block opens with the same line as the yum branch of the preremove, the install
# and the postremove blocks. The upgrade block is the first of the four.
block="$(otherpkgs_block '#now update the existing rpms' 'if [ $hasyum -eq 1 ]; then' 1 4)" || return 99
local hasyum=0 haszypper=0 hasapt=0
eval "$1=1"
local envlist="" yumcmd=fake_pkg VERBOSE= log_label=otherpkgs RETURNVAL=0 REPOFILE=/dev/null result=""
shadow_logger
shadow_pkg_manager
eval "$block"
printf 'RETURNVAL=%s\n' "$RETURNVAL"
}
run_repo_preremove_block()
{
local block
block="$(otherpkgs_block '#Now we have parsed the input' 'if [ "$repo_pkgs_preremove" != "" ]; then')" || return 99
local hasyum=0 haszypper=0 hasapt=0
eval "$1=1"
local envlist="" yumcmd=fake_pkg VERBOSE= log_label=otherpkgs RETURNVAL=0 REPOFILE=/dev/null result=""
local repo_pkgs_preremove="oldfoo"
shadow_logger
shadow_pkg_manager
eval "$block"
printf 'RETURNVAL=%s\n' "$RETURNVAL"
}
run_plain_preremove_block()
{
local block
block="$(otherpkgs_block '#Now we have parsed the input' 'if [ "$plain_pkgs_preremove" != "" ]; then')" || return 99
local envlist="" VERBOSE= log_label=otherpkgs RETURNVAL=0 result=""
local sremovecommand=fake_pkg plain_pkgs_preremove="oldfoo"
shadow_logger
shadow_pkg_manager
eval "$block"
printf 'RETURNVAL=%s\n' "$RETURNVAL"
}
@test "otherpkgs sends the package manager transaction to syslog one line per message" {
run run_upgrade_block hasyum
[ "$status" -eq 0 ]
[ "$(logger_calls)" -eq 3 ]
[ "$(logger_call 1)" = "--> Running transaction check" ]
[ "$(logger_call 2)" = "Installed: foo-1.0" ]
[ "$(logger_call 3)" = "Error: nothing provides bar" ]
}
@test "the zypper and apt upgrade paths also send one message per output line" {
run run_upgrade_block haszypper
[ "$status" -eq 0 ]
[ "$(logger_calls)" -eq 3 ]
: >"$LOGGER_LOG"
run run_upgrade_block hasapt
[ "$status" -eq 0 ]
[ "$(logger_calls)" -eq 3 ]
}
@test "the remove paths also send one message per output line" {
local manager
for manager in hasyum haszypper hasapt; do
: >"$LOGGER_LOG"
run run_repo_preremove_block "$manager"
[ "$status" -eq 0 ]
[ "$(logger_calls)" -eq 3 ]
done
: >"$LOGGER_LOG"
run run_plain_preremove_block
[ "$status" -eq 0 ]
[ "$(logger_calls)" -eq 3 ]
}
run_install_block()
{
local block
block="$(otherpkgs_block '#installation using yum/dnf or zypper' 'if [ "$repo_pkgs" != "" ]; then')" || return 99
local hasyum=0 haszypper=0 hasapt=0
eval "$1=1"
local envlist="" yumcmd=fake_pkg VERBOSE= log_label=otherpkgs RETURNVAL=0 REPOFILE=/dev/null result=""
local repo_pkgs="foo bar"
shadow_logger
shadow_pkg_manager
eval "$block"
printf 'RETURNVAL=%s\n' "$RETURNVAL"
}
run_repo_postremove_block()
{
local block
block="$(otherpkgs_block '#remove more rpms if specified with' 'if [ "$repo_pkgs_postremove" != "" ]; then')" || return 99
local hasyum=0 haszypper=0 hasapt=0
eval "$1=1"
local envlist="" yumcmd=fake_pkg VERBOSE= log_label=otherpkgs RETURNVAL=0 REPOFILE=/dev/null result=""
local repo_pkgs_postremove="oldfoo"
shadow_logger
shadow_pkg_manager
eval "$block"
printf 'RETURNVAL=%s\n' "$RETURNVAL"
}
@test "a failed package install is not logged as installed" {
local manager
for manager in hasyum haszypper hasapt; do
: >"$LOGGER_LOG"
PKG_STATUS=1 run run_install_block "$manager"
[ "$status" -eq 0 ]
[[ "$output" == *'RETURNVAL=1'* ]]
refute_grep -q 'foo bar installed\.' "$LOGGER_LOG"
grep -q 'failed\.' "$LOGGER_LOG"
done
}
@test "a successful package install is logged as installed" {
local manager
for manager in hasyum haszypper hasapt; do
: >"$LOGGER_LOG"
run run_install_block "$manager"
[ "$status" -eq 0 ]
[[ "$output" == *'RETURNVAL=0'* ]]
grep -q 'foo bar installed\.' "$LOGGER_LOG"
refute_grep -q 'failed\.' "$LOGGER_LOG"
done
}
@test "a failed package removal is not logged as removed" {
local manager
for manager in hasyum haszypper hasapt; do
: >"$LOGGER_LOG"
PKG_STATUS=1 run run_repo_postremove_block "$manager"
[ "$status" -eq 0 ]
[[ "$output" == *'RETURNVAL=1'* ]]
refute_grep -q 'oldfoo removed\.' "$LOGGER_LOG"
done
: >"$LOGGER_LOG"
run run_repo_postremove_block hasyum
[ "$status" -eq 0 ]
grep -q 'oldfoo removed\.' "$LOGGER_LOG"
}
@test "the url repository guard is false when OTHERPKGDIR has no http entry" {
local guard cond
guard="$(extract_first_matching_line "$OTHERPKGS" 'OTHERPKGDIR_INTERNET" *[]] *; *then')" || return 99
cond="${guard#*if }"
cond="${cond%%;then*}"
OTHERPKGDIR_INTERNET=""
run eval "$cond"
[ "$status" -ne 0 ]
OTHERPKGDIR_INTERNET="http://192.0.2.1/repo,"
run eval "$cond"
[ "$status" -eq 0 ]
}
# Runs the OTHERPKGDIR split and then the url repository block, and leaves the repository
# files the url block wrote under BATS_TEST_TMPDIR.
run_url_repo_block()
{
local split url_block
split="$(extract_shell_if_block "$OTHERPKGS" 'if [ -n "$OTHERPKGDIR" ]; then')" || return 99
url_block="$(otherpkgs_block '#add repo for url repos in otherpkgdir' 'if [ -n "$OTHERPKGDIR_INTERNET" ];then')" || return 99
local OTHERPKGDIR="$1" OTHERPKGDIR_INTERNET="" OTHERPKGDIR_LOCAL=""
local hasyum="${2:-1}" haszypper=0 hasapt="${3:-0}"
local repo_base="$BATS_TEST_TMPDIR" urlrepoindex=0
eval "$split"
eval "$url_block"
printf 'urlrepoindex=%s\n' "$urlrepoindex"
}
@test "the generated yum baseurl carries no trailing space" {
run run_url_repo_block 'http://192.0.2.1/repo-a,/install/post/otherpkgs,http://192.0.2.1/repo-b'
[ "$status" -eq 0 ]
[[ "$output" == *'urlrepoindex=2'* ]]
[ "$(grep '^baseurl=' "${BATS_TEST_TMPDIR}/xCAT-otherpkgs0.repo")" = "baseurl=http://192.0.2.1/repo-a" ]
[ "$(grep '^baseurl=' "${BATS_TEST_TMPDIR}/xCAT-otherpkgs1.repo")" = "baseurl=http://192.0.2.1/repo-b" ]
}
@test "the generated apt source carries no trailing space" {
run run_url_repo_block 'http://192.0.2.1/repo-a' 0 1
[ "$status" -eq 0 ]
[ "$(cat "${BATS_TEST_TMPDIR}/xCAT-otherpkgs0.list")" = "deb http://192.0.2.1/repo-a" ]
}
# Drives the zypper branch that adds the local otherpkgs repository, refreshes it and deletes
# it again when the refresh fails. The branch is evaluated whole, so the success case shows
# that a repository which refreshes is kept.
run_zypper_local_repo()
{
local urlrepoindex="$1" index="$2"
local repo_base="$BATS_TEST_TMPDIR" mounted=1 whole_path=/install/post/otherpkgs/sles15/x86_64
local OSVER=sles15 VERBOSE= localrepoindex REPOFILE rc=1 result="" path=/pkgdir
zypper()
{
printf '%s\n' "$*" >>"$CMD_LOG"
case "$1" in
ar) sed -n '1s/^\[\(.*\)\]$/added=\1/p' "$3" >>"$CMD_LOG" ;;
esac
return "${ZYPPER_STATUS:-0}"
}
array_set_element() { :; }
eval "$(extract_shell_function "$OTHERPKGS" pmatch)" || return 99
# The three lines that name the repository are straight-line assignments, so each one is
# taken on its own. The zypper branch that follows is a branch: it is taken whole, because
# what is measured is which arm runs. Keep the extraction apart from the eval, so a failing
# zypper does not read as a failed extraction.
local pattern line
for pattern in \
'localrepoindex=' \
'REPOFILE="[$]repo_base/xCAT-otherpkgs[$]localrepoindex.repo"' \
'echo "[[]xcat-otherpkgs[$]localrepoindex[]]"'; do
line="$(extract_first_matching_line "$OTHERPKGS" "$pattern")" || return 99
eval "$line"
done
# The range ends on the apt branch that follows; its two lines are dropped.
local branch
branch="$(extract_line_range "$OTHERPKGS" '#use zypper' '#use apt')" || return 99
branch="$(printf '%s\n' "$branch" | head -n -2)"
case "$branch" in
*'zypper sd xcat-otherpkgs'*) ;;
*) return 99 ;;
esac
eval "$branch"
printf 'rc=%s\n' "$rc"
return 0
}
@test "zypper keeps the otherpkgs repository it added when the refresh succeeds" {
run run_zypper_local_repo 2 0
[ "$status" -eq 0 ]
[ "$output" = "rc=0" ]
[ "$(cmd_call 2)" = "added=xcat-otherpkgs2" ]
[ "$(cmd_call 3)" = "--non-interactive refresh xcat-otherpkgs2" ]
refute_grep -q '^sd ' "$CMD_LOG"
}
@test "zypper deletes the otherpkgs repository it added when the refresh fails" {
ZYPPER_STATUS=1 run run_zypper_local_repo 2 0
[ "$status" -eq 0 ]
[ "$output" = "rc=1" ]
[ "$(cmd_call 2)" = "added=xcat-otherpkgs2" ]
[ "$(cmd_call 4)" = "sd xcat-otherpkgs2" ]
}
run_sdk_block()
{
local block
block="$(otherpkgs_block '#adds SDK repository' 'if [ "$SDKDIR" != "" ]; then')" || return 99
local SDKDIR=/install/sles15/x86_64/sdk1 OSVER=sles15 mounted=1 VERBOSE= log_label=otherpkgs result=""
local NFSSERVER=192.0.2.1 HTTPPORT=80
eval "$(extract_shell_function "$OTHERPKGS" pmatch)" || return 99
shadow_logger
zypper()
{
printf 'zypper failed\n'
return 1
}
eval "$block"
return 0
}
@test "a failed SDK repository add is logged with the repository name" {
run run_sdk_block
[ "$status" -eq 0 ]
grep -q 'xCAT-sles15-sdk1' "$LOGGER_LOG"
}
# Drives the package list split and the two diagnostic lines that follow it. The range ends on
# the "for" line that starts the package loop, and that line is dropped: the loop is not part of
# what is measured.
run_pkglist_diagnostics()
{
local range
range="$(extract_line_range "$OTHERPKGS" 'pkgsarray=' '^[[:space:]]*for x in')" || return 99
local pkglist="foo bar" hasyum=1 yumcmd=dnf hasapt=0 haszypper=0 oifs=$IFS
eval "$(printf '%s\n' "$range" | sed '$d')"
}
@test "the package list diagnostics print nothing when VERBOSE is not set" {
VERBOSE= run run_pkglist_diagnostics
[ "$status" -eq 0 ]
[ -z "$output" ]
}
@test "the package list diagnostics print the list and the package manager under VERBOSE" {
VERBOSE=1 run run_pkglist_diagnostics
[ "$status" -eq 0 ]
[[ "$output" == *'pkgsarray: foo bar, 2'* ]]
[[ "$output" == *'yum/dnf: 1 (dnf), apt: 0, zypper: 0'* ]]
}
run_plain_install_block()
{
local block
block="$(otherpkgs_block '#Handle the rest with rpm' 'if [ "$plain_pkgs" != "" -a -n "$OTHERPKGDIR" ]; then')" || return 99
local envlist="" VERBOSE= log_label=otherpkgs RETURNVAL=0 result=""
local supdatecommand=fake_pkg plain_pkgs="foo bar" mounted=1
local OTHERPKGDIR="$BATS_TEST_TMPDIR"
shadow_logger
shadow_pkg_manager
# The block changes directory. A subshell keeps the test in its own directory.
(
eval "$block"
printf 'RETURNVAL=%s\n' "$RETURNVAL"
)
}
run_plain_postremove_block()
{
local block
block="$(otherpkgs_block '#remove more rpms if specified with' 'if [ "$plain_pkgs_postremove" != "" ]; then')" || return 99
local envlist="" VERBOSE= log_label=otherpkgs RETURNVAL=0 result=""
local sremovecommand=fake_pkg plain_pkgs_postremove="oldfoo"
shadow_logger
shadow_pkg_manager
eval "$block"
printf 'RETURNVAL=%s\n' "$RETURNVAL"
}
@test "a failed rpm fallback install is logged as failed" {
PKG_STATUS=1 run run_plain_install_block
[ "$status" -eq 0 ]
[[ "$output" == *'RETURNVAL=1'* ]]
refute_grep -q 'foo bar installed\.' "$LOGGER_LOG"
grep -q 'foo bar failed\.' "$LOGGER_LOG"
}
@test "a successful rpm fallback install is logged as installed" {
run run_plain_install_block
[ "$status" -eq 0 ]
[[ "$output" == *'RETURNVAL=0'* ]]
grep -q 'foo bar installed\.' "$LOGGER_LOG"
refute_grep -q 'failed\.' "$LOGGER_LOG"
}
@test "a failed package removal is logged as failed" {
local manager
for manager in hasyum haszypper hasapt; do
: >"$LOGGER_LOG"
PKG_STATUS=1 run run_repo_postremove_block "$manager"
[ "$status" -eq 0 ]
[[ "$output" == *'RETURNVAL=1'* ]]
grep -q 'oldfoo failed\.' "$LOGGER_LOG"
done
: >"$LOGGER_LOG"
PKG_STATUS=1 run run_plain_postremove_block
[ "$status" -eq 0 ]
[[ "$output" == *'RETURNVAL=1'* ]]
refute_grep -q 'oldfoo removed\.' "$LOGGER_LOG"
grep -q 'oldfoo failed\.' "$LOGGER_LOG"
}
@test "a successful package removal is logged as removed only" {
run run_plain_postremove_block
[ "$status" -eq 0 ]
[[ "$output" == *'RETURNVAL=0'* ]]
grep -q 'oldfoo removed\.' "$LOGGER_LOG"
refute_grep -q 'failed\.' "$LOGGER_LOG"
}