#!/usr/bin/env bash set -euo pipefail cd "$(dirname "$0")/.." mode="${1:-all}" case "$mode" in all|l1|l2) ;; *) echo 'Usage: bash scripts/verify-webgl-display.sh [all|l1|l2]' >&2; exit 2 ;; esac if [[ "$mode" != l2 ]]; then ./mvnw -o test node --test src/test/js/webgl-player.test.cjs ./mvnw -o -DskipTests package echo 'L1 WebGL display: PASS (Java regression, Node player regression, WAR package)' fi [[ "$mode" != l1 ]] || exit 0 # No existing database, credentials, volume, or application container is used. image="${WEBGL_CONTRACT_POSTGRES_IMAGE:-postgres:16}" docker image inspect "$image" >/dev/null container="bibimbap-webgl-contract-$$-${RANDOM}" cleanup() { docker rm -f "$container" >/dev/null 2>&1 || true; } docker run --pull=never -d --name "$container" --label bibimbap.webgl-contract=true \ -e POSTGRES_HOST_AUTH_METHOD=trust -e POSTGRES_DB=webgl_contract \ -p 127.0.0.1::5432 "$image" >/dev/null trap cleanup EXIT ready=false for ((attempt=0; attempt<60; attempt++)); do if docker exec "$container" pg_isready -h 127.0.0.1 -U postgres -d webgl_contract >/dev/null 2>&1; then ready=true; break; fi sleep 1 done [[ "$ready" == true ]] || { echo 'Disposable PostgreSQL did not become ready' >&2; exit 1; } sql() { docker exec -i "$container" psql -X -v ON_ERROR_STOP=1 -U postgres -d "$1" "${@:2}"; } sql webgl_contract -q < db/schema.sql sql webgl_contract -q <<'SQL' SET search_path TO dev; ALTER TABLE games DROP COLUMN display_width, DROP COLUMN display_height, DROP COLUMN display_source; INSERT INTO users(id, display_name) VALUES (9000001, 'Legacy contract author'); INSERT INTO games(id,user_id,name) VALUES (9000001,9000001,'Legacy contract game'); SQL for repeat in 1 2; do { echo 'SET search_path TO dev;'; cat db/migrations/20261014-game-display-metadata.sql; } | sql webgl_contract -q done sql webgl_contract -q <<'SQL' SET search_path TO dev; DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM games WHERE id=9000001 AND name='Legacy contract game' AND display_width IS NULL AND display_height IS NULL AND display_source IS NULL) THEN RAISE EXCEPTION 'Migration changed existing row or metadata nullability'; END IF; UPDATE games SET display_width=800,display_height=800,display_source='build-info' WHERE id=9000001; BEGIN UPDATE games SET display_height=NULL WHERE id=9000001; RAISE EXCEPTION 'Partial pair unexpectedly accepted'; EXCEPTION WHEN check_violation THEN NULL; END; BEGIN UPDATE games SET display_width=0 WHERE id=9000001; RAISE EXCEPTION 'Zero width unexpectedly accepted'; EXCEPTION WHEN check_violation THEN NULL; END; BEGIN UPDATE games SET display_width=16385 WHERE id=9000001; RAISE EXCEPTION 'Oversize width unexpectedly accepted'; EXCEPTION WHEN check_violation THEN NULL; END; BEGIN UPDATE games SET display_width=1,display_height=100 WHERE id=9000001; RAISE EXCEPTION 'Extreme ratio unexpectedly accepted'; EXCEPTION WHEN check_violation THEN NULL; END; BEGIN UPDATE games SET display_source='unexpected' WHERE id=9000001; RAISE EXCEPTION 'Unknown source enum unexpectedly accepted'; EXCEPTION WHEN check_violation THEN NULL; END; UPDATE games SET display_width=NULL,display_height=NULL,display_source='unknown' WHERE id=9000001; END $$; CREATE DATABASE webgl_fresh; SQL sql webgl_fresh -q < db/schema.sql signature="SELECT 'column:'||column_name||':'||data_type||':'||is_nullable||':'||COALESCE(character_maximum_length::text,'') FROM information_schema.columns WHERE table_schema='dev' AND table_name='games' AND column_name LIKE 'display_%' UNION ALL SELECT 'constraint:'||conname||':'||pg_get_constraintdef(oid) FROM pg_constraint WHERE conrelid='dev.games'::regclass AND conname LIKE 'games_display_%' ORDER BY 1" migrated="$(sql webgl_contract -At -c "$signature")" fresh="$(sql webgl_fresh -At -c "$signature")" [[ "$migrated" == "$fresh" ]] || { echo 'Fresh/migrated display schema mismatch' >&2; exit 1; } port="$(docker port "$container" 5432/tcp)" port="${port##*:}" WEBGL_CONTRACT_JDBC_URL="jdbc:postgresql://127.0.0.1:${port}/webgl_contract?currentSchema=dev" \ ./mvnw -o -Dtest=WebglDisplayDatabaseContractTest test echo 'L2 WebGL display: PASS (legacy row, idempotency, checks, fresh equivalence, actual mapper roundtrip)'