| git.druid.rocks | index | druid520 | mp | test/ | suites/ | commands.sh |
test/suites/commands.sh
# suite: frontend command correctness for slotted/stray packages --
# file-conflict rollback safety, and fetch/files/revdep/reinstall/clean's
# handling of a bare name for a statically slotted or stray package.
# file-conflict rollback must never delete another package's file: a
# rejected install may leave content overwritten (its OWN install phase
# ran before conflict detection), but never DELETE the file, and a
# subsequent reinstall of the original owner must recover it.
test_file_conflict_no_data_loss() {
t_begin "file_conflict_no_data_loss"
reset_state
mkport rt12A <<'EOF'
pkg_name="rt12A"
pkg_ver="1.0"
install:
mkdir -p $MP_PREFIX/share/rt12collide
echo A > $MP_PREFIX/share/rt12collide/same.txt
touch $MP_PREFIX/rt12A-own-marker
remove:
rm -rf $MP_PREFIX/share/rt12collide
rm -f $MP_PREFIX/rt12A-own-marker
EOF
mkport rt12B <<'EOF'
pkg_name="rt12B"
pkg_ver="1.0"
install:
mkdir -p $MP_PREFIX/share/rt12collide
echo B > $MP_PREFIX/share/rt12collide/same.txt
remove:
rm -rf $MP_PREFIX/share/rt12collide
EOF
mp install rt12A >/tmp/rt12.out 2>&1
mp install rt12B >>/tmp/rt12.out 2>&1
assert_file_exists "$MP_PREFIX/share/rt12collide/same.txt" "$CUR_TEST" || return
assert_file_exists "$MP_PREFIX/rt12A-own-marker" "$CUR_TEST" || return
mp reinstall rt12A >>/tmp/rt12.out 2>&1
content=$(cat "$MP_PREFIX/share/rt12collide/same.txt" 2>/dev/null)
assert_contains "$content" "A" "$CUR_TEST" || return
t_pass
}
# fetch.pl / files.pl / revdep.pl / reinstall_pkg: a bare name for a
# statically slotted package (two directories, one pkg_name) must not be
# silently mishandled -- fetch cache is per-slot, files/revdep resolve
# via the one installed slot, and reinstall checks HOLD_VERSION before
# removing the old copy.
test_slotted_barename_commands() {
t_begin "slotted_barename_commands"
reset_state
mkport rt13-12 <<'EOF'
pkg_name="rt13stub"
pkg_ver="12.0"
pkg_slot="12"
pkg_pref="10"
fetch:
mkdir -p rt13stub
install:
touch $MP_PREFIX/rt13stub12-installed
remove:
rm -f $MP_PREFIX/rt13stub12-installed
EOF
mkport rt13-13 <<'EOF'
pkg_name="rt13stub"
pkg_ver="13.0"
pkg_slot="13"
pkg_pref="20"
fetch:
mkdir -p rt13stub
install:
touch $MP_PREFIX/rt13stub13-installed
remove:
rm -f $MP_PREFIX/rt13stub13-installed
EOF
mkport rt13consumer <<'EOF'
pkg_name="rt13consumer"
pkg_ver="1.0"
pkg_deps="rt13stub:12"
install:
touch $MP_PREFIX/rt13consumer-installed
remove:
rm -f $MP_PREFIX/rt13consumer-installed
EOF
mp fetch 'rt13stub:12' >/tmp/rt13.out 2>&1
out=$(mp fetch 'rt13stub:13' 2>&1)
assert_not_contains "$out" "already has a cached fetch" "$CUR_TEST" || return
rm -rf "$WD/fetch-cache"
mp install 'rt13stub:12' >>/tmp/rt13.out 2>&1
mp install rt13consumer >>/tmp/rt13.out 2>&1
files_out=$(mp files rt13stub 2>&1)
assert_contains "$files_out" "rt13stub12-installed" "$CUR_TEST" || return
revdep_out=$(mp revdep rt13stub 2>&1)
assert_contains "$revdep_out" "rt13consumer" "$CUR_TEST" || return
mp remove --force rt13consumer >>/tmp/rt13.out 2>&1
cat >> "$CONF" <<'EOF'
rt13stub:12:
HOLD_VERSION=999.0
EOF
out2=$(mp reinstall rt13stub 2>&1)
assert_contains "$out2" "does not match HOLD_VERSION" "$CUR_TEST" || return
assert_file_exists "$MP_PREFIX/rt13stub-12/rt13stub12-installed" "$CUR_TEST" || return
t_pass
}
# mp clean must resolve a bare name to a stray/stuck slotted stage dir
# that has NO corresponding db entry at all -- resolved_db_key can't
# help here, since there's nothing in the db to resolve from; this
# needs its own directory-listing fallback scan.
test_clean_slotted_stray_stagedir() {
t_begin "clean_slotted_stray_stagedir"
reset_state
mkdir -p "$WD/rt19stray:12"
mp clean rt19stray >/tmp/rt19.out 2>&1
assert_file_absent "$WD/rt19stray:12" "$CUR_TEST" || return
t_pass
}
# the mpx backend's own snapshot/stage/unstage primitives: snapshot
# emits "path\tsec.nsec" lines, stage recursively copies a nested tree
# (file contents intact), unstage removes it again.
test_backend_stage_snapshot() {
t_begin "backend_stage_snapshot"
reset_state
mkdir -p "$MP_PREFIX/sub" /tmp/rt36-src/nested
echo payload > "$MP_PREFIX/sub/f.txt"
echo inner > /tmp/rt36-src/nested/g.txt
"$MP_BACKEND" snapshot "$MP_PREFIX" /tmp/rt36-snap.txt >/tmp/rt36.out 2>&1
rc=$?
assert_exit0 "$rc" "$CUR_TEST" || return
snap=$(cat /tmp/rt36-snap.txt)
assert_contains "$snap" "sub/f.txt" "$CUR_TEST" || return
assert_contains "$snap" " " "$CUR_TEST" || return
"$MP_BACKEND" stage /tmp/rt36-src /tmp/rt36-dst >/tmp/rt36.out 2>&1
assert_file_exists /tmp/rt36-dst/nested/g.txt "$CUR_TEST" || return
content=$(cat /tmp/rt36-dst/nested/g.txt)
assert_contains "$content" "inner" "$CUR_TEST" || return
"$MP_BACKEND" unstage /tmp/rt36-dst >/tmp/rt36.out 2>&1
assert_file_absent /tmp/rt36-dst "$CUR_TEST" || return
rm -rf /tmp/rt36-src /tmp/rt36-dst /tmp/rt36-snap.txt
t_pass
}
# the sugar commands' persistence matrix: each hold/mask/use toggle is
# recorded in pkgconf.conf and honored by the very next invocation.
sugar_case() {
# $1 name, $2 sugar command, $3 expected pkgconf.conf substring
t_begin "$1"
reset_state
printf 'GLOBAL_DEPS=" "\n' >> "$CONF"
mkport "${1}p" <<EOF
pkg_name="${1}p"
pkg_ver="1.0"
install:
touch \$MP_PREFIX/${1}p-installed
remove:
rm -f \$MP_PREFIX/${1}p-installed
EOF
mp "$2" "${1}p" >/tmp/"$1".out 2>&1
pkgconf=$(cat "$WD/pkgconf.conf")
assert_contains "$pkgconf" "$3" "$CUR_TEST" || return
t_pass
}
run_sugar_matrix() {
sugar_case sg_hold 'hold' 'HOLD="yes"'
sugar_case sg_mask 'mask' 'MASK="yes"'
sugar_case sg_unhold_after_hold 'hold' 'HOLD="yes"'
}
# hold then unhold round-trip clears the entry entirely; unmask after
# mask likewise.
test_sugar_clear_roundtrip() {
t_begin "sugar_clear_roundtrip"
reset_state
printf 'GLOBAL_DEPS=" "\n' >> "$CONF"
mkport rt52p <<'EOF'
pkg_name="rt52p"
pkg_ver="1.0"
install:
touch $MP_PREFIX/rt52p-installed
remove:
rm -f $MP_PREFIX/rt52p-installed
EOF
mp hold rt52p >/tmp/rt52.out 2>&1
mp unhold rt52p >>/tmp/rt52.out 2>&1
mp mask rt52p >>/tmp/rt52.out 2>&1
mp unmask rt52p >>/tmp/rt52.out 2>&1
pkgconf=$(cat "$WD/pkgconf.conf")
assert_not_contains "$pkgconf" "HOLD" "$CUR_TEST" || return
assert_not_contains "$pkgconf" "MASK" "$CUR_TEST" || return
t_pass
}
# mp files on an installed package lists every tracked file with the
# real prefix; on a never-installed one it reports no manifest.
test_files_tracked_and_missing() {
t_begin "files_tracked_and_missing"
reset_state
printf 'GLOBAL_DEPS=" "\n' >> "$CONF"
mkport rt53p <<'EOF'
pkg_name="rt53p"
pkg_ver="1.0"
install:
mkdir -p $MP_PREFIX/share/rt53
touch $MP_PREFIX/share/rt53/data.txt
touch $MP_PREFIX/rt53p-installed
remove:
rm -rf $MP_PREFIX/share/rt53
rm -f $MP_PREFIX/rt53p-installed
EOF
mp install rt53p >/tmp/rt53.out 2>&1
files=$(mp files rt53p 2>&1)
assert_contains "$files" "$MP_PREFIX/share/rt53/data.txt" "$CUR_TEST" || return
assert_contains "$files" "$MP_PREFIX/rt53p-installed" "$CUR_TEST" || return
out=$(mp files rt53neverinstalled 2>&1)
assert_contains "$out" "no manifest" "$CUR_TEST" || return
t_pass
}
# mp fetch on a port with no fetch phase reports the no-op; on one with
# a fetch phase, the cache dir is created and re-fetch collides loudly.
test_fetch_cache_semantics() {
t_begin "fetch_cache_semantics"
reset_state
printf 'GLOBAL_DEPS=" "\n' >> "$CONF"
mkport rt54nofetch <<'EOF'
pkg_name="rt54nofetch"
pkg_ver="1.0"
install:
touch $MP_PREFIX/rt54nofetch-installed
remove:
rm -f $MP_PREFIX/rt54nofetch-installed
EOF
mkport rt54fetch <<'EOF'
pkg_name="rt54fetch"
pkg_ver="1.0"
fetch:
mkdir -p rt54fetch
install:
touch $MP_PREFIX/rt54fetch-installed
remove:
rm -f $MP_PREFIX/rt54fetch-installed
EOF
out=$(mp fetch rt54nofetch 2>&1)
assert_contains "$out" "no separate fetch phase" "$CUR_TEST" || return
mp fetch rt54fetch >/tmp/rt54.out 2>&1
assert_file_exists "$WD/fetch-cache/rt54fetch" "$CUR_TEST" || return
out=$(mp fetch rt54fetch 2>&1)
assert_contains "$out" "already has a cached fetch" "$CUR_TEST" || return
t_pass
}
# mp why on a bare name for a slotted installed package resolves to the
# installed canon and names the dependent.
test_why_bare_slotted_target() {
t_begin "why_bare_slotted_target"
reset_state
printf 'GLOBAL_DEPS=" "\n' >> "$CONF"
mkport rt55prov <<'EOF'
pkg_name="rt55prov"
pkg_ver="1.0"
pkg_slot="s55"
install:
touch $MP_PREFIX/rt55prov-installed
remove:
rm -f $MP_PREFIX/rt55prov-installed
EOF
mkport rt55cons <<'EOF'
pkg_name="rt55cons"
pkg_ver="1.0"
pkg_deps="rt55prov:s55"
install:
touch $MP_PREFIX/rt55cons-installed
remove:
rm -f $MP_PREFIX/rt55cons-installed
EOF
mp install rt55cons >/tmp/rt55.out 2>&1
why=$(mp why rt55prov 2>&1)
assert_contains "$why" "rt55cons" "$CUR_TEST" || return
t_pass
}
# mp list --installed dumps db format name<TAB>ver<TAB>license<TAB>
# requested, one line per canon.
test_list_installed_format() {
t_begin "list_installed_format"
reset_state
printf 'GLOBAL_DEPS=" "\n' >> "$CONF"
mkport rt56p <<'EOF'
pkg_name="rt56p"
pkg_ver="2.5"
pkg_license="BSD"
install:
touch $MP_PREFIX/rt56p-installed
remove:
rm -f $MP_PREFIX/rt56p-installed
EOF
mp install rt56p >/tmp/rt56.out 2>&1
list=$(mp list --installed 2>&1)
assert_contains "$list" "rt56p 2.5 BSD 1" "$CUR_TEST" || return
t_pass
}
# end-to-end (not just mplib::portformat's own unit-level matrix, see
# portformat.sh's enuse_default_* cases): a "+flag" default-enabled USE
# flag actually reaches an install phase script as a real USE_<flag>=1
# env var with NOTHING configured at all, "mp use pkg -flag" then
# genuinely turns it off on a REAL reinstall (not just what the toggle
# command itself reports), and the port's declared-off flag never turns
# on by itself.
test_use_flag_default_toggle() {
t_begin "use_flag_default_toggle"
reset_state
printf 'GLOBAL_DEPS=" "\n' >> "$CONF"
mkport rt57p <<'EOF'
pkg_name="rt57p"
pkg_ver="1.0"
pkg_use="+alwayson offbydefault"
install:
echo "alwayson=[$USE_alwayson] offbydefault=[$USE_offbydefault]" > $MP_PREFIX/rt57-log
touch $MP_PREFIX/rt57p-installed
remove:
rm -f $MP_PREFIX/rt57p-installed $MP_PREFIX/rt57-log
EOF
mp install rt57p >/tmp/rt57.out 2>&1
log1=$(cat "$MP_PREFIX/rt57-log" 2>/dev/null)
mp use rt57p -alwayson >>/tmp/rt57.out 2>&1
mp remove --force rt57p >>/tmp/rt57.out 2>&1
mp install rt57p >>/tmp/rt57.out 2>&1
log2=$(cat "$MP_PREFIX/rt57-log" 2>/dev/null)
assert_contains "$log1" "alwayson=[1] offbydefault=[]" "$CUR_TEST" || return
assert_contains "$log2" "alwayson=[] offbydefault=[]" "$CUR_TEST" || return
t_pass
}
# "mpx version" reports the exact cc/cflags THIS build actually used
# (buildinfo.h, regenerated by mk/b.sh every build -- never hand-
# maintained), and "mp version"/"mp --version" (identical) layer mp's
# own version, that same mpx report, and the full command/plugin list
# on top -- the same discover_cmds()/plugin_names() usage() itself uses.
test_version_reports_build_and_commands() {
t_begin "version_reports_build_and_commands"
reset_state
out=$("$MP_BACKEND" version 2>&1)
rc=$?
assert_exit0 "$rc" "$CUR_TEST" || return
assert_contains "$out" "cc=" "$CUR_TEST (mpx cc=)" || return
assert_contains "$out" "-std=c89" "$CUR_TEST (mpx cflags)" || return
out=$(mp version 2>&1)
rc=$?
assert_exit0 "$rc" "$CUR_TEST" || return
assert_contains "$out" "mp " "$CUR_TEST (mp's own version)" || return
assert_contains "$out" "cc=" "$CUR_TEST (mp version includes mpx build info)" || return
assert_contains "$out" "commands:" "$CUR_TEST" || return
assert_contains "$out" "install" "$CUR_TEST (a real core command listed)" || return
assert_contains "$out" "plugins:" "$CUR_TEST" || return
assert_contains "$out" "lint" "$CUR_TEST (a real plugin listed)" || return
dashout=$(mp --version 2>&1)
assert_contains "$dashout" "commands:" "$CUR_TEST (--version alias)" || return
t_pass
}
run_commands_suite() {
test_file_conflict_no_data_loss
test_slotted_barename_commands
test_clean_slotted_stray_stagedir
test_backend_stage_snapshot
run_sugar_matrix
test_sugar_clear_roundtrip
test_files_tracked_and_missing
test_fetch_cache_semantics
test_why_bare_slotted_target
test_list_installed_format
test_use_flag_default_toggle
test_version_reports_build_and_commands
}