aboutsummaryrefslogtreecommitdiffstats
path: root/.extras/test-logic.sh
blob: a05e9909f1f7d6011293b5ef117b8ca01042982a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#!/bin/bash
#
# Logic self-check for .extras/test-build. Covers the pure, host-side parts:
# dependency resolution, override application, unknown-dep -> UNMET, cache
# decisions, and BLOCKED-BY-DEP propagation. No docker.
#
# Run: bash .extras/test-logic.sh
#
set -uo pipefail

SCRIPT="$(dirname "$0")/test-build"
T=$(mktemp -d)
BASE_DB=$(mktemp -d); mkdir -p "$BASE_DB"

cleanup() { rm -rf "$T" "$BASE_DB"; }
trap cleanup EXIT

# Source the script without running main(). Sourcing re-runs the CONFIG block,
# so set test vars AFTER the source.
LIB=$(mktemp)
sed '/^main "\$@"$/d' "$SCRIPT" > "$LIB"
# shellcheck disable=SC1090
source "$LIB" 2>/dev/null
rm -f "$LIB"

pass=0; fail=0
ok()  { echo "  ok: $1"; ((pass++)); return 0; }
bad() { echo "  FAIL: $1"; ((fail++)); return 0; }

# Placeholder assertion so this file runs before any logic exists.
ok "script sources without executing main"

# --- version selection ------------------------------------------------------
SBO_TREE_CURRENT="/trees/current"
SBO_TREE_STABLE="/trees/stable"
IMAGE_CURRENT="sbo-testbuild:current"
IMAGE_STABLE="sbo-testbuild:15.0"

VERSION_ID="current"; select_version_paths
[[ "$ACTIVE_TREE" == "/trees/current" ]] && ok "current -> current tree" || bad "current tree wrong: [$ACTIVE_TREE]"
[[ "$ACTIVE_IMAGE" == "sbo-testbuild:current" ]] && ok "current -> current image" || bad "current image wrong: [$ACTIVE_IMAGE]"

VERSION_ID="15.0"; select_version_paths
[[ "$ACTIVE_TREE" == "/trees/stable" ]] && ok "15.0 -> stable tree" || bad "stable tree wrong: [$ACTIVE_TREE]"
[[ "$ACTIVE_IMAGE" == "sbo-testbuild:15.0" ]] && ok "15.0 -> stable image" || bad "stable image wrong: [$ACTIVE_IMAGE]"

# --- resolution -------------------------------------------------------------
# Fake SBo tree under one category. mk <prog> "<REQUIRES>".
mk() { mkdir -p "$T/cat/$1"; echo "REQUIRES=\"$2\"" > "$T/cat/$1/$1.info"; }
mk c ""
mk b "c"
mk a "b %README%"
mk d "nonexistentpkg"
mk e "f"
mk f "e"
mk g "b"

SBO_TREE_ROOTS=("$T")   # resolver reads this global (set by select in real runs)

resolve_target "$T/cat/a"
order=""; for x in "${RESOLVED_ORDER[@]}"; do order+="$(basename "$x") "; done
order="${order% }"
[[ "$order" == "c b a" ]] && ok "topo order c b a" || bad "topo order, got: [$order]"
[[ "${HAS_README[$T/cat/a]:-}" == "1" ]] && ok "%README% recorded" || bad "%README% not recorded"
[[ ${#UNMET[@]} -eq 0 ]] && ok "no false unmet" || bad "unexpected unmet"

resolve_target "$T/cat/d"
[[ ${#UNMET[@]} -eq 1 ]] && ok "unmet-dep caught" || bad "unmet-dep missed"

resolve_target "$T/cat/e"
[[ ${#CYCLES[@]} -ge 1 ]] && ok "cycle caught" || bad "cycle missed"

# --- overrides --------------------------------------------------------------
VERSION_ID="current"   # reset: left at 15.0 by the version-selection checks above
OV=$(mktemp)
cat > "$OV" <<'EOF'
# comment ignored
drop:   dropme
rename: oldname -> newname
fetch:  fetchme
EOF
TB_OVERRIDES="$OV"
load_overrides

[[ "${OV_DROP[dropme]:-}" == "1" ]] && ok "override drop parsed" || bad "drop not parsed"
[[ "${OV_RENAME[oldname]:-}" == "newname" ]] && ok "override rename parsed" || bad "rename not parsed"
[[ "${OV_FETCH[fetchme]:-}" == "1" ]] && ok "override fetch parsed" || bad "fetch not parsed"

# rename maps a token
[[ "$(apply_rename oldname)" == "newname" ]] && ok "apply_rename maps" || bad "apply_rename wrong: [$(apply_rename oldname)]"
[[ "$(apply_rename untouched)" == "untouched" ]] && ok "apply_rename passthrough" || bad "apply_rename mangled untouched"

# drop filters the order (build a fake order of dirs; dropme is removed)
mk dropme ""
mk keepme ""
RESOLVED_ORDER=("$T/cat/dropme" "$T/cat/keepme")
apply_overrides_to_order
kept=""; for x in "${RESOLVED_ORDER[@]}"; do kept+="$(basename "$x") "; done
kept="${kept% }"
[[ "$kept" == "keepme" ]] && ok "drop removes from order" || bad "drop failed, order=[$kept]"

# all entries dropped -> RESOLVED_ORDER must be truly empty (not one "" element)
OV_DROP=([dropme]=1 [keepme]=1)
RESOLVED_ORDER=("$T/cat/dropme" "$T/cat/keepme")
apply_overrides_to_order
[[ ${#RESOLVED_ORDER[@]} -eq 0 ]] && ok "all-dropped -> empty order" || bad "all-dropped left ${#RESOLVED_ORDER[@]} elem(s): [${RESOLVED_ORDER[*]}]"
OV_DROP=()
rm -f "$OV"

# overrides only apply on current; on 15.0 they are a no-op
VERSION_ID="15.0"
TB_OVERRIDES="$OV"   # file gone; must not error, must clear maps
load_overrides
[[ ${#OV_DROP[@]} -eq 0 ]] && ok "overrides inert on 15.0" || bad "overrides applied on 15.0"
VERSION_ID="current"

# --- cache ------------------------------------------------------------------
PKG_CACHE=$(mktemp -d)
CACHE_ROOT="$PKG_CACHE/sha256-deadbeef"   # simulate a resolved digest namespace
mkc() { mkdir -p "$CACHE_ROOT/$1/$2"; : > "$CACHE_ROOT/$1/$2/$3"; }

mkc net libfoo "libfoo-1.1-x86_64-1_danix.txz"
[[ "$(cache_decision net libfoo 1.1)" == "cached" ]] && ok "cache hit on version match" || bad "cache_decision got [$(cache_decision net libfoo 1.1)]"
[[ "$(cache_decision net libfoo 1.2)" == "bump:1.1:1.2" ]] && ok "cache bump reported" || bad "cache bump got [$(cache_decision net libfoo 1.2)]"
[[ "$(cache_decision net libbar 1.0)" == "new" ]] && ok "cache new for absent" || bad "cache new got [$(cache_decision net libbar 1.0)]"

hit="$(cache_path net libfoo 1.1)"
[[ "$hit" == "$CACHE_ROOT/net/libfoo/libfoo-1.1-x86_64-1_danix.txz" ]] && ok "cache_path returns hit" || bad "cache_path got [$hit]"
[[ -z "$(cache_path net libfoo 9.9)" ]] && ok "cache_path empty on miss" || bad "cache_path not empty on miss"

srctmp=$(mktemp -d); : > "$srctmp/libfoo-1.2-x86_64-1_danix.txz"
cache_store net libfoo "$srctmp/libfoo-1.2-x86_64-1_danix.txz"
count=$(find "$CACHE_ROOT/net/libfoo" -name '*.t?z' | wc -l)
[[ "$count" -eq 1 ]] && ok "cache_store evicts to one file" || bad "cache_store left $count files"
[[ -e "$CACHE_ROOT/net/libfoo/libfoo-1.2-x86_64-1_danix.txz" ]] && ok "cache_store stored new file" || bad "cache_store did not store"
rm -rf "$srctmp"

# disabled cache -> new
CACHE_ROOT_SAVE="$CACHE_ROOT"; USE_CACHE=0
[[ "$(cache_decision net libfoo 1.2)" == "new" ]] && ok "--no-cache disables (new)" || bad "disabled cache got [$(cache_decision net libfoo 1.2)]"
USE_CACHE=1; CACHE_ROOT="$CACHE_ROOT_SAVE"

# --- BLOCKED-BY-DEP (depends_on_failed) -------------------------------------
dead=(b)
if depends_on_failed "$T/cat/g" dead; then ok "g blocked when b dead"; else bad "g should block on b"; fi
if depends_on_failed "$T/cat/a" dead; then ok "a blocked when b dead (direct)"; else bad "a should block on b"; fi

dead=(c)
if depends_on_failed "$T/cat/a" dead; then bad "a wrongly blocked on c"; else ok "a not directly blocked by c"; fi
if depends_on_failed "$T/cat/b" dead; then ok "b blocked when c dead"; else bad "b should block on c"; fi

dead=()
if depends_on_failed "$T/cat/a" dead; then bad "a blocked with empty dead"; else ok "no block when nothing dead"; fi

dead=("%README%")
if depends_on_failed "$T/cat/a" dead; then bad "%README% treated as dep"; else ok "%README% not treated as dep"; fi

echo
echo "$pass passed, $fail failed"
[[ $fail -eq 0 ]] || exit 1
echo "ALL LOGIC CHECKS PASS"