|
| 1 | +#!/usr/bin/env bash |
| 2 | +# Smoke-test the example livebooks against the LOCAL emily checkout. |
| 3 | +# |
| 4 | +# For each notebook in notebooks/, this extracts its Elixir cells, |
| 5 | +# repoints the `{:emily, "~> x"}` Mix.install dependency at this repo (as |
| 6 | +# a `path:` dep, so the notebook exercises the working tree — including a |
| 7 | +# from-source NIF build), and runs the result headlessly with `elixir`. |
| 8 | +# A notebook passes if it runs to completion with exit code 0. |
| 9 | +# |
| 10 | +# Notes: |
| 11 | +# * First run downloads model checkpoints via Bumblebee (cached under |
| 12 | +# ~/Library/Caches/bumblebee afterwards) and compiles emily's NIF, so |
| 13 | +# it needs network + disk and can take several minutes per notebook. |
| 14 | +# * Cells render Kino widgets; outside Livebook those just evaluate to |
| 15 | +# structs. Notebooks are *run*, not interacted with — anything gated |
| 16 | +# behind a Kino form/input (e.g. recording audio in the Whisper |
| 17 | +# notebook) won't fire, but the surrounding setup/inference still does. |
| 18 | +# |
| 19 | +# Usage: |
| 20 | +# scripts/test-livebooks.sh # all notebooks |
| 21 | +# scripts/test-livebooks.sh distilbert_qa nomic_embeddings # a subset |
| 22 | +# |
| 23 | +# Env: |
| 24 | +# LIVEBOOK_TIMEOUT per-notebook timeout, seconds (default 1200) |
| 25 | +# LIVEBOOK_SKIP space-separated notebook names to skip |
| 26 | +# EMILY_CACHE MLX/NIF cache dir (passed through to the build) |
| 27 | + |
| 28 | +set -uo pipefail |
| 29 | + |
| 30 | +REPO="$(cd "$(dirname "$0")/.." && pwd)" |
| 31 | +NB_DIR="$REPO/notebooks" |
| 32 | +TIMEOUT="${LIVEBOOK_TIMEOUT:-1200}" |
| 33 | +SKIP=" ${LIVEBOOK_SKIP:-} " |
| 34 | + |
| 35 | +if ! command -v elixir >/dev/null 2>&1; then |
| 36 | + echo "error: elixir not on PATH" >&2 |
| 37 | + exit 2 |
| 38 | +fi |
| 39 | + |
| 40 | +# Selection: explicit notebook basenames, or every *.livemd. |
| 41 | +if [[ $# -gt 0 ]]; then |
| 42 | + names=("$@") |
| 43 | +else |
| 44 | + names=() |
| 45 | + for f in "$NB_DIR"/*.livemd; do names+=("$(basename "$f" .livemd)"); done |
| 46 | +fi |
| 47 | + |
| 48 | +# Print the contents of every ```elixir fenced block, blank-line separated. |
| 49 | +extract_cells() { |
| 50 | + awk ' |
| 51 | + /^```elixir[[:space:]]*$/ { inblock=1; next } |
| 52 | + /^```[[:space:]]*$/ { if (inblock) { inblock=0; print "" }; next } |
| 53 | + inblock { print } |
| 54 | + ' "$1" |
| 55 | +} |
| 56 | + |
| 57 | +pass=() |
| 58 | +fail=() |
| 59 | +skip=() |
| 60 | +log_dir="$(mktemp -d "${TMPDIR:-/tmp}/emily-livebooks.XXXXXX")" |
| 61 | +echo "emily: $REPO (path dep)" |
| 62 | +echo "logs: $log_dir" |
| 63 | +echo |
| 64 | + |
| 65 | +for name in "${names[@]}"; do |
| 66 | + nb="$NB_DIR/$name.livemd" |
| 67 | + if [[ ! -f "$nb" ]]; then |
| 68 | + echo ">> $name: NOT FOUND" |
| 69 | + fail+=("$name") |
| 70 | + continue |
| 71 | + fi |
| 72 | + if [[ "$SKIP" == *" $name "* ]]; then |
| 73 | + echo ">> $name: SKIP" |
| 74 | + skip+=("$name") |
| 75 | + continue |
| 76 | + fi |
| 77 | + |
| 78 | + script="$log_dir/$name.exs" |
| 79 | + out="$log_dir/$name.out" |
| 80 | + # Extract the cells and repoint the emily dependency at this checkout. |
| 81 | + extract_cells "$nb" \ |
| 82 | + | sed "s|{:emily,[^}]*}|{:emily, path: \"$REPO\"}|" \ |
| 83 | + > "$script" |
| 84 | + |
| 85 | + printf ">> %-28s running (timeout %ss) ... " "$name" "$TIMEOUT" |
| 86 | + start=$SECONDS |
| 87 | + if timeout "$TIMEOUT" elixir "$script" >"$out" 2>&1; then |
| 88 | + echo "PASS ($((SECONDS - start))s)" |
| 89 | + pass+=("$name") |
| 90 | + else |
| 91 | + code=$? |
| 92 | + echo "FAIL (exit $code, $((SECONDS - start))s)" |
| 93 | + tail -n 25 "$out" | sed 's/^/ | /' |
| 94 | + fail+=("$name") |
| 95 | + fi |
| 96 | +done |
| 97 | + |
| 98 | +echo |
| 99 | +echo "==================== livebook results ====================" |
| 100 | +printf "PASS (%d): %s\n" "${#pass[@]}" "${pass[*]:-}" |
| 101 | +printf "FAIL (%d): %s\n" "${#fail[@]}" "${fail[*]:-}" |
| 102 | +printf "SKIP (%d): %s\n" "${#skip[@]}" "${skip[*]:-}" |
| 103 | +echo "logs in $log_dir" |
| 104 | + |
| 105 | +[[ ${#fail[@]} -eq 0 ]] |
0 commit comments