do not edit — generated by btf.
git.druid.rocksindexdruid520mptest/suites/fuzz.sh

test/suites/fuzz.sh


# suite: randomized soundness fuzzing -- thousands of seeded iterations
# generating random package graphs (deps/tags/prefs/slots/use/hooks/
# patches/conflicts) and asserting exact invariants against mp's actual
# behavior: transitive-closure equality, prune-closure equality, db
# shape, marker consistency, hook firing counts and order, patch gating,
# use-composed slot composition, lowest-pref provider choice, and clean
# failure on conflict. deterministic: FUZZ_SEED seeds everything,
# FUZZ_ITERATIONS sets the batch size (1000 by default), so a failing
# iteration reproduces exactly by rerunning with the same seed, and its
# full state (scratch ports, conf, db, hook log) is left on disk.
 
FUZZ_SEED=${FUZZ_SEED:-1337}
FUZZ_ITERATIONS=${FUZZ_ITERATIONS:-1000}
 
# deterministic lcg: fz_rnd <bound> sets REPLY in [0,bound).
fz_rnd() {
	FUZZ_STATE=$(( (FUZZ_STATE * 1103515245 + 12345) & 2147483647 ))
	REPLY=$(( FUZZ_STATE % $1 ))
}
 
# port index from a name or canon (fz..p<N>[:...]).
fz_idx_of() {
	FZ_K_TMP=${1%%:*}
	FZ_K_TMP=${FZ_K_TMP##*p}
	REPLY=$FZ_K_TMP
}
 
# canon of a port, by index, name, or canon (all resolve to the same
# numeric suffix).
fz_canon_of() {
	fz_idx_of "$1"
	eval "REPLY=\$FZ_CANON_$REPLY"
}
 
# one iteration: generate, install, assert every invariant, prune-check,
# remove one package, re-check. returns 0/1.
fz_iteration() {
	FUZZ_I=$1
	FUZZ_STATE=$(( (FUZZ_SEED + FUZZ_I * 2654435761) & 2147483647 ))
	reset_state
	printf 'GLOBAL_DEPS=" "\n' >> "$CONF"
	TAB=$(printf '\t')
 
	# --- iteration shape ----------------------------------------
	fz_rnd 100; FZ_MODE=$REPLY          # <20 conflict, <45 provider-choice
	fz_rnd 5;   FZ_NP=$(( 3 + REPLY ))  # 3..7 ports
	FZ_NTAG=0
	fz_rnd 100
	if [ "$REPLY" -lt 60 ]; then FZ_NTAG=1; fi
	if [ "$FZ_NTAG" -eq 1 ]; then
		fz_rnd 100
		[ "$REPLY" -lt 40 ] && FZ_NTAG=2
	fi
	if [ "$FZ_MODE" -ge 20 ] && [ "$FZ_MODE" -lt 45 ]; then
		FZ_NTAG=1
	fi
	FZ_PIPELINE=0
	fz_rnd 100
	[ "$REPLY" -lt 25 ] && FZ_PIPELINE=1
	# tag providers live at the BOTTOM of the index order (ports 1/2
	# in provider-choice mode, port 1 otherwise), and %tag references
	# only ever come from higher indices: a provider's own dependency
	# closure (always lower indices) can then never reach a %tag
	# reference, so no provider-referencing-its-own-tag cycle is
	# possible. in provider-choice mode plain deps also skip ports 1/2
	# entirely, so neither provider can be installed by any edge other
	# than the tag itself (which would trip resolve_dep's "already
	# satisfied" shortcut and skip the contested pick).
	if [ "$FZ_MODE" -ge 20 ] && [ "$FZ_MODE" -lt 45 ]; then
		FZ_PROVMAX=2
		FZ_DEPMIN=3
	else
		FZ_PROVMAX=1
		FZ_DEPMIN=2
	fi
 
 
	# --- generate ports ------------------------------------------
	j=1
	while [ "$j" -le "$FZ_NP" ]; do
		name="fz${FUZZ_I}p$j"
		fz_rnd 9; ver="1.$(( 1 + REPLY ))"
		slot=""
		slotuse=""
		enabled=""
		fz_rnd 100
		if [ "$REPLY" -lt 20 ]; then
			fz_rnd 3
			case "$REPLY" in
				0) slot="2" ;;
				1) slot="3" ;;
				2) slot="7" ;;
			esac
		fi
		fz_rnd 100
		[ "$REPLY" -lt 25 ] && slotuse="ssl lto"
		if [ "$slotuse" != "" ]; then
			fz_rnd 100; [ "$REPLY" -lt 50 ] && enabled=" ssl"
			fz_rnd 100; [ "$REPLY" -lt 50 ] && enabled="$enabled lto"
			joined=""
			for f in ssl lto; do
				case "$enabled" in
					*" $f"*)
						if [ "$joined" = "" ]; then
							joined="$f"
						else
							joined="$joined-$f"
						fi
						;;
				esac
			done
			if [ "$joined" != "" ]; then
				slotpart="${slot:+$slot-}$joined"
			else
				slotpart="$slot"
			fi
			if [ "$slotpart" = "" ]; then
				canon="$name"
			else
				canon="$name:$slotpart"
			fi
		else
			if [ "$slot" = "" ]; then
				canon="$name"
			else
				canon="$name:$slot"
			fi
		fi
		# use-flag deps: enabled flags only, referencing EARLIER ports
		# or a tag (acyclic by construction)
		usedepstr=""
		fz_rnd 100
		if [ "$slotuse" != "" ] && [ "$REPLY" -lt 60 ] && [ "$j" -gt 1 ]; then
			fz_rnd 100
			if [ "$FZ_NTAG" -ge 1 ] && [ "$REPLY" -lt 50 ] && [ "$j" -gt "$FZ_PROVMAX" ]; then
				usedep_ssl="%fz${FUZZ_I}t1"
			elif [ "$j" -gt "$FZ_DEPMIN" ]; then
				fz_rnd "$(( j - FZ_DEPMIN ))"
				usedep_ssl="fz${FUZZ_I}p$(( FZ_DEPMIN + REPLY ))"
			else
				usedep_ssl=""
			fi
			[ "$usedep_ssl" != "" ] && usedepstr="ssl:$usedep_ssl"
			fz_rnd 100
			if [ "$REPLY" -lt 40 ] && [ "$j" -gt "$FZ_DEPMIN" ]; then
				fz_rnd "$(( j - FZ_DEPMIN ))"
				usedepstr="$usedepstr lto:b:fz${FUZZ_I}p$(( FZ_DEPMIN + REPLY ))"
			fi
		fi
		deps=""
		# in provider-choice mode the LAST port is forced to depend on
		# the contested tag (its pkg_deps and FZ_DEPS agree, since the
		# random deps are skipped entirely)
		if [ "$FZ_MODE" -ge 20 ] && [ "$FZ_MODE" -lt 45 ] && [ "$j" -eq "$FZ_NP" ]; then
			deps="%fz${FUZZ_I}t1"
		else
			fz_rnd 100
			if [ "$REPLY" -lt 55 ] && [ "$j" -gt "$FZ_DEPMIN" ]; then
				fz_rnd 2
				ndep=$(( REPLY + 1 ))
				k=0
				while [ "$k" -lt "$ndep" ]; do
					fz_rnd 100
					if [ "$FZ_NTAG" -ge 1 ] && [ "$REPLY" -lt 35 ]; then
						deps="$deps %fz${FUZZ_I}t1"
					else
						# bounded to start at FZ_DEPMIN, same as every other dep
						# kind below (bdep/rdep/soft/usedep) -- in provider-choice
						# mode this is load-bearing, not cosmetic: the provider-pick
						# assertion assumes ports 1/2 are reachable ONLY through the
						# contested tag edge (see the FZ_PROVMAX/FZ_DEPMIN comment
						# above), and a plain dep landing on port 1 or 2 directly
						# would install the "losing" provider for a real reason,
						# tripping that assertion.
						fz_rnd "$(( j - FZ_DEPMIN ))"
						deps="$deps fz${FUZZ_I}p$(( FZ_DEPMIN + REPLY ))"
						fz_rnd 100
						if [ "$REPLY" -lt 30 ]; then
							fz_rnd 2
							if [ "$REPLY" -eq 0 ]; then
								deps="${deps}>=1.0"
							else
								deps="${deps}~1"
							fi
						fi
					fi
					k=$(( k + 1 ))
				done
			fi
		fi
		soft=""
		fz_rnd 100
		if [ "$REPLY" -lt 15 ] && [ "$j" -gt "$FZ_DEPMIN" ]; then
			fz_rnd "$(( j - FZ_DEPMIN ))"
			soft="fz${FUZZ_I}p$(( FZ_DEPMIN + REPLY ))"
		fi
		bdep=""
		rdep=""
		fz_rnd 100
		if [ "$REPLY" -lt 15 ] && [ "$j" -gt "$FZ_DEPMIN" ]; then
			fz_rnd "$(( j - FZ_DEPMIN ))"
			bdep="fz${FUZZ_I}p$(( FZ_DEPMIN + REPLY ))"
			fz_rnd "$(( j - FZ_DEPMIN ))"
			rdep="fz${FUZZ_I}p$(( FZ_DEPMIN + REPLY ))"
		fi
		hookpre=""
		fz_rnd 100
		[ "$REPLY" -lt 20 ] && hookpre="1"
		hookdir=""
		fz_rnd 100
		[ "$REPLY" -lt 20 ] && hookdir="1"
		haspatches=0
		fz_rnd 100
		[ "$REPLY" -lt 15 ] && haspatches=1
 
		eval "FZ_CANON_$j=\"$canon\""
		eval "FZ_DEPS_$j=\"$deps $rdep $bdep $usedepstr $soft\""
		eval "FZ_RDEPS_$j=\"$deps $usedepstr $soft $rdep\""
		eval "FZ_EN_$j=\"$enabled\""
		eval "FZ_PATCH_$j=$haspatches"
		eval "FZ_HOOKPRE_$j=$hookpre"
		eval "FZ_HOOKDIR_$j=$hookdir"
 
		# --- write the port ---------------------------------------
		body="pkg_name=\"$name\"
pkg_ver=\"$ver\"
"
		if [ "$slot" != "" ]; then
			body="${body}pkg_slot=\"$slot\"
"
		fi
		if [ "$slotuse" != "" ]; then
			body="${body}pkg_slot_use=\"$slotuse\"
pkg_use=\"$usedepstr\"
"
		fi
		if [ "$deps" != "" ]; then
			body="${body}pkg_deps=\"$deps\"
"
		fi
		if [ "$soft" != "" ]; then
			body="${body}pkg_deps_soft=\"$soft\"
"
		fi
		if [ "$bdep" != "" ]; then
			body="${body}pkg_bdepend=\"$bdep\"
pkg_rdepend=\"$rdep\"
"
		fi
		if [ "$haspatches" -eq 1 ]; then
			body="${body}fetch:
	mkdir -p $name
"
		fi
		if [ "$FZ_PIPELINE" -eq 1 ] && [ $(( j % 3 )) -eq 0 ]; then
			body="${body}build:
	:
"
		fi
		body="${body}install:
	touch \$MP_PREFIX/${name}-installed
remove:
	rm -f \$MP_PREFIX/${name}-installed
"
		mkport "$name" <<EOF
$body
EOF
		j=$(( j + 1 ))
	done
 
	# --- tags / providers -----------------------------------------
	# --- roots and expected closures -------------------------------
	ROOTS=""
	# in provider-choice mode the forced tag consumer (the last port)
	# is always one of the roots, so the contested pick is guaranteed
	# to actually happen; roots never land on the provider ports (a
	# rooted provider would satisfy the tag before the pick).
	if [ "$FZ_MODE" -ge 20 ] && [ "$FZ_MODE" -lt 45 ]; then
		ROOTS=" fz${FUZZ_I}p$FZ_NP"
		fz_rnd "$(( FZ_NP - FZ_DEPMIN + 1 ))"
		ROOTS="$ROOTS fz${FUZZ_I}p$(( FZ_DEPMIN + REPLY ))"
	else
		fz_rnd 2
		nroots=$(( REPLY + 1 ))
		k=0
		while [ "$k" -lt "$nroots" ]; do
			fz_rnd "$(( FZ_NP - FZ_DEPMIN + 1 ))"
			ROOTS="$ROOTS fz${FUZZ_I}p$(( FZ_DEPMIN + REPLY ))"
			k=$(( k + 1 ))
		done
	fi
	ROOT_CANONS=""
	for r in $ROOTS; do
		fz_canon_of "$r"
		ROOT_CANONS="$ROOT_CANONS $REPLY"
	done
 
	# providers: fixed early indices (see the FZ_PROVMAX/FZ_DEPMIN
	# rationale in the shape section). t2 (when generated) is never
	# referenced by anything, so its provider is arbitrary.
	PROVIDERS=""
	PROV2=""
	if [ "$FZ_MODE" -ge 20 ] && [ "$FZ_MODE" -lt 45 ]; then
		p=1
		p2=2
		fz_rnd 50; pref=$(( REPLY + 1 ))
		fz_rnd 50; pref2=$(( REPLY + 1 ))
		[ "$pref2" -eq "$pref" ] && pref2=$(( pref2 % 50 + 1 ))
		[ "$pref2" -eq "$pref" ] && pref2=$(( pref2 + 1 ))
		fz_canon_of 1;  name1=$REPLY
		fz_canon_of 2;  name2=$REPLY
		mkdir -p "$SCRATCH/fz${FUZZ_I}p1"
		cat >> "$SCRATCH/fz${FUZZ_I}p1/pkg.conf" <<EOF
pkg_tags="fz${FUZZ_I}t1"
pkg_pref="$pref"
EOF
		mkdir -p "$SCRATCH/fz${FUZZ_I}p2"
		cat >> "$SCRATCH/fz${FUZZ_I}p2/pkg.conf" <<EOF
pkg_tags="fz${FUZZ_I}t1"
pkg_pref="$pref2"
EOF
		if [ "$pref2" -lt "$pref" ]; then
			eval "FZ_TAGPROV_1=\"$name2\""
			eval "FZ_TAGLIST_1=\"$name2 $name1\""
		else
			eval "FZ_TAGPROV_1=\"$name1\""
			eval "FZ_TAGLIST_1=\"$name1 $name2\""
		fi
		eval "FZ_TAGPROVS_1=\"1 2\""
		PROVIDERS="$name1 $name2"
		PROV2="$name2"
	fi
	if [ "$FZ_MODE" -ge 45 ] || [ "$FZ_MODE" -lt 20 ]; then
		k=1
		while [ "$k" -le "$FZ_NTAG" ]; do
			if [ "$k" -eq 1 ]; then
				p=1
			else
				# excludes port 1 (t1's own fixed provider, just
				# above): pkg.conf is a plain key=value format, so a
				# second "pkg_tags=" line on the SAME port doesn't
				# add a tag, it silently overwrites the first --
				# picking the same port for both tags would leave
				# t1 with no provider at all (a real, and correct,
				# "no port provides tag" failure on install, just
				# not the scenario this generator meant to create).
				fz_rnd "$(( FZ_NP - 1 ))"
				p=$(( REPLY + 2 ))
			fi
			fz_rnd 50; pref=$(( REPLY + 1 ))
			fz_canon_of "$p"; name1=$REPLY
			mkdir -p "$SCRATCH/fz${FUZZ_I}p$p"
			cat >> "$SCRATCH/fz${FUZZ_I}p$p/pkg.conf" <<EOF
pkg_tags="fz${FUZZ_I}t$k"
pkg_pref="$pref"
EOF
			eval "FZ_TAGPROV_$k=\"$name1\""
			eval "FZ_TAGPROVS_$k=\"$p\""
			eval "FZ_TAGLIST_$k=\"$name1\""
			PROVIDERS="$PROVIDERS $name1"
			k=$(( k + 1 ))
		done
	fi
 
	# --- per-package config, hooks, patches -----------------------
	j=1
	while [ "$j" -le "$FZ_NP" ]; do
		eval "en=\$FZ_EN_$j"
		if [ "$en" != "" ]; then
			cat >> "$CONF" <<EOF
fz${FUZZ_I}p$j:
	USE=$en
EOF
		fi
		eval "hp=\$FZ_HOOKPRE_$j"
		if [ "$hp" = "1" ]; then
			cat >> "$CONF" <<EOF
fz${FUZZ_I}p$j:
	hook_pre_install=echo pre$j >> /tmp/fz${FUZZ_I}-hooks.log
EOF
		fi
		eval "hd=\$FZ_HOOKDIR_$j"
		if [ "$hd" = "1" ]; then
			mkdir -p "$WD/hooks/post_install"
			cat > "$WD/hooks/post_install/dir$j" <<EOF
#!/bin/sh
echo dir$j >> /tmp/fz${FUZZ_I}-hooks.log
EOF
			chmod +x "$WD/hooks/post_install/dir$j"
		fi
		eval "hp2=\$FZ_PATCH_$j"
		if [ "$hp2" -eq 1 ]; then
			mkdir -p "$SCRATCH/fz${FUZZ_I}p$j/patches"
			printf -- '--- a/dummy\n+++ b/dummy\n@@ -0,0 +1 @@\n+uncond\n' > "$SCRATCH/fz${FUZZ_I}p$j/patches/001.patch"
			printf -- '--- a/dummy\n+++ b/dummy\n@@ -0,0 +1 @@\n+sslpatch\n' > "$SCRATCH/fz${FUZZ_I}p$j/patches/002.patch"
			cat > "$SCRATCH/fz${FUZZ_I}p$j/patches/patches.conf" <<EOF
002.patch:
	IF_USE=ssl
EOF
		fi
		j=$(( j + 1 ))
	done
 
	# --- random pre_build pipeline (chain, third gated off) --------
	PIPE_ORDER=""
	if [ "$FZ_PIPELINE" -eq 1 ]; then
		mkdir -p "$WD/hooks/pre_build"
		fz_rnd 3
		case "$REPLY" in
			0) first=a ;;
			1) first=b ;;
			2) first=c ;;
		esac
		rest=""
		for L in a b c; do
			[ "$L" = "$first" ] && continue
			rest="$rest$L"
		done
		second=$(printf '%s' "$rest" | cut -c1)
		third=$(printf '%s' "$rest" | cut -c2)
		PIPE_ORDER="$first $second"
		for L in $first $second $third; do
			cat > "$WD/hooks/pre_build/$L" <<EOF
#!/bin/sh
echo pipe$L >> /tmp/fz${FUZZ_I}-hooks.log
EOF
			chmod +x "$WD/hooks/pre_build/$L"
		done
		cat > "$WD/hooks/pre_build/hooks.conf" <<EOF
$second:
	AFTER=$first
 
$third:
	AFTER=$second
	IF_USE=fz${FUZZ_I}zzznonexistent
EOF
	fi
 
	# --- conflict mode: target conflicts with root -----------------
	CONFLICT_TARGET=""
	if [ "$FZ_MODE" -lt 20 ]; then
		fz_rnd "$FZ_NP"; ci1=$(( REPLY + 1 ))
		fz_rnd "$FZ_NP"; ci2=$(( REPLY + 1 ))
		while [ "$ci2" -eq "$ci1" ]; do
			fz_rnd "$FZ_NP"; ci2=$(( REPLY + 1 ))
		done
		# every dep kind above only ever targets a STRICTLY lower
		# index than its own port, so the port-index order is a
		# valid topological order of the whole generated dep DAG --
		# giving CONFLICT_TARGET the lower index guarantees it can
		# never depend (directly or transitively) on CONFLICT_ROOT.
		# without this, installing CONFLICT_TARGET first (below) can
		# occasionally pull CONFLICT_ROOT in as an ordinary dep of
		# its own, so by the time the conflict install runs
		# CONFLICT_ROOT is already installed and the whole conflict
		# check never triggers -- not a conflict-detection failure,
		# just a scenario this generator should never have posed.
		if [ "$ci1" -lt "$ci2" ]; then
			ci_target=$ci1; ci_root=$ci2
		else
			ci_target=$ci2; ci_root=$ci1
		fi
		CONFLICT_TARGET="fz${FUZZ_I}p$ci_target"
		CONFLICT_ROOT="fz${FUZZ_I}p$ci_root"
		cat >> "$SCRATCH/$CONFLICT_TARGET/pkg.conf" <<EOF
pkg_conflicts="$CONFLICT_ROOT"
EOF
	fi
 
	# expected closures. the INSTALL closure must simulate resolve_dep's
	# actual depth-first order exactly: deps are processed in
	# effective_deps order, and a %tag dep picks the lowest-pref
	# provider UNLESS another provider of that tag is already installed
	# at that moment (pick_provider's installed-first shortcut), so the
	# visit order decides which provider wins. the RUNTIME closure is a
	# plain set reachability with prune's own "first lexicographically
	# sorted installed provider" tag rule, order-free.
 
	# fz_tok_target <tok> <idx> <runtime> resolves one dep token to a
	# canon in REPLY ("" when it contributes nothing).
	fz_tok_target() {
		local tok idx mode target flag enx rest2 tag kk pl pc t
		tok="$1"
		idx="$2"
		mode="$3"
		target=""
		case "$tok" in
			ssl:*|lto:*)
				flag=${tok%%:*}
				eval "enx=\$FZ_EN_$idx"
				case "$enx" in
					*" $flag"*) ;;
					*) REPLY=""; return 0 ;;
				esac
				rest2=${tok#*:}
				case "$rest2" in
					b:*) [ "$mode" = "1" ] && { REPLY=""; return 0; }; rest2=${rest2#b:} ;;
				esac
				tok="$rest2"
				;;
		esac
		case "$tok" in
			%*)
				tag=${tok#%}
				tag=${tag%%[>=<~]*}
				kk=1
				while [ "$kk" -le "$FZ_NTAG" ]; do
					if [ "$tag" = "fz${FUZZ_I}t$kk" ]; then
						if [ "$mode" = "1" ]; then
							eval "target=\$FZ_RTAGPROV_$kk"
						else
							# install-time pick: first (lowest-pref)
							# provider already in FZ_DONE, else the
							# lowest-pref one outright.
							eval "pl=\$FZ_TAGLIST_$kk"
							target=""
							for pc in $pl; do
								case " $FZ_DONE " in
									*" $pc "*)
										if [ "$target" = "" ]; then
											target="$pc"
										fi
										;;
								esac
							done
							if [ "$target" = "" ]; then
								target=$(echo "$pl" | cut -d' ' -f1)
							fi
						fi
						break
					fi
					kk=$(( kk + 1 ))
				done
				;;
			*)
				case "$tok" in
					\?*) t=${tok#\?} ;;
					*) t="$tok" ;;
				esac
				t=${t%%[>=<~]*}
				fz_canon_of "$t"
				target=$REPLY
				;;
		esac
		REPLY="$target"
		return 0
	}
 
	# depth-first install simulation (the db-state shortcut needs the
	# exact visit order).
	fz_dfs() {
		# cur/idx/ds/tok/target are recursion-sensitive: fz_dfs calls
		# itself for a dependency's own dependencies before this loop
		# is done with the rest of $ds, so without "local" each
		# recursive descent clobbers idx/ds out from under the
		# resuming outer call, making fz_tok_target check USE-flag
		# gating (FZ_EN_$idx) against whatever port was visited last
		# instead of the port actually being walked -- silently
		# dropping (or wrongly keeping) later USE-gated dep tokens.
		local cur idx ds tok target
		cur="$1"
		case " $FZ_DONE " in
			*" $cur "*) return 0 ;;
		esac
		FZ_DONE="$FZ_DONE $cur"
		fz_idx_of "$cur"
		idx=$REPLY
		case "$idx" in
			''|*[!0-9]*) return 0 ;;
		esac
		[ "$idx" -ge 1 ] 2>/dev/null || return 0
		[ "$idx" -le "$FZ_NP" ] 2>/dev/null || return 0
		eval "ds=\$FZ_DEPS_$idx"
		for tok in $ds; do
			[ "$tok" = "" ] && continue
			fz_tok_target "$tok" "$idx" 0
			target=$REPLY
			if [ "$target" != "" ]; then
				case " $FZ_DONE " in
					*" $target "*) ;;
					*) fz_dfs "$target" ;;
				esac
			fi
		done
		return 0
	}
 
	FZ_DONE=""
	FZ_REQ=""
	for r in $ROOTS; do
		fz_canon_of "$r"
		rc=$REPLY
		# every entry in $ROOTS is its own explicit "mp install"
		# argument, so it belongs in FZ_REQ regardless of whether an
		# EARLIER root's own dependency walk already reached it first
		# (order in $ROOTS is exactly mp's own argv order) -- real mp
		# now promotes an already-installed-as-a-dep package's
		# requested flag the same way when it's later named
		# explicitly, so gating this on "not already in FZ_DONE"
		# would silently expect the OLD, un-promoted behavior again.
		FZ_REQ="$FZ_REQ $rc"
		fz_dfs "$rc"
	done
	EXPECTED_ALL="$FZ_DONE"
 
	# prune's %tag closure marks the FIRST lexicographically-sorted
	# installed provider of each tag (any installed provider satisfies
	# the tag), not necessarily the install-time pick -- model that
	# exactly, over the final installed set.
	kk=1
	while [ "$kk" -le "$FZ_NTAG" ]; do
		eval "pl=\$FZ_TAGPROVS_$kk"
		firstp=""
		for pi in $pl; do
			fz_canon_of "$pi"
			c=$REPLY
			# only INSTALLED providers count for prune's closure
			case " $FZ_DONE " in
				*" $c "*) ;;
				*) continue ;;
			esac
			if [ "$firstp" = "" ]; then
				firstp="$c"
			elif [ "$c" \< "$firstp" ]; then
				firstp="$c"
			fi
		done
		eval "FZ_RTAGPROV_$kk=\"$firstp\""
		kk=$(( kk + 1 ))
	done
 
	# runtime closure: plain set reachability over FZ_RDEPS.
	fz_runtime_closure() {
		queue="$ROOT_CANONS"
		seen=""
		while [ "$queue" != "" ]; do
			cur=$(echo "$queue" | cut -d' ' -f1)
			queue=$(echo "$queue" | cut -d' ' -f2-)
			[ "$queue" = "$cur" ] && queue=""
			case " $seen " in
				*" $cur "*) continue ;;
			esac
			seen="$seen $cur"
			fz_idx_of "$cur"
			idx=$REPLY
			case "$idx" in
				''|*[!0-9]*) continue ;;
			esac
			[ "$idx" -ge 1 ] 2>/dev/null || continue
			[ "$idx" -le "$FZ_NP" ] 2>/dev/null || continue
			eval "ds=\$FZ_RDEPS_$idx"
			for tok in $ds; do
				[ "$tok" = "" ] && continue
				fz_tok_target "$tok" "$idx" 1
				target=$REPLY
				if [ "$target" != "" ]; then
					case " $queue $seen " in
						*" $target "*) ;;
						*) queue="$queue $target" ;;
					esac
				fi
			done
		done
		EXPECTED_RUNTIME="$seen"
	}
 
	fz_runtime_closure
 
	rm -f "/tmp/fz${FUZZ_I}-hooks.log"
 
	# --- conflict mode: preinstall target, root must fail cleanly ----
	if [ "$CONFLICT_TARGET" != "" ]; then
		mp install "$CONFLICT_TARGET" >/dev/null 2>&1
		out=$(mp install "$CONFLICT_ROOT" 2>&1)
		rc=$?
		if [ "$rc" -eq 0 ]; then
			echo "conflict mode: expected failure, got success (out: $out)"
			return 1
		fi
		case "$out" in
			*"err: "*) ;;
			*) echo "conflict mode: no clean err: (out: $out)"; return 1 ;;
		esac
		while IFS= read -r line; do
			[ -z "$line" ] && continue
			case "$line" in
				*"$TAB"*"$TAB"*"$TAB"*"$TAB"*) echo "conflict mode: db line has >3 fields: $line"; return 1 ;;
			esac
		done < "$WD/db"
		return 0
	fi
 
	# --- the install ------------------------------------------------
	out=$(mp install $ROOTS 2>&1)
	rc=$?
	if [ "$rc" -ne 0 ]; then
		echo "install failed (rc=$rc): $out"
		jj=1
		while [ "$jj" -le "$FZ_NP" ]; do
			eval "c=\$FZ_CANON_$jj"
			eval "d=\$FZ_DEPS_$jj"
			echo "gen p$jj canon=$c deps=[$d]"
			jj=$(( jj + 1 ))
		done
		echo "gen roots=[$ROOTS] mode=$FZ_MODE"
		return 1
	fi
 
	# --- db shape ----------------------------------------------------
	while IFS= read -r line; do
		[ -z "$line" ] && continue
		case "$line" in
			*"$TAB"*"$TAB"*"$TAB"*"$TAB"*) echo "db line has >3 fields: $line"; return 1 ;;
		esac
	done < "$WD/db"
	actual=$(cut -f1 "$WD/db" | sort)
	expected=$(for x in $EXPECTED_ALL; do echo "$x"; done | sort)
	if [ "$actual" != "$expected" ]; then
		echo "closure mismatch: expected=[$expected] actual=[$actual]"
		jj=1
		while [ "$jj" -le "$FZ_NP" ]; do
			eval "c=\$FZ_CANON_$jj"
			eval "d=\$FZ_DEPS_$jj"
			eval "e=\$FZ_EN_$jj"
			echo "gen p$jj canon=$c deps=[$d] en=[$e]"
			jj=$(( jj + 1 ))
		done
		echo "gen roots=[$ROOTS] mode=$FZ_MODE"
		return 1
	fi
	while IFS= read -r line; do
		[ -z "$line" ] && continue
		name=$(echo "$line" | cut -f1)
		req=$(echo "$line" | cut -f4)
		case " $FZ_REQ " in
			*" $name "*)
				[ "$req" = "1" ] || { echo "root $name requested=$req"; return 1; }
				;;
			*)
				[ "$req" = "0" ] || { echo "dep $name requested=$req"; return 1; }
				;;
		esac
	done < "$WD/db"
 
	# --- markers (slot prefixes respected) --------------------------
	for x in $EXPECTED_ALL; do
		base=${x%%:*}
		suf=${x#*:}
		[ "$suf" = "$x" ] && suf=""
		if [ "$suf" = "" ]; then
			[ -f "$MP_PREFIX/$base-installed" ] || { echo "marker missing for $x"; return 1; }
		else
			[ -f "$MP_PREFIX/$base-$suf/$base-installed" ] || { echo "slot marker missing for $x"; return 1; }
		fi
	done
 
	# --- hooks: exact multiset + pipeline order ----------------------
	# pre lines (per-package config hook) fire once for their own port;
	# HOOKS_DIR files are GLOBAL per phase, so each generated dir file
	# fires once for EVERY installed package; the pre_build pipeline
	# fires once per installed package that has a build phase.
	explog=""
	for x in $EXPECTED_ALL; do
		fz_idx_of "$x"
		idx=$REPLY
		eval "hp=\$FZ_HOOKPRE_$idx"
		[ "$hp" = "1" ] && explog="$explog pre$idx"
		if [ "$FZ_PIPELINE" -eq 1 ] && [ $(( idx % 3 )) -eq 0 ]; then
			for L in $PIPE_ORDER; do
				explog="$explog pipe$L"
			done
		fi
	done
	jj=1
	while [ "$jj" -le "$FZ_NP" ]; do
		eval "hd=\$FZ_HOOKDIR_$jj"
		if [ "$hd" = "1" ]; then
			for x in $EXPECTED_ALL; do
				explog="$explog dir$jj"
			done
		fi
		jj=$(( jj + 1 ))
	done
	explog_sorted=$(for x in $explog; do echo "$x"; done | sort)
	actlog_sorted=$(sort "/tmp/fz${FUZZ_I}-hooks.log" 2>/dev/null)
	if [ "$explog_sorted" != "$actlog_sorted" ]; then
		echo "hook multiset mismatch: expected=[$explog_sorted] actual=[$actlog_sorted]"
		return 1
	fi
	case "$explog" in
		*pipe*)
			first=$(echo "$PIPE_ORDER" | cut -d' ' -f1)
			second=$(echo "$PIPE_ORDER" | cut -d' ' -f2)
			pos1=$(grep -n "pipe$first" "/tmp/fz${FUZZ_I}-hooks.log" 2>/dev/null | head -1 | cut -d: -f1)
			pos2=$(grep -n "pipe$second" "/tmp/fz${FUZZ_I}-hooks.log" 2>/dev/null | head -1 | cut -d: -f1)
			if [ -z "$pos1" ] || [ -z "$pos2" ] || [ "$pos1" -ge "$pos2" ]; then
				echo "pipeline order wrong ($first=$pos1 $second=$pos2)"
				return 1
			fi
			;;
	esac
 
	# --- patches: gate expectations ---------------------------------
	for x in $EXPECTED_ALL; do
		fz_idx_of "$x"
		idx=$REPLY
		eval "hp2=\$FZ_PATCH_$idx"
		[ "$hp2" -eq 1 ] || continue
		dummy=$(cat "$WD/$x/fz${FUZZ_I}p$idx/dummy" 2>/dev/null)
		case "$dummy" in
			*uncond*) ;;
			*) echo "patch 001 missing for $x"; return 1 ;;
		esac
		eval "en=\$FZ_EN_$idx"
		case "$en" in
			*" ssl"*)
				case "$dummy" in
					*sslpatch*) ;;
					*) echo "ssl patch missing for $x"; return 1 ;;
				esac
				;;
			*)
				case "$dummy" in
					*sslpatch*) echo "ssl patch wrongly applied for $x"; return 1 ;;
				esac
				;;
		esac
	done
 
	# --- provider choice: lowest pref --------------------------------
	if [ "$FZ_MODE" -ge 20 ] && [ "$FZ_MODE" -lt 45 ]; then
		eval "want=\$FZ_TAGPROV_1"
		case " $EXPECTED_ALL " in
			*" $want "*) ;;
			*)
				echo "expected provider $want not installed"
				jj=1
				while [ "$jj" -le "$FZ_NP" ]; do
					eval "c=\$FZ_CANON_$jj"
					eval "d=\$FZ_DEPS_$jj"
					echo "gen p$jj canon=$c deps=[$d]"
					jj=$(( jj + 1 ))
				done
				echo "gen roots=[$ROOTS] expected=[$EXPECTED_ALL]"
				return 1
				;;
		esac
		if [ "$want" != "$PROV2" ]; then
			case " $EXPECTED_ALL " in
				*" $PROV2 "*) echo "wrong provider installed: $PROV2"; return 1 ;;
			esac
		fi
	fi
 
	# --- prune: exact equality with the runtime closure --------------
	dry=$(mp prune --dry-run 2>&1)
	prunable=""
	for x in $EXPECTED_ALL; do
		case " $EXPECTED_RUNTIME " in
			*" $x "*) continue ;;
		esac
		case " $ROOT_CANONS " in
			*" $x "*) continue ;;
		esac
		prunable="$prunable $x"
	done
	expected_p=$(for x in $prunable; do echo "would remove: $x"; done | sort)
	actual_p=$(echo "$dry" | grep '^would remove:' | sort)
	if [ "$expected_p" != "$actual_p" ]; then
		echo "prune mismatch: expected=[$expected_p] actual=[$actual_p]"
		return 1
	fi
 
	# --- random removal ----------------------------------------------
	candidates=""
	for x in $EXPECTED_ALL; do
		case " $PROVIDERS " in
			*" $x "*) continue ;;
		esac
		candidates="$candidates $x"
	done
	if [ "$candidates" != "" ]; then
		n=0
		for x in $candidates; do n=$(( n + 1 )); done
		fz_rnd "$n"
		pick=$(( REPLY + 1 ))
		target=$(for x in $candidates; do echo "$x"; done | sed -n "${pick}p")
		mp remove --force "$target" >/dev/null 2>&1
		if grep -q "^$target$TAB" "$WD/db"; then
			echo "remove failed for $target"
			return 1
		fi
		base=${target%%:*}
		suf=${target#*:}
		[ "$suf" = "$target" ] && suf=""
		if [ "$suf" = "" ]; then
			[ -f "$MP_PREFIX/$base-installed" ] && { echo "marker survived removal of $target"; return 1; }
		else
			[ -f "$MP_PREFIX/$base-$suf/$base-installed" ] && { echo "slot marker survived removal of $target"; return 1; }
		fi
	fi
 
	return 0
}
 
# the whole batch is one reported test (per-iteration diagnostics name
# the failing iteration), so 1000 iterations don't spam 1000 lines.
test_fuzz_batch() {
	t_begin "fuzz_${FUZZ_ITERATIONS}_iterations_seed_${FUZZ_SEED}"
	reset_state
	FUZZ_I=1
	while [ "$FUZZ_I" -le "$FUZZ_ITERATIONS" ]; do
		ferr=$(fz_iteration "$FUZZ_I" 2>&1)
		frc=$?
		if [ "$frc" -ne 0 ]; then
			t_fail "iteration $FUZZ_I (FUZZ_SEED=$FUZZ_SEED): $ferr"
			echo "state left at iteration $FUZZ_I for inspection"
			return
		fi
		if [ $(( FUZZ_I % 100 )) -eq 0 ]; then
			echo "  [fuzz] $FUZZ_I/$FUZZ_ITERATIONS iterations ok"
		fi
		FUZZ_I=$(( FUZZ_I + 1 ))
	done
	t_pass
}
 
run_fuzz_suite() {
	test_fuzz_batch
}
powered by btf.