Make `testium lsp` (and the testium_assist editor extension that spawns it)
work from every distribution channel: source, wheel, PyInstaller, Flatpak,
AppImage.
Two enablers:
1. Declarative ACTIONS registry. The TestItemActions parents (console, plot,
json_rpc) now declare their nested actions as a class attribute
`ACTIONS = {yaml_key: class}`, mirroring PARAMS. The base __init__ seeds
action_classes from type(self).ACTIONS; register_actions() is kept only as
an imperative escape hatch. lsp/schema.py reads ACTIONS directly, dropping
the inspect.getsource/AST walk that returned no actions in a frozen
PyInstaller build (no .py source on disk).
2. pygls bundled per channel. Kept as the pyproject [lsp] extra (lean
`pip install testium`), layered into each full-app channel:
- build_env.sh installs pygls into test/tmp/.venv (source run + PyInstaller
build env)
- AppImage installs the wheel as `…whl[lsp]`
- Flatpak adds a python3-lsp network-pip module (matches the manifest's
global --share=network)
- PyInstaller .spec collect_submodules(pygls/lsprotocol) + hiddenimports for
the lazily-imported lsp/lsp.server/lsp.schema
test/validation/lsp_smoke.py (run by run.sh before the suite) enforces both
per channel: `<channel> schema` must keep console/plot/json_rpc actions and
`<channel> lsp` must answer an initialize request without reporting pygls
missing. Verified for source mode; the other channels need a rebuild to verify.
DESIGN.md updated (declarative section + new "Language server across channels"
subsection + Recent fixes).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
151 lines
5.1 KiB
Bash
Executable File
151 lines
5.1 KiB
Bash
Executable File
#!/bin/bash
|
|
# Runs the testium validation suite against any installable channel of
|
|
# testium (source, wheel, pyinstaller, flatpak, appimage).
|
|
#
|
|
# Usage:
|
|
# ./test/validation/run.sh [clean] [--mode MODE] [extra testium args]
|
|
#
|
|
# clean remove the validation venv before recreating it
|
|
# (must be the first argument; useful after a Python upgrade)
|
|
#
|
|
# --mode MODE which testium build to validate. One of:
|
|
# source (default) src/testium via project run.sh
|
|
# wheel dist/testium-<v>-py3-none-any.whl
|
|
# pyinstaller dist/testium-<v>
|
|
# flatpak installed org.testium.Testium
|
|
# appimage dist/Testium-<v>-*.AppImage
|
|
#
|
|
# Every test-execution subprocess (inline <| ... |>, py_func, cycle,
|
|
# post_execution, ...) runs in a dedicated host venv under
|
|
# /tmp/testium-validation-venv. That venv is shared across modes —
|
|
# even Flatpak reaches it via flatpak-spawn --host. The validation venv
|
|
# is created with --system-site-packages so existing system packages
|
|
# (PySide6, lxml, ...) stay visible, then junit-xml is pip-installed
|
|
# for post_execution.py.
|
|
#
|
|
# The report file is suffixed with the mode (e.g. validation-flatpak.sqlite)
|
|
# so consecutive runs in different modes don't overwrite each other.
|
|
|
|
set -e
|
|
|
|
SCRIPT_PATH="$(readlink -f "$0")"
|
|
SCRIPT_DIR="$(realpath "$(dirname "$SCRIPT_PATH")")"
|
|
PROJECT_DIR="$(realpath "$SCRIPT_DIR/../..")"
|
|
VERSION="$(cat "$PROJECT_DIR/src/VERSION")"
|
|
|
|
# ---------- arg parsing -------------------------------------------------------
|
|
|
|
MODE=source
|
|
|
|
if [ "${1:-}" = "clean" ]; then
|
|
CLEAN=1
|
|
shift
|
|
else
|
|
CLEAN=0
|
|
fi
|
|
|
|
EXTRA=()
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--mode)
|
|
MODE="$2"
|
|
shift 2
|
|
;;
|
|
--mode=*)
|
|
MODE="${1#--mode=}"
|
|
shift
|
|
;;
|
|
*)
|
|
EXTRA+=("$1")
|
|
shift
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# ---------- validation venv ---------------------------------------------------
|
|
|
|
VENV_DIR="${TMPDIR:-/tmp}/testium-validation-venv"
|
|
if [ "$CLEAN" -eq 1 ]; then
|
|
rm -rf "$VENV_DIR"
|
|
fi
|
|
|
|
if [ ! -d "$VENV_DIR" ]; then
|
|
echo "Creating validation venv at $VENV_DIR"
|
|
python3 -m venv --system-site-packages "$VENV_DIR"
|
|
"$VENV_DIR/bin/pip" install --quiet --upgrade pip
|
|
"$VENV_DIR/bin/pip" install --quiet junit-xml
|
|
fi
|
|
VENV_PYTHON="$VENV_DIR/bin/python3"
|
|
|
|
# ---------- per-mode launcher -------------------------------------------------
|
|
|
|
case "$MODE" in
|
|
source)
|
|
CMD=("$PROJECT_DIR/run.sh")
|
|
;;
|
|
wheel)
|
|
WHEEL="$PROJECT_DIR/dist/testium-${VERSION}-py3-none-any.whl"
|
|
if [ ! -f "$WHEEL" ]; then
|
|
echo "ERROR: wheel not found at $WHEEL — run ./build_all.sh first." >&2
|
|
exit 1
|
|
fi
|
|
WHEEL_VENV="${TMPDIR:-/tmp}/testium-wheel-venv-${VERSION}"
|
|
if [ "$CLEAN" -eq 1 ]; then
|
|
rm -rf "$WHEEL_VENV"
|
|
fi
|
|
if [ ! -d "$WHEEL_VENV" ]; then
|
|
echo "Creating wheel venv at $WHEEL_VENV"
|
|
python3 -m venv --system-site-packages "$WHEEL_VENV"
|
|
"$WHEEL_VENV/bin/pip" install --quiet --upgrade pip
|
|
"$WHEEL_VENV/bin/pip" install --quiet "$WHEEL"
|
|
fi
|
|
CMD=("$WHEEL_VENV/bin/python" -m testium)
|
|
;;
|
|
pyinstaller)
|
|
PYI_BIN="$PROJECT_DIR/dist/testium-${VERSION}"
|
|
if [ ! -x "$PYI_BIN" ]; then
|
|
echo "ERROR: PyInstaller binary not found at $PYI_BIN — run ./build_all.sh first." >&2
|
|
exit 1
|
|
fi
|
|
CMD=("$PYI_BIN")
|
|
;;
|
|
flatpak)
|
|
if ! flatpak info --user org.testium.Testium &>/dev/null \
|
|
&& ! flatpak info --system org.testium.Testium &>/dev/null; then
|
|
echo "ERROR: org.testium.Testium is not installed." >&2
|
|
echo " flatpak install --user $PROJECT_DIR/dist/testium-${VERSION}.flatpak" >&2
|
|
exit 1
|
|
fi
|
|
CMD=(flatpak run --command=testium org.testium.Testium)
|
|
;;
|
|
appimage)
|
|
APPIMAGE=$(ls -1t "$PROJECT_DIR/dist"/Testium-"${VERSION}"-*.AppImage 2>/dev/null | head -1)
|
|
if [ -z "$APPIMAGE" ] || [ ! -x "$APPIMAGE" ]; then
|
|
echo "ERROR: no AppImage for version $VERSION under $PROJECT_DIR/dist — run ./build_all.sh first." >&2
|
|
exit 1
|
|
fi
|
|
CMD=("$APPIMAGE")
|
|
;;
|
|
*)
|
|
echo "ERROR: unknown --mode '$MODE'. Expected: source|wheel|pyinstaller|flatpak|appimage." >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
# ---------- launch ------------------------------------------------------------
|
|
|
|
echo "-- validation mode: $MODE"
|
|
echo "-- launch: ${CMD[*]}"
|
|
|
|
# ---------- LSP smoke check (this exact channel) ------------------------------
|
|
# Verify `testium lsp` / `testium schema` work in the build under test before
|
|
# running the suite: schema must keep its nested actions (declarative ACTIONS,
|
|
# survives frozen builds) and the language server must start (pygls bundled).
|
|
echo "-- LSP smoke check ($MODE)"
|
|
"$VENV_PYTHON" "$SCRIPT_DIR/lsp_smoke.py" "${CMD[@]}"
|
|
|
|
exec "${CMD[@]}" -b \
|
|
-d "python_bin=$VENV_PYTHON" \
|
|
-d "validation_report_file=validation-$MODE" \
|
|
-- "$SCRIPT_DIR/main.tum" "${EXTRA[@]}"
|