ci(smoke): cover teardown, state transitions and fake hardware

The smoke test only exercised steady-state rendering and killed waybar with
SIGTERM, so whole crash classes were invisible: exit-time use-after-free
(#5182), module state transitions (#5183) and hardware-backed modules (#5179).
Add tiers that hit those paths under ASan (+ _GLIBCXX_ASSERTIONS):

- lib.sh: assert_clean_exit (SIGINT teardown -> checks segfault/abort + ASan
  report emitted during destruction), output hotplug helpers, signal/reload,
  WAYBAR_WRAP hook, opt-in leak detection.
- lifecycle.sh (gating): clean exit, runtime output hotplug (Bar/module
  destroy), toggle/reload churn, fast-interval teardown race (#5182 class).
- fuzz.sh (gating): pathological custom-backend output (empty, nonzero exit,
  invalid JSON, huge, non-UTF8, empty format).
- coverage.sh (gating): every Factory module must be classified for smoke
  coverage; a new unlisted module fails the job (#5179 slipped through).
- modules.sh: also render the whole matrix inside a group; SIGINT teardown per
  module instead of SIGTERM.
- state.sh (best-effort): real mpd driven through an empty queue (#5183) +
  stop/clear; pulseaudio + slider on a null sink.
- hardware.sh (best-effort): backlight, backlight/slider (#5179) and battery
  via umockdev.
- leakcheck.sh (report-only): clean-exit run under LSan.
This commit is contained in:
Alex
2026-07-05 22:21:46 +02:00
parent 445e2aec1f
commit 9a10949938
10 changed files with 558 additions and 13 deletions
+25 -3
View File
@@ -47,13 +47,35 @@ EOF
smoke::assert_not_blank "$SHOTDIR/$safe.png" || ok=0
fi
[ "$ok" = 1 ] || fails+=("$mod")
kill "$WAYBAR_PID" 2>/dev/null || true
sleep 1
# SIGINT teardown (not SIGTERM) so each module's destructor path is ASan-checked.
smoke::assert_clean_exit || fails+=("$mod (exit)")
echo "::endgroup::"
done
# --- all modules inside a group -----------------------------------------
# Group children have a different construct/destroy path than top-level modules
# (#5179 crashed inside a group), so render the whole matrix wrapped in one.
echo "::group::modules inside a group"
mods_json="$(printf '%s\n' "${!MODULES[@]}" | jq -R . | jq -s .)"
opts_json='{}'
for mod in "${!MODULES[@]}"; do
opts_json="$(jq --arg k "$mod" --argjson v "${MODULES[$mod]}" '. + {($k):$v}' <<<"$opts_json")"
done
gcfg="$(mktemp --suffix=.json)"
jq -n --argjson mods "$mods_json" --argjson opts "$opts_json" '
{layer:"top",position:"top",height:30,"modules-center":["group/g"],"group/g":{modules:$mods}} + $opts' \
> "$gcfg"
smoke::launch_waybar "$gcfg" "$DIR/style.css" 5
ok=1
smoke::assert_alive || ok=0
smoke::assert_clean || ok=0
[ "$ok" = 1 ] && { smoke::screenshot "$SHOTDIR/_group.png"; smoke::assert_not_blank "$SHOTDIR/_group.png" || ok=0; }
smoke::assert_clean_exit || ok=0
[ "$ok" = 1 ] || fails+=("group")
echo "::endgroup::"
if [ "${#fails[@]}" -gt 0 ]; then
echo "::error::modules failed to render cleanly: ${fails[*]}"
exit 1
fi
echo "✓ all ${#MODULES[@]} modules rendered cleanly"
echo "✓ all ${#MODULES[@]} modules rendered cleanly (standalone + grouped)"