qmd/test/smoke-install.sh
Tobi Lutke c7e8ea02a5
test: restructure container smoke tests for interactive use
Replaces the inner test script with an outer driver that runs individual
podman/docker commands against a pre-built image. Tests sqlite-vec
loading and store unit tests under both node and bun runtimes.

Supports --build (image only), --shell (interactive), and -- CMD
(arbitrary command) for debugging install issues in isolation.
2026-02-22 11:09:36 -04:00

170 lines
4.7 KiB
Bash
Executable File

#!/usr/bin/env bash
# Build a container image with qmd installed via npm and bun, then run smoke tests.
# Works with docker or podman (whichever is available).
#
# Usage:
# test/smoke-install.sh # build + run all smoke tests
# test/smoke-install.sh --build # build image only
# test/smoke-install.sh --shell # drop into container shell
# test/smoke-install.sh -- CMD... # run arbitrary command in container
set -euo pipefail
cd "$(dirname "$0")/.."
# Pick container runtime
if command -v podman &>/dev/null; then
CTR=podman
elif command -v docker &>/dev/null; then
CTR=docker
else
echo "Error: neither podman nor docker found" >&2
exit 1
fi
IMAGE=qmd-smoke
build_image() {
echo "==> Building TypeScript..."
npm run build --silent
echo "==> Packing tarball..."
rm -f test/tobilu-qmd-*.tgz
TARBALL=$(npm pack --pack-destination test/ 2>/dev/null | tail -1)
echo " $TARBALL"
# Copy project files into build context so vitest/bun tests can run inside
rm -rf test/test-src
mkdir -p test/test-src/src test/test-src/test
cp src/*.ts test/test-src/src/
cp -r dist test/test-src/
cp test/*.test.ts test/test-src/test/
cp package.json tsconfig.json tsconfig.build.json test/test-src/
echo "==> Building container image ($CTR)..."
$CTR build -f test/Containerfile -t "$IMAGE" test/
# Clean up
rm -f test/tobilu-qmd-*.tgz
rm -rf test/test-src
echo "==> Image ready: $IMAGE"
}
run() {
$CTR run --rm "$IMAGE" bash -c "$*"
}
PASS=0
FAIL=0
ok() { printf " %-50s OK\n" "$1"; PASS=$((PASS + 1)); }
fail() { printf " %-50s FAIL\n" "$1"; FAIL=$((FAIL + 1)); echo "$2" | sed 's/^/ /'; }
smoke_test() {
local label="$1"; shift
local out
if out=$(run "$@" 2>&1); then
ok "$label"
else
fail "$label" "$out"
fi
}
smoke_test_output() {
local label="$1"; local expect="$2"; shift 2
local out
out=$(run "$@" 2>&1) || true
if echo "$out" | grep -q "$expect"; then
ok "$label"
else
fail "$label" "$out"
fi
}
run_smoke_tests() {
# ------------------------------------------------------------------
# Node (npm-installed qmd)
# ------------------------------------------------------------------
local NODE_BIN='$(mise where node@latest)/bin'
echo "=== Node (npm install) ==="
smoke_test_output "qmd shows help" "Usage:" \
"export PATH=$NODE_BIN:\$PATH; qmd"
smoke_test "qmd collection list" \
"export PATH=$NODE_BIN:\$PATH; qmd collection list"
smoke_test "qmd status" \
"export PATH=$NODE_BIN:\$PATH; qmd status"
smoke_test "sqlite-vec loads" \
"export PATH=$NODE_BIN:\$PATH;
NPM_GLOBAL=\$(npm root -g);
node -e \"
const {openDatabase, loadSqliteVec} = await import('\$NPM_GLOBAL/@tobilu/qmd/dist/db.js');
const db = openDatabase(':memory:');
loadSqliteVec(db);
const r = db.prepare('SELECT vec_version() as v').get();
console.log('sqlite-vec', r.v);
if (!r.v) process.exit(1);
\""
smoke_test "vitest (node)" \
"export PATH=$NODE_BIN:\$PATH; cd /opt/qmd && npx vitest run --reporter=verbose test/store.test.ts 2>&1 | tail -5"
# ------------------------------------------------------------------
# Bun (bun-installed qmd)
# ------------------------------------------------------------------
local BUN_BIN='$(mise where bun@latest)/bin'
echo ""
echo "=== Bun (bun install) ==="
smoke_test_output "qmd shows help" "Usage:" \
"export PATH=$BUN_BIN:$NODE_BIN:\$PATH; \$HOME/.bun/bin/qmd"
smoke_test "qmd collection list" \
"export PATH=$BUN_BIN:$NODE_BIN:\$PATH; \$HOME/.bun/bin/qmd collection list"
smoke_test "qmd status" \
"export PATH=$BUN_BIN:$NODE_BIN:\$PATH; \$HOME/.bun/bin/qmd status"
smoke_test "sqlite-vec loads (bun)" \
"export PATH=$BUN_BIN:\$PATH; bun -e \"
const {openDatabase, loadSqliteVec} = await import('\$HOME/.bun/install/global/node_modules/@tobilu/qmd/dist/db.js');
const db = openDatabase(':memory:');
loadSqliteVec(db);
const r = db.prepare('SELECT vec_version() as v').get();
console.log('sqlite-vec', r.v);
if (!r.v) process.exit(1);
\""
smoke_test "bun test store" \
"export PATH=$BUN_BIN:\$PATH; cd /opt/qmd && bun test --preload ./src/test-preload.ts --timeout 30000 test/store.test.ts 2>&1 | tail -10"
# ------------------------------------------------------------------
echo ""
echo "=== Results: $PASS passed, $FAIL failed ==="
[[ $FAIL -eq 0 ]]
}
# Parse arguments
case "${1:-}" in
--build)
build_image
;;
--shell)
build_image
echo "==> Dropping into container shell..."
$CTR run --rm -it "$IMAGE" bash
;;
--)
shift
run "$@"
;;
*)
build_image
echo ""
echo "==> Running smoke tests..."
run_smoke_tests
;;
esac