AtlatestRepositorytessera
1
#!/usr/bin/env bash2
# Run only on an isolated build/test host. Never inherits a user's desktop.3
set -euo pipefail4
tools=$(cd "$(dirname "$0")" && pwd)5
fixtures=$(realpath "${3:?fixture directory}")6
binary=$(realpath "${1:?binary}")7
out=$(realpath -m "${2:?receipts directory}")8
mkdir -p "$out"9
scratch=$(mktemp -d /tmp/tessera-release-smoke.XXXXXX)10
chmod 700 "$scratch"11
server= parent= client=12
cleanup() {13
local status=$?14
for child in "$client" "$server" "$parent"; do15
[[ -z $child ]] || { kill -TERM "$child" 2>/dev/null || true; wait "$child" 2>/dev/null || true; }16
done17
if [[ $status != 0 ]]; then tail -40 "$out/server.log" "$out/parent.log" 2>/dev/null || true; fi18
rm -rf "$scratch"19
}20
trap cleanup EXIT21
unset DISPLAY WAYLAND_DISPLAY WAYLAND_SOCKET SWAYSOCK DBUS_SESSION_BUS_ADDRESS TMUX \22
SIGIL_WM_LIBRARY TESSERA_LIBRARY TESSERA_CONFIG TESSERA_DATA_DIR TESSERA_THEME_DIR \23
TESSERA_THEME_RUNTIME_DIR TESSERA_LOGIN_SESSION TESSERA_CLIENT_ENV_FILE24
export HOME=$scratch/home XDG_CONFIG_HOME=$scratch/config XDG_CACHE_HOME=$scratch/cache25
export XDG_DATA_HOME=$scratch/data XDG_RUNTIME_DIR=$scratch/run26
export TESSERA_REPL=$scratch/run/repl TESSERA_SOCKET=release-smoke27
export TESSERA_THEME_LIVE=tessera28
export PULSE_SERVER=unix:$scratch/no-audio29
mkdir -p "$HOME" "$XDG_CONFIG_HOME" "$XDG_CACHE_HOME" "$XDG_DATA_HOME" "$XDG_RUNTIME_DIR"30
chmod 700 "$XDG_RUNTIME_DIR"31
cd "$scratch"32
if env -u XDG_RUNTIME_DIR "$binary" start > "$out/missing-runtime.log" 2>&1; then exit 1; fi33
grep -q 'Tessera: XDG_RUNTIME_DIR is missing' "$out/missing-runtime.log"34
"$binary" --version > "$out/version.txt"35
"$binary" --help > "$out/help.txt"36
"$binary" theme list > "$out/palettes.txt"37
grep -q orpiment "$out/palettes.txt"38
if "$binary" msg '(+ 1 2)' > "$out/no-msg-alias.log" 2>&1; then exit 1; else [[ $? == 2 ]]; fi39
if "$binary" eval > "$out/eval-usage.log" 2>&1; then exit 1; else [[ $? == 2 ]]; fi40
if "$binary" eval '(+ 1 2)' > "$out/missing-socket.log" 2>&1; then exit 1; else [[ $? == 1 ]]; fi41
weston --backend=headless --renderer=pixman --socket=parent --width=1280 --height=720 \42
--idle-time=0 --log="$out/parent.log" >/dev/null 2>&1 & parent=$!43
for ((i=0;i<200;i++)); do [[ ! -S $XDG_RUNTIME_DIR/parent ]] || break; sleep .05; done44
[[ -S $XDG_RUNTIME_DIR/parent ]]45
export WAYLAND_DISPLAY=$XDG_RUNTIME_DIR/parent46
unset WLR_BACKENDS WLR_RENDERER TESSERA_MODIFIER47
export SIGIL_WLROOTS_TEST_INPUT=1 TESSERA_MODIFIER=Super48
# Plain desktop invocation must exit without a compositor or asset extraction.49
"$binary" > "$out/desktop-help.txt" 2>&150
grep -q "tessera start" "$out/desktop-help.txt"51
! grep -q "WAYLAND_SOCKET=" "$out/desktop-help.txt"52
export TESSERA_LOGIN_SESSION=1 TESSERA_SOCKET=parent TESSERA_REPL=$XDG_RUNTIME_DIR/parent-repl53
export WLR_SCENE_DISABLE_DIRECT_SCANOUT=154
"$binary" start > "$out/server.log" 2>&1 & server=$!55
for ((i=0;i<400;i++)); do56
endpoint=$(sed -n 's/^TESSERA_REPL=//p' "$out/server.log" | tail -n1)57
[[ -z $endpoint || ! -S $endpoint ]] || break58
kill -0 "$server"; sleep .0559
done60
export TESSERA_REPL=$endpoint61
export TESSERA_SOCKET=$(sed -n 's/^WAYLAND_SOCKET=//p' "$out/server.log" | tail -n1)62
[[ $TESSERA_SOCKET != parent && $TESSERA_REPL != "$XDG_RUNTIME_DIR/parent-repl" ]]63
[[ -S $TESSERA_REPL && $(stat -c %a "$TESSERA_REPL") == 600 ]]64
evaluate() { "$binary" eval "$1"; }65
[[ $(evaluate '(+ 1 2)') == 3 ]]66
expected_commit=$(git -C "$tools/.." rev-parse HEAD)67
[[ $(evaluate '(begin (import (sigil meta)) (app-commit))') == "\"$expected_commit\"" ]]68
printf 'RUNTIME_APP_COMMIT=%s\n' "$expected_commit" > "$out/app-commit.txt"69
for args in 'volume 55' 'brightness 80' 'mic muted' 'keyboard-layout us'; do70
read -r kind value <<< "$args"71
[[ $("$binary" osd "$kind" "$value") == '#t' ]]72
done73
for args in 'unknown 50' 'brightness 101' 'volume -1' 'mic bad'; do74
read -r kind value <<< "$args"75
if "$binary" osd "$kind" "$value" > "$out/osd-invalid-$kind.log" 2>&1; then exit 1; else [[ $? == 2 ]]; fi76
done77
if evaluate '(error "release error probe")' > "$out/expression-error.log" 2>&1; then exit 1; fi78
bash "$tools/test-repl-command" "$binary" "$out/repl"79
"$fixtures/repl-terminal" "$binary" > "$out/repl-terminal.txt"80
grep -q 'REPL_TERMINAL=PASS' "$out/repl-terminal.txt"81
WAYLAND_DISPLAY=$TESSERA_SOCKET timeout --foreground 30 "$fixtures/security-context-client" check native > "$out/security-context.log" 2>&182
cat "$out/security-context.log"83
[[ $(evaluate '(and84
(= (length (module-exports (find-module (quote (tessera api))))) 79)85
(every (lambda (name) (procedure? (%module-lookup name)))86
(module-exports (find-module (quote (tessera api)))))87
(every (lambda (name) (not (%module-lookup name)))88
(quote (tessera-config tessera-run-command! tessera-reload!89
tessera-host-native host-snapshot start-host! stop-host!))))') == '#t' ]]90
bash "$tools/test-release-bound-keys" "$binary" "$fixtures" "$out" "$scratch" "$server"91
evaluate '(define (release-live-value) 1)' > "$out/redefine.log"92
[[ $(evaluate '(release-live-value)') == 1 ]]93
evaluate '(define (release-live-value) 2)' >> "$out/redefine.log"94
[[ $(evaluate '(release-live-value)') == 2 ]]95
evaluate '(output-box (focused-output))' > "$out/output-box.txt"96
evaluate '(background-command)' > "$out/background.txt"97
! grep -q 'Tessera: unpacking bundled wallpapers' "$out/missing-runtime.log" "$out/server.log"98
# A binary-only HOME must produce native-size images asynchronously.99
wait_background() {100
local recipe=$1 palette=$2 seed=$3 receipt=$4101
for ((attempt=0; attempt<400; attempt++)); do102
evaluate '(background-command)' > "$receipt"103
if grep -Fq "/v1/$recipe/$palette/seed-$seed/" "$receipt" &&104
[[ -n $(find "$XDG_DATA_HOME/tessera/backgrounds/v1/$recipe/$palette/seed-$seed" \105
-name '*.png' -type f -print -quit 2>/dev/null) ]]; then return 0; fi106
kill -0 "$server"; sleep .1107
done108
printf 'RELEASE_BACKGROUND_TIMEOUT=%s/%s/%s\n' "$recipe" "$palette" "$seed" >&2109
return 1110
}111
wait_background facets orpiment 1 "$out/cold-background.txt"112
# A burst is one pending theme operation, with bounded public action admission.113
[[ $(evaluate '(begin (for-each (lambda (index) (next-wallpaper!)) (iota 500)) #t)') == '#t' ]]114
wait_background drift orpiment 1 "$out/burst-background.txt"115
evaluate '(define release-overflow-before (length (problems)))' > "$out/overflow-before.txt"116
[[ $(evaluate '(let ((accepted 0) (rejected 0))117
(for-each (lambda (index)118
(if (focus-workspace! "1") (set! accepted (+ accepted 1)) (set! rejected (+ rejected 1))))119
(iota 500))120
(list accepted rejected))') == '(64 436)' ]]121
[[ $(evaluate '(and (> (length (problems)) release-overflow-before)122
(any (lambda (problem) (string-contains? (format "~a" problem) "rejected 436")) (problems)))') == '#t' ]]123
[[ $(evaluate '(begin (apply-theme! "smalti") (set-wallpaper! "drift" 7) #t)') == '#t' ]]124
wait_background drift smalti 7 "$out/merged-background.txt"125
[[ $(evaluate '(equal? (palette-id (theme-palette)) "smalti")') == '#t' ]]126
[[ $(evaluate "(set-wallpaper! 'drift seed: 42 params: '((density . 0.7)))") == '#t' ]]127
wait_background drift smalti 42 "$out/parameter-background.txt"128
[[ $(evaluate "(= (cdr (assq 'density (theme-wallpaper-params))) 0.7)") == '#t' ]]129
[[ $(evaluate "(save-wallpaper! \"$out/api-export.png\")") == '#t' ]]130
for ((attempt=0; attempt<200; attempt++)); do131
[[ ! -f $out/api-export.png ]] || break132
kill -0 "$server"; sleep .1133
done134
native_cache=$(find "$XDG_DATA_HOME/tessera/backgrounds/v1/drift/smalti/seed-42" -name 1280x720.png)135
node "$tools/../test/check-wallpaper-export.mjs" "$out/api-export.png" "$native_cache" drift smalti 42 1280 720 '(density . 0.7)'136
[[ $(evaluate "(save-wallpaper! \"$out/api-sized-export.png\" width: 256 height: 144)") == '#t' ]]137
for ((attempt=0; attempt<200; attempt++)); do138
[[ ! -f $out/api-sized-export.png ]] || break139
kill -0 "$server"; sleep .1140
done141
node "$tools/../test/check-wallpaper-export.mjs" "$out/api-sized-export.png" - drift smalti 42 256 144 '(density . 0.7)'142
"$binary" wallpaper save "$out/cli-export.png" --size 320x180 > "$out/cli-export.txt"143
node "$tools/../test/check-wallpaper-export.mjs" "$out/cli-export.png" - drift smalti 42 320 180 '(density . 0.7)'144
[[ $(evaluate '(begin (apply-theme! "orpiment" "facets" 1) #t)') == '#t' ]]145
wait_background facets orpiment 1 "$out/restored-background.txt"146
"$binary" theme apply workbench > "$out/apply-workbench.log" 2>&1147
wait_background facets workbench 1 "$out/workbench-background.txt"148
[[ $(evaluate '(= (config-focused-border (current-config)) #xff8800ff)') == '#t' ]]149
"$binary" theme apply orpiment --wallpaper drift > "$out/apply-drift-a.log" 2>&1150
wait_background drift orpiment 23 "$out/drift-a-background.txt"151
"$binary" theme apply workbench > "$out/apply-drift-b.log" 2>&1152
wait_background drift workbench 23 "$out/drift-b-background.txt"153
"$binary" theme wallpaper facets > "$out/wallpaper-facets.log" 2>&1154
[[ $(evaluate '(palette-id (theme-palette))') == '"workbench"' ]]155
wait_background facets workbench 1 "$out/wallpaper-facets-background.txt"156
"$binary" theme preview lichen --wallpaper drift > "$out/preview-wallpaper.log" 2>&1157
wait_background drift lichen 23 "$out/preview-wallpaper-background.txt"158
"$binary" theme revert > "$out/revert-wallpaper.log" 2>&1159
[[ $(evaluate '(theme-wallpaper)') == '"facets"' ]]160
"$binary" theme wallpaper facets --seed -3 > "$out/wallpaper-seed.log" 2>&1161
wait_background facets workbench -3 "$out/seed-background.txt"162
[[ $(evaluate '(theme-wallpaper-seed)') == -3 ]]163
"$binary" wallpaper render drift --palette current --seed 0 --size 512x320 \164
--output "$scratch/repeat-a.png" > "$out/render-a.txt"165
"$binary" wallpaper render drift --palette current --seed 0 --size 512x320 \166
--output "$scratch/repeat-b.png" > "$out/render-b.txt"167
cmp "$scratch/repeat-a.png" "$scratch/repeat-b.png"168
"$binary" wallpaper render drift --palette current --seed 1 --size 512x320 \169
--output "$scratch/changed.png" > "$out/render-changed.txt"170
! cmp -s "$scratch/repeat-a.png" "$scratch/changed.png"171
find "$XDG_DATA_HOME/tessera/backgrounds" -type f -name '*.png' \172
-exec sha256sum {} + > "$out/assets.sha256"173
"$binary" theme apply lichen > "$out/apply.log" 2>&1174
[[ $(evaluate '(= (config-focused-border (current-config)) (config-focused-border (stock-config-for (theme-palette))))') == '#t' ]]175
evaluate '(config-focused-border (current-config))' > "$out/lichen-border.txt"176
"$binary" theme preview smalti > "$out/preview.log" 2>&1177
[[ $(evaluate '(= (config-focused-border (current-config)) (config-focused-border (stock-config-for (theme-palette))))') == '#t' ]]178
"$binary" theme revert > "$out/revert.log" 2>&1179
"$binary" theme status > "$out/status.txt"180
[[ $(evaluate '(config-focused-border (current-config))') == "$(cat "$out/lichen-border.txt")" ]]181
export RELEASE_SMOKE_WAYLAND_DISPLAY=$TESSERA_SOCKET182
TESSERA_RELEASE_SMOKE=1 bash "$tools/test-float-snapping" "$binary" "$fixtures" "$out" "$scratch"183
# The final executable must use its registered native ABI, with no WM plugin.184
if grep -E '/gnu/store/|/work/|libsigil-wm|bootstrap' "/proc/$server/maps" > "$out/forbidden-maps.txt"; then185
# The executable itself may reside in /work; permit exactly its pathname.186
grep -vF "$binary" "$out/forbidden-maps.txt" > "$out/forbidden-maps-other.txt" || true187
[[ ! -s $out/forbidden-maps-other.txt ]]188
fi189
cp "/proc/$server/maps" "$out/runtime-maps.txt"190
evaluate '(run-command! (quote (exit)))' > "$out/exit.txt" || true191
for ((i=0;i<200;i++)); do ! kill -0 "$server" 2>/dev/null && break; sleep .05; done192
if kill -0 "$server" 2>/dev/null; then kill -TERM "$server"; fi193
wait "$server"194
server=195
# A cold process must load a user config in the same environment as IPC.196
# Deliberately omit (sigil process): getenv is in the shared user vocabulary.197
export TESSERA_CONFIG=$scratch/cold-config.sgl198
cat > "$TESSERA_CONFIG" <<'CONFIG'199
(import (tessera config))200
(define release-config-home (getenv "HOME"))201
(unless release-config-home (error "cold config needs HOME"))202
(config-with default-config focused-border: #x123456ff203
startup: '() session-helpers: '())204
CONFIG205
# Retain the generated cache across a fresh process and config load.206
"$binary" start > "$out/warm-server.log" 2>&1 & server=$!207
for ((i=0;i<400;i++)); do208
endpoint=$(sed -n 's/^TESSERA_REPL=//p' "$out/warm-server.log" | tail -n1)209
[[ -z $endpoint || ! -S $endpoint ]] || break210
kill -0 "$server"; sleep .05211
done212
export TESSERA_REPL=$endpoint213
export TESSERA_SOCKET=$(sed -n 's/^WAYLAND_SOCKET=//p' "$out/warm-server.log" | tail -n1)214
[[ $TESSERA_SOCKET != parent && $TESSERA_REPL != "$XDG_RUNTIME_DIR/parent-repl" ]]215
[[ -S $TESSERA_REPL ]]216
[[ $(evaluate '(+ 2 3)') == 5 ]]217
grep -q 'TESSERA_CONFIG_LOADED=' "$out/warm-server.log"218
! grep -q 'configuration .* not used:' "$out/warm-server.log"219
[[ $(evaluate '(equal? release-config-home (getenv "HOME"))') == '#t' ]]220
[[ $(evaluate '(= (config-focused-border (current-config)) #x123456ff)') == '#t' ]]221
[[ $(evaluate '(apply-config! (load-config (getenv "TESSERA_CONFIG")))') == '#t' ]]222
! grep -q 'Tessera: unpacking bundled wallpapers' "$out/warm-server.log"223
evaluate '(run-command! (quote (exit)))' > "$out/warm-exit.txt" || true224
for ((i=0;i<200;i++)); do ! kill -0 "$server" 2>/dev/null && break; sleep .05; done225
if kill -0 "$server" 2>/dev/null; then kill -TERM "$server"; fi226
wait "$server"227
server=228
! grep -q 'event handler failed' "$out/server.log" "$out/warm-server.log"229
bash "$tools/test-repl-startup" "$binary" "$out/repl-startup" "$fixtures"230
printf 'RELEASE_NESTED_SMOKE=PASS\n' | tee "$out/PASS"