DVX_GUI/server/test/run.sh
2026-11-01 19:45:47 -06:00

156 lines
6.6 KiB
Bash
Executable file

#!/bin/bash
# The MIT License (MIT)
#
# Copyright (C) 2026 Scott Duensing
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
# run.sh -- the DVX package server's tests, as singemaster's are run: fixtures made, the server
# started on a port of its own with a configuration of its own, the suites run against it, the
# server stopped. Then both services in one calog process, each answering on its own port.
#
# server/test/run.sh (from anywhere; needs bin/host/dvxpkg from a DVX build, calog, and singemaster)
#
# calog and singemaster are beside this repository (../../calog and ../../singemaster from the
# server folder) unless CALOG_HOME and SINGE_HOME say where they are; CALOG is the calog program
# (CALOG_HOME/bin/calog unless it is set).
#
# CALOG_HOME=/opt/calog SINGE_HOME=/opt/singemaster server/test/run.sh
#
# Exit status 0 when every suite passed.
set -u
cd "$(dirname "$0")/.." || exit 1
CALOG_HOME=${CALOG_HOME:-$(cd ../../calog 2>/dev/null && pwd)}
CALOG=${CALOG:-$CALOG_HOME/bin/calog}
SINGE=${SINGE_HOME:-$(cd ../../singemaster 2>/dev/null && pwd)}
DVXPKG=$(cd .. && pwd)/bin/host/dvxpkg
PORT=18101
MASTER_PORT=18102
ADMIN=testoperatortoken0123456789abcdef
DATA=$(pwd)/test/data
# calog's library (its examples' web and mail servers) and singemaster's shared modules, and the
# programs the run needs: said at once when they are not where they are looked for
if [ -z "$CALOG_HOME" ] || [ ! -f "$CALOG_HOME/examples/httpd.lua" ]; then
echo "calog is not beside this repository (set CALOG_HOME)"; exit 1
fi
[ -x "$CALOG" ] || { echo "calog is not at $CALOG (set CALOG)"; exit 1; }
if [ -z "$SINGE" ] || [ ! -f "$SINGE/lib/service.lua" ]; then
echo "singemaster is not beside this repository (set SINGE_HOME)"; exit 1
fi
[ -x "$DVXPKG" ] || { echo "the package tool is not at $DVXPKG (build DVX first)"; exit 1; }
rm -rf "$DATA" && mkdir -p "$DATA/stage"
# The repository's key pair (its secret stays here, as on the operator's computer) and a publisher's
"$DVXPKG" keygen "DVX Test Repository" "$DATA/REPO" > /dev/null
"$DVXPKG" keygen "Acme Test" "$DATA/ACME" > /dev/null
# package <name> <template text> <file in the package> [key]: a .DPK in $DATA
package() {
local stage="$DATA/stage/$1"
mkdir -p "$(dirname "$stage/$3")"
printf 'contents of %s\n' "$3" > "$stage/$3"
printf '%b' "$2" > "$DATA/$1.ini"
"$DVXPKG" build "$DATA/$1.ini" "$stage" "$DATA/$1.dpk" ${4:+"$4"} > /dev/null || echo "fixture $1 failed"
}
package cards '[package]\nid = acme.cards\nname = Cards\nversion = 1.0.0\nkind = library\nsummary = Card games; for everyone\n' LIBS/ACME/CARDS/CARDS.LIB "$DATA/ACME.SEC"
package cards2 '[package]\nid = acme.cards\nname = Cards\nversion = 1.1.0\nkind = library\n' LIBS/ACME/CARDS/CARDS.LIB
package chess '[package]\nid = acme.chess\nname = Chess\nversion = 2.0\nkind = app\n[depends]\nacme.cards = 1.0\n' APPS/ACME/CHESS/CHESS.APP
package dvxown '[package]\nid = kpunch.extra\nname = Extra\nversion = 1.0.0\nkind = font\n' SHARED/FONTS/KPUNCH/EXTRA.DFN
package dice '[package]\nid = acme.dice\nname = Dice\nversion = 1.0.0\nkind = app\n' APPS/ACME/DICE/DICE.APP
package dice2 '[package]\nid = acme.dice\nname = Dice\nversion = 1.1.0\nkind = app\n' APPS/ACME/DICE/DICE.APP
package dice3 '[package]\nid = acme.dice\nname = Dice\nversion = 1.2.0\nkind = app\n' APPS/ACME/DICE/DICE.APP
printf 'not a package' > "$DATA/junk.dpk"
cat > "$DATA/dvx.conf" <<CONF
bindHost = 127.0.0.1
bindPort = $PORT
publicOrigin = http://127.0.0.1:$PORT
dataDir = $DATA/server
database = $DATA/server/dvx.db
pbkdf2Iterations = 1000
mailFrom = test@example.com
dvxpkg = $DVXPKG
repoKey = $DATA/REPO.KEY
serveContexts = 3
uploadMax = 1048576
adminToken = $ADMIN
CONF
stop() { # stop <pid>: ask, then insist, so a stuck server cannot hang the run
kill "$1" 2>/dev/null
for _ in $(seq 1 40); do
kill -0 "$1" 2>/dev/null || break
sleep 0.25
done
kill -9 "$1" 2>/dev/null
wait "$1" 2>/dev/null
}
wait_for() { # wait_for <port>
for _ in $(seq 1 40); do
curl -s -m 1 "http://127.0.0.1:$1/v1/health" > /dev/null 2>&1 && return 0
sleep 0.25
done
return 1
}
# Something already answering on a test port would be tested in place of the server under test
for port in $PORT $MASTER_PORT; do
curl -s -m 1 "http://127.0.0.1:$port/" > /dev/null 2>&1 && { echo "port $port is already in use"; exit 1; }
done
"$CALOG" dvxserver.lua -- "singe=$SINGE" "calog=$CALOG_HOME" "$DATA/dvx.conf" > "$DATA/server.log" 2>&1 &
SERVER=$!
wait_for $PORT || { echo "the server did not start:"; cat "$DATA/server.log"; stop $SERVER; exit 1; }
STATUS=0
for suite in testPackages testReview; do
printf '%-16s ' "$suite"
"$CALOG" "test/$suite.lua" -- "http://127.0.0.1:$PORT" "$DATA" "$DVXPKG" "$ADMIN" "$CALOG" "$SINGE" | grep -E "^FAIL|passed,"
[ "${PIPESTATUS[0]}" -ne 0 ] && STATUS=1
done
stop $SERVER
# Both services in one process: singemaster's master.lua and this one, each with its own settings
mkdir -p "$DATA/master"
cat > "$DATA/master.conf" <<CONF
bindHost = 127.0.0.1
bindPort = $MASTER_PORT
publicOrigin = http://127.0.0.1:$MASTER_PORT
dataDir = $DATA/master
database = $DATA/master/master.db
pbkdf2Iterations = 1000
mailFrom = test@example.com
CONF
"$CALOG" "$SINGE/master.lua" dvxserver.lua -- "singe=$SINGE" "calog=$CALOG_HOME" "master=$DATA/master.conf" "dvx=$DATA/dvx.conf" > "$DATA/both.log" 2>&1 &
BOTH=$!
printf '%-16s ' "oneProcess"
if wait_for $PORT && wait_for $MASTER_PORT \
&& curl -s "http://127.0.0.1:$PORT/v1/health" | grep -q '"dvx-packages"' \
&& curl -s "http://127.0.0.1:$MASTER_PORT/v1/health" | grep -q '"singe-master"'; then
echo "2 passed, 0 failed"
else
echo "FAIL both services in one process"; cat "$DATA/both.log"; STATUS=1
fi
stop $BOTH
exit $STATUS