#!/usr/bin/env bash # Load the viewer page in headless Chromium and check what it renders. # # browser.sh FIXTURE_DIR # # FIXTURE_DIR holds fixture.h5 from make_fixture.py; ../pkg must be built. # The page is opened with ?file=fixture.h5&path=, which fetches the # file, builds the tree down to and shows it; the rendered DOM is # dumped and checked for the values libhdf5 reads. # # Browser: $CHROME, else chromium/google-chrome on PATH, else a Playwright # download under ~/.cache/ms-playwright. Exit 3 when none is found. # BROWSER_DEBUG=/some/prefix saves each rendered page as prefix..html. set -euo pipefail HERE="$(cd "$(dirname "$0")" && pwd)" FIX="$(cd "$1" && pwd)" PY="${CLAWHDF5_PYTHON:-python3}" chrome="${CHROME:-}" if [ -z "$chrome" ]; then for c in chromium chromium-browser google-chrome chrome-headless-shell; do if command -v "$c" >/dev/null; then chrome="$(command -v "$c")"; break; fi done fi if [ -z "$chrome" ]; then chrome="$(ls -d "$HOME"/.cache/ms-playwright/chromium_headless_shell-*/chrome-headless-shell-linux64/chrome-headless-shell 2>/dev/null | tail -1 || true)" fi if [ -z "$chrome" ] || [ ! -x "$chrome" ]; then echo "no Chromium found (set CHROME)" >&2 exit 3 fi root="$(mktemp -d)" server="" cleanup() { [ -n "$server" ] && kill "$server" 2>/dev/null || true rm -rf "$root" } trap cleanup EXIT ln -s "$HERE/../index.html" "$HERE/../viewer-lib.js" "$HERE/../pkg" "$FIX/fixture.h5" "$root/" port=$("$PY" -c 'import socket; s = socket.socket(); s.bind(("127.0.0.1", 0)); print(s.getsockname()[1])') "$PY" -m http.server --bind 127.0.0.1 --directory "$root" "$port" >/dev/null 2>&1 & server=$! for _ in $(seq 50); do "$PY" -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:$port/index.html')" 2>/dev/null && break sleep 0.1 done fails=0 # A fresh profile per page: a second instance on the same profile fails. render() { local profile profile="$(mktemp -d "$root/profile.XXXXXX")" "$chrome" --headless --no-sandbox --disable-gpu --user-data-dir="$profile" \ --virtual-time-budget=20000 \ --dump-dom "http://127.0.0.1:$port/index.html?file=fixture.h5&path=$1" 2>/dev/null } # expect PATH TEXT...: every TEXT appears in the page rendered for PATH. expect() { local path="$1" dom shift dom="$(render "$path")" [ -n "${BROWSER_DEBUG:-}" ] && printf "%s\n" "$dom" > "$BROWSER_DEBUG.$(echo "$path" | tr / _).html" for text in "$@"; do if ! grep -qF -- "$text" <<<"$dom"; then echo "FAIL: page for $path lacks: $text" >&2 fails=$((fails + 1)) fi done echo "rendered $path" } # Tree (root expanded; the group row carries its path) and root attributes. expect "/" 'data-path="/sensors"' 'data-path="/grid"' 'title"wasm fixture"' \ 'big9223372036854775813' '(compound{x: f64, n: i32})' # A chunked, deflated 2-D dataset: type, shape, the first window of values. expect "/grid" '
f64
' '
(6, 10)
' '9' '0.25' '14.75' \ 'showing rows 0–5, columns 0–9 of 60 values' # Nested path revealed through the tree; big-endian float32. expect "/sensors/temp" 'data-path="/sensors/temp"' '
f32
' '21.5' '22.25' # 64-bit integers stay exact; strings; array datatype cells. expect "/u64" '18446744073709551615' expect "/vlen_str" '"двa"' '
vlen string
' expect "/pairs" '[2, 3]' '
array[2]<i32>
' # 3-D: leading dimension held at 0, window over the last two. expect "/cube" '
(2, 5, 6)
' '29' 'dim 0' # Unsupported type: an error, not values. expect "/table" 'class="error"' 'reading compound{x: f64, n: i32} datasets is not supported' if [ "$fails" -gt 0 ]; then echo "browser: $fails checks failed" >&2 exit 1 fi echo "browser: all checks passed ($chrome)"