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:
Executable
+80
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env bash
|
||||
# Tier 4 — lifecycle / teardown safety net.
|
||||
#
|
||||
# Everything above renders in steady state and kills waybar with SIGTERM, which
|
||||
# never runs the C++ destructors. The crash classes that hurt most (exit,
|
||||
# DPMS/output unmap, reload) all live in that create/destroy path, so exercise it
|
||||
# explicitly under ASan:
|
||||
# 1. clean exit on SIGINT (the real Bar teardown path, #5182)
|
||||
# 2. runtime output hotplug (bar + module destruction while running, #5182)
|
||||
# 3. visibility toggle + config reload churn (SIGUSR1 / SIGUSR2)
|
||||
# 4. fast-interval modules torn down mid-tick (thread vs destructor races)
|
||||
#
|
||||
# Usage: lifecycle.sh
|
||||
set -euo pipefail
|
||||
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
# shellcheck source=lib.sh
|
||||
source "$DIR/lib.sh"
|
||||
|
||||
CFG="$DIR/config.jsonc"
|
||||
STYLE="$DIR/style.css"
|
||||
|
||||
smoke::setup
|
||||
smoke::start_compositor
|
||||
trap smoke::stop EXIT
|
||||
|
||||
fail=0
|
||||
|
||||
# --- 1) clean exit on SIGINT (destructor path, #5182) --------------------
|
||||
echo "::group::clean exit (SIGINT)"
|
||||
smoke::launch_waybar "$CFG" "$STYLE" 5
|
||||
smoke::assert_alive || fail=1
|
||||
smoke::assert_clean_exit || fail=1
|
||||
echo "::endgroup::"
|
||||
|
||||
# --- 2) output hotplug at runtime (bar/module destroy, #5182) ------------
|
||||
if [ "$COMPOSITOR" = sway ]; then
|
||||
echo "::group::output hotplug"
|
||||
smoke::launch_waybar "$CFG" "$STYLE" 5
|
||||
smoke::assert_alive || fail=1
|
||||
for _ in 1 2 3; do
|
||||
smoke::add_output
|
||||
smoke::assert_alive || { fail=1; break; }
|
||||
smoke::remove_output # destroys that output's Bar -> ~Bar -> unmap
|
||||
smoke::assert_alive || { fail=1; break; }
|
||||
done
|
||||
smoke::assert_clean || fail=1
|
||||
smoke::assert_clean_exit || fail=1
|
||||
echo "::endgroup::"
|
||||
fi
|
||||
|
||||
# --- 3) visibility toggle + reload churn ---------------------------------
|
||||
echo "::group::signal churn (toggle + reload)"
|
||||
smoke::launch_waybar "$CFG" "$STYLE" 5
|
||||
smoke::assert_alive || fail=1
|
||||
for _ in 1 2 3; do smoke::signal SIGUSR1 1; done # hide/show mode churn
|
||||
smoke::reload # SIGUSR2: recreate bars/modules
|
||||
smoke::assert_alive || fail=1
|
||||
smoke::assert_clean_exit || fail=1
|
||||
echo "::endgroup::"
|
||||
|
||||
# --- 4) fast-interval modules torn down mid-tick -------------------------
|
||||
echo "::group::fast-interval teardown race"
|
||||
cfg="$(mktemp --suffix=.json)"
|
||||
cat > "$cfg" <<'EOF'
|
||||
{
|
||||
"layer": "top", "position": "top", "height": 30,
|
||||
"modules-center": ["clock", "cpu", "memory", "custom/tick"],
|
||||
"clock": { "interval": 1 },
|
||||
"cpu": { "interval": 1 },
|
||||
"memory": { "interval": 1 },
|
||||
"custom/tick": { "exec": "date +%s", "interval": 1 }
|
||||
}
|
||||
EOF
|
||||
smoke::launch_waybar "$cfg" "$STYLE" 8
|
||||
smoke::assert_alive || fail=1
|
||||
smoke::assert_clean_exit || fail=1 # SIGINT while worker threads are mid-tick
|
||||
echo "::endgroup::"
|
||||
|
||||
[ "$fail" = 0 ] || { echo "::error::lifecycle tier failed"; exit 1; }
|
||||
echo "✓ lifecycle tier passed"
|
||||
Reference in New Issue
Block a user