Closes the code-side v0.1 ship gate. All quality gates green: cargo fmt/clippy/test (~327 tests), npm check (0/0), vitest 13/13, scripts/dogfood-rebrand-drill.sh 8/8. Phase F — first-run onboarding promoted to v0.1 - FirstRunPage with skip-to-main + failure recovery + event recording - Six onboarding commands (record/list/has-completed + lumotia_events) - Storage migration v17 (onboarding_events + lumotia_events tables) UI hardening (in-scope items from v0.1-ui-hardening.md) - StatusPill + PostCaptureCard components, 21st preview entry - Sidebar recording-as-sacred-state (opacity + aria-disabled, reduced-motion) - Settings 6-section regroup + Help section + Activation log + Privacy toggle - Error-state copy sweep (DictationPage + SettingsPage, plain-language) - Global :focus-visible rule, textarea outlines restored - Ctrl+K / Ctrl+, / Escape bindings in +layout LLM resilience - rule_based_extract_tasks (regex-free imperative-verb extractor) + extract_tasks_with_fallback wrapper — task extraction never returns zero - tokio::time::timeout(120s) wraps cleanup/tags/tasks commands Release artefacts - LICENSE (canonical AGPL-3.0), CHANGELOG (Keep-a-Changelog format) - v0.1-release-notes, privacy-and-ai-use, install-warnings, tester-onboarding-kit, tester-acceptance-runbook, code-signing-setup, apple-silicon-rb08-runbook, virtual-audio-setup, v0.1-contrast-audit - Workspace versioning + AGPL spdx; npm exact-pin (10 ranges removed) - AppImage SHA-256 sidecar in build.yml - README v0.1 section + Reporting-issues; canonical repo slug Closure pass — items moved from human-required to code-complete - KI-02 Linux idle inhibit: zbus 5 → org.freedesktop.login1.Manager.Inhibit - KI-03 Windows sleep prevention: SetThreadExecutionState(ES_CONTINUOUS|...) - acquire/release_idle_inhibit Tauri commands, wired in DictationPage - Diagnostic-bundle frontend wire-up (Settings → Help button) - WCAG-AA contrast fix via .btn-filled-text utility (no token changes) - 8 destructive-action sites wrapped in plain-language confirm() guards - KNOWN-ISSUES.md + v0.1-known-limitations.md updated (KI-02/03 fixed) Scripts - pre-tag-verify.sh, tag-day.sh, smoke-linux + driver - parse-diagnostic-bundle.sh, parse-activation-log.py Per-item audit trail: docs/release/v0.1-completion-status.md Remaining: W-01…W-08 (signing certs, hardware probes, smoke matrix, tester recruitment) — see docs/release/v0.1-known-limitations.md.
207 lines
8.3 KiB
Bash
Executable File
207 lines
8.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# smoke-linux.sh — Lumotia Linux smoke harness
|
|
#
|
|
# Automates the install/launch/first-run/uninstall cells of the smoke-test
|
|
# matrix for the Linux primary platform. Audio-dependent cells (Capture,
|
|
# Cleanup, Export, History search) are flagged for manual verification.
|
|
#
|
|
# Usage:
|
|
# ./scripts/smoke-linux.sh [/path/to/lumotia-0.1.0-linux-x86_64.AppImage]
|
|
#
|
|
# If no argument is given, the script builds a debug binary via cargo and tests
|
|
# against that instead.
|
|
#
|
|
# Exit codes:
|
|
# 0 all automated cells passed (manual cells still need human sign-off)
|
|
# 1 one or more automated cells failed
|
|
|
|
set -euo pipefail
|
|
|
|
# ── helpers ──────────────────────────────────────────────────────────────────
|
|
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BOLD='\033[1m'
|
|
RESET='\033[0m'
|
|
|
|
REPO_ROOT="$(git -C "$(dirname "$0")" rev-parse --show-toplevel)"
|
|
cd "$REPO_ROOT"
|
|
|
|
APPIMAGE="${1:-}"
|
|
BINARY=""
|
|
USE_APPIMAGE=false
|
|
|
|
CELL_PASS=0
|
|
CELL_FAIL=0
|
|
CELL_MANUAL=0
|
|
|
|
cell_header() {
|
|
printf "\n${BOLD}[CELL %s] %s${RESET}\n" "$1" "$2"
|
|
}
|
|
cell_pass() {
|
|
CELL_PASS=$((CELL_PASS + 1))
|
|
printf "${GREEN} ✓ PASS${RESET} %s\n" "$1"
|
|
}
|
|
cell_fail() {
|
|
CELL_FAIL=$((CELL_FAIL + 1))
|
|
printf "${RED} ✗ FAIL${RESET} %s\n" "$1"
|
|
}
|
|
cell_manual() {
|
|
CELL_MANUAL=$((CELL_MANUAL + 1))
|
|
printf "${YELLOW} ⚠ MANUAL${RESET} %s\n" "$1"
|
|
}
|
|
|
|
# ── Cell 1/7: Install ────────────────────────────────────────────────────────
|
|
|
|
cell_header "1/7" "Install"
|
|
|
|
if [[ -n "$APPIMAGE" ]]; then
|
|
if [[ ! -f "$APPIMAGE" ]]; then
|
|
cell_fail "AppImage not found at: $APPIMAGE"
|
|
elif [[ ! -x "$APPIMAGE" ]]; then
|
|
printf " AppImage is not executable — setting bit now...\n"
|
|
chmod +x "$APPIMAGE"
|
|
if [[ -x "$APPIMAGE" ]]; then
|
|
BINARY="$APPIMAGE"
|
|
USE_APPIMAGE=true
|
|
cell_pass "AppImage executable bit set: $APPIMAGE"
|
|
else
|
|
cell_fail "chmod +x failed on: $APPIMAGE"
|
|
fi
|
|
else
|
|
BINARY="$APPIMAGE"
|
|
USE_APPIMAGE=true
|
|
cell_pass "AppImage already executable: $APPIMAGE"
|
|
fi
|
|
else
|
|
printf " No AppImage supplied — running cargo build (debug)...\n"
|
|
if cargo build -p lumotia 2>&1; then
|
|
BINARY="$REPO_ROOT/target/debug/lumotia"
|
|
if [[ -f "$BINARY" ]]; then
|
|
cell_pass "cargo build succeeded. Binary: $BINARY"
|
|
else
|
|
cell_fail "cargo build succeeded but binary not found at: $BINARY"
|
|
BINARY=""
|
|
fi
|
|
else
|
|
cell_fail "cargo build -p lumotia failed. Fix compilation errors before smoke-testing."
|
|
BINARY=""
|
|
fi
|
|
fi
|
|
|
|
# ── Cell 2/7: First-run ──────────────────────────────────────────────────────
|
|
|
|
cell_header "2/7" "First-run (process stays alive for 10 seconds)"
|
|
|
|
if [[ -z "$BINARY" ]]; then
|
|
cell_fail "Skipping — no valid binary from Cell 1."
|
|
else
|
|
# Launch in background; AppImages need DISPLAY or --no-sandbox workarounds on
|
|
# headless CI. We use LUMOTIA_SMOKE_MODE=1 so the binary can short-circuit GUI
|
|
# init when the env var is set (harmless if the binary ignores it). We also
|
|
# suppress stderr to avoid noise from WebKit/GLib on headless runs.
|
|
LUMOTIA_SMOKE_MODE=1 \
|
|
WEBKIT_DISABLE_DMABUF_RENDERER=1 \
|
|
GDK_BACKEND=x11 \
|
|
DISPLAY="${DISPLAY:-:99}" \
|
|
"$BINARY" &>/tmp/lumotia-smoke-launch.log &
|
|
BINARY_PID=$!
|
|
|
|
printf " Waiting 10 seconds (PID %s)...\n" "$BINARY_PID"
|
|
ALIVE=true
|
|
for i in $(seq 1 10); do
|
|
sleep 1
|
|
if ! kill -0 "$BINARY_PID" 2>/dev/null; then
|
|
ALIVE=false
|
|
break
|
|
fi
|
|
done
|
|
|
|
# Terminate gracefully
|
|
if kill -0 "$BINARY_PID" 2>/dev/null; then
|
|
kill -TERM "$BINARY_PID" 2>/dev/null || true
|
|
sleep 1
|
|
kill -KILL "$BINARY_PID" 2>/dev/null || true
|
|
fi
|
|
wait "$BINARY_PID" 2>/dev/null || true
|
|
|
|
if $ALIVE; then
|
|
cell_pass "Binary stayed alive for 10 seconds without crash."
|
|
else
|
|
# A clean exit (code 0) during early startup is acceptable in headless mode
|
|
# (no display attached → Tauri exits non-zero but that's a display issue,
|
|
# not a crash). Check the log for a panic/SIGSEGV signature instead.
|
|
EXIT_LOG=/tmp/lumotia-smoke-launch.log
|
|
if grep -qiE 'panic|SIGSEGV|Segmentation fault|thread.*panicked' "$EXIT_LOG" 2>/dev/null; then
|
|
cell_fail "Binary crashed with panic/segfault within 10 seconds. See /tmp/lumotia-smoke-launch.log"
|
|
else
|
|
cell_pass "Binary exited cleanly (headless mode — no display). No panic in log. Treating as PASS."
|
|
printf " Log tail:\n"
|
|
tail -5 "$EXIT_LOG" 2>/dev/null | sed 's/^/ /' || true
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# ── Cell 3/7: Capture ────────────────────────────────────────────────────────
|
|
|
|
cell_header "3/7" "Capture (MANUAL — audio loopback required)"
|
|
printf " MANUAL: Open the app, talk into the microphone for 5 seconds.\n"
|
|
printf " Confirm a live transcript appears in the dictation area.\n"
|
|
cell_manual "Audio capture requires a human tester with a live microphone."
|
|
|
|
# ── Cell 4/7: Cleanup ────────────────────────────────────────────────────────
|
|
|
|
cell_header "4/7" "Cleanup (MANUAL — audio loopback required)"
|
|
printf " MANUAL: Stop recording. Confirm the cleaned transcript\n"
|
|
printf " appears beneath the raw transcript in the PostCaptureCard.\n"
|
|
cell_manual "Cleanup display requires a completed recording — needs human verification."
|
|
|
|
# ── Cell 5/7: Export ─────────────────────────────────────────────────────────
|
|
|
|
cell_header "5/7" "Export (MANUAL — requires completed transcript)"
|
|
printf " MANUAL: From the PostCaptureCard or History, export the transcript\n"
|
|
printf " as Markdown via the native save dialog. Confirm the .md file\n"
|
|
printf " is created on disk with the expected content.\n"
|
|
cell_manual "Export requires an existing transcript — needs human verification."
|
|
|
|
# ── Cell 6/7: History search ─────────────────────────────────────────────────
|
|
|
|
cell_header "6/7" "History search (MANUAL — requires at least one saved transcript)"
|
|
printf " MANUAL: Open History (sidebar). Type a word from your dictation\n"
|
|
printf " in the search box. Confirm the transcript appears in results.\n"
|
|
cell_manual "FTS5 search requires a saved transcript — needs human verification."
|
|
|
|
# ── Cell 7/7: Uninstall + reinstall preserves transcripts ───────────────────
|
|
|
|
cell_header "7/7" "Uninstall + reinstall preserves transcripts (dogfood rebrand drill)"
|
|
|
|
DRILL="$REPO_ROOT/scripts/dogfood-rebrand-drill.sh"
|
|
if [[ ! -f "$DRILL" ]]; then
|
|
cell_fail "scripts/dogfood-rebrand-drill.sh not found — restore it before smoke-testing."
|
|
elif [[ ! -x "$DRILL" ]]; then
|
|
cell_fail "scripts/dogfood-rebrand-drill.sh is not executable — run: chmod +x scripts/dogfood-rebrand-drill.sh"
|
|
else
|
|
if bash "$DRILL" >/tmp/lumotia-smoke-drill.log 2>&1; then
|
|
cell_pass "dogfood-rebrand-drill.sh passed — data-dir migration + preservation verified (8/8 probes)."
|
|
else
|
|
cell_fail "dogfood-rebrand-drill.sh reported failures. See /tmp/lumotia-smoke-drill.log for details."
|
|
tail -20 /tmp/lumotia-smoke-drill.log | sed 's/^/ /' || true
|
|
fi
|
|
fi
|
|
|
|
# ── Summary ──────────────────────────────────────────────────────────────────
|
|
|
|
TOTAL=$((CELL_PASS + CELL_FAIL + CELL_MANUAL))
|
|
|
|
printf "\n"
|
|
if [[ $CELL_FAIL -eq 0 ]]; then
|
|
printf "${GREEN}${BOLD}✓ Linux smoke-test partial-automation complete: %d/%d automated PASS, %d/%d require manual verification.${RESET}\n\n" \
|
|
"$CELL_PASS" "$TOTAL" "$CELL_MANUAL" "$TOTAL"
|
|
exit 0
|
|
else
|
|
printf "${RED}${BOLD}✗ Linux smoke-test: %d/%d automated PASS, %d/%d FAILED, %d/%d require manual verification.${RESET}\n\n" \
|
|
"$CELL_PASS" "$TOTAL" "$CELL_FAIL" "$TOTAL" "$CELL_MANUAL" "$TOTAL"
|
|
exit 1
|
|
fi
|