225 lines
9.1 KiB
Bash
Executable File
225 lines
9.1 KiB
Bash
Executable File
#!/bin/sh
|
|
set -eu
|
|
|
|
usage() {
|
|
echo "usage: $0 [env-file]" >&2
|
|
exit 64
|
|
}
|
|
|
|
[ "$#" -le 1 ] || usage
|
|
|
|
script_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
|
workspace_root=$(CDPATH= cd -- "$script_dir/.." && pwd)
|
|
env_file=${1:-"$workspace_root/.env.ci"}
|
|
|
|
if [ ! -f "$env_file" ]; then
|
|
echo "missing integration environment file: $env_file" >&2
|
|
exit 66
|
|
fi
|
|
env_file=$(CDPATH= cd -- "$(dirname -- "$env_file")" && pwd)/$(basename -- "$env_file")
|
|
|
|
# .env.ci is generated by the sam_rebuild development Compose helper and is a
|
|
# shell-compatible, credential-bearing local file. Never print its contents.
|
|
set -a
|
|
# shellcheck disable=SC1090
|
|
. "$env_file"
|
|
set +a
|
|
|
|
: "${POSTGRES_HOST:?POSTGRES_HOST is required in $env_file}"
|
|
: "${POSTGRES_PORT:?POSTGRES_PORT is required in $env_file}"
|
|
: "${POSTGRES_DB:?POSTGRES_DB is required in $env_file}"
|
|
: "${POSTGRES_USER:?POSTGRES_USER is required in $env_file}"
|
|
: "${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required in $env_file}"
|
|
: "${REDIS_URL:?REDIS_URL is required in $env_file}"
|
|
|
|
integration_schema=${CONDITIONAL_INTEGRATION_SCHEMA:-conditional_integration}
|
|
scenario_schema=${SCENARIO_SEED_INTEGRATION_SCHEMA:-conditional_scenario_seed}
|
|
npc_possession_schema=${NPC_POSSESSION_INTEGRATION_SCHEMA:-conditional_$(date +%s)_$$_npc_possession_integration}
|
|
npc_possession_differential_schema=conditional_$(date +%s)_$$_npc_possession_differential
|
|
|
|
for schema in "$integration_schema" "$scenario_schema" "$npc_possession_schema" "$npc_possession_differential_schema"; do
|
|
case "$schema" in
|
|
''|[!a-z_]*|*[!a-z0-9_]*)
|
|
echo "integration schema must be a lowercase PostgreSQL identifier: $schema" >&2
|
|
exit 64
|
|
;;
|
|
esac
|
|
done
|
|
|
|
build_database_url() {
|
|
SCHEMA_NAME=$1 node --input-type=module -e '
|
|
const required = [
|
|
"POSTGRES_HOST",
|
|
"POSTGRES_PORT",
|
|
"POSTGRES_DB",
|
|
"POSTGRES_USER",
|
|
"POSTGRES_PASSWORD",
|
|
"SCHEMA_NAME",
|
|
];
|
|
for (const name of required) {
|
|
if (!process.env[name]) {
|
|
throw new Error(`missing ${name}`);
|
|
}
|
|
}
|
|
const url = new URL("postgresql://localhost");
|
|
url.hostname = process.env.POSTGRES_HOST;
|
|
url.port = process.env.POSTGRES_PORT;
|
|
url.username = process.env.POSTGRES_USER;
|
|
url.password = process.env.POSTGRES_PASSWORD;
|
|
url.pathname = `/${process.env.POSTGRES_DB}`;
|
|
url.searchParams.set("schema", process.env.SCHEMA_NAME);
|
|
process.stdout.write(url.href);
|
|
'
|
|
}
|
|
|
|
run_marked_tests() {
|
|
package_dir=$1
|
|
marker=$2
|
|
label=$3
|
|
test_files=$(cd "$workspace_root/$package_dir" && rg -l "$marker" test -g '*.test.ts' | sort)
|
|
if [ -z "$test_files" ]; then
|
|
echo "no $label tests found under $package_dir" >&2
|
|
exit 65
|
|
fi
|
|
echo "running $label tests in $package_dir"
|
|
(
|
|
cd "$workspace_root/$package_dir"
|
|
printf '%s\n' "$test_files" |
|
|
xargs -r pnpm exec vitest run --no-file-parallelism --maxWorkers=1
|
|
)
|
|
}
|
|
|
|
cd "$workspace_root"
|
|
pnpm install --frozen-lockfile
|
|
pnpm --filter @sammo-ts/infra prisma:generate
|
|
pnpm --filter @sammo-ts/common build
|
|
pnpm --filter @sammo-ts/infra build
|
|
|
|
database_url=$(build_database_url "$integration_schema")
|
|
export POSTGRES_SCHEMA=$integration_schema
|
|
export DATABASE_URL=$database_url
|
|
export INPUT_EVENT_DATABASE_URL=$database_url
|
|
export GENERAL_LIFECYCLE_DATABASE_URL=$database_url
|
|
export TURN_DAEMON_LEASE_DATABASE_URL=$database_url
|
|
export TURN_DIFFERENTIAL_DATABASE_URL=$database_url
|
|
export RESERVED_TURN_DATABASE_URL=$database_url
|
|
|
|
pnpm --filter @sammo-ts/infra prisma:db:push:game
|
|
|
|
database_markers='INPUT_EVENT_DATABASE_URL|GENERAL_LIFECYCLE_DATABASE_URL|TURN_DAEMON_LEASE_DATABASE_URL|RESERVED_TURN_DATABASE_URL'
|
|
run_marked_tests app/game-api "$database_markers" "PostgreSQL"
|
|
run_marked_tests app/game-engine "$database_markers" "PostgreSQL"
|
|
run_marked_tests tools/integration-tests \
|
|
'TURN_DIFFERENTIAL_DATABASE_URL|INPUT_EVENT_DATABASE_URL' \
|
|
"PostgreSQL snapshot"
|
|
|
|
npc_possession_database_url=$(build_database_url "$npc_possession_schema")
|
|
(
|
|
export POSTGRES_SCHEMA=$npc_possession_schema
|
|
export DATABASE_URL=$npc_possession_database_url
|
|
export NPC_POSSESSION_DATABASE_URL=$npc_possession_database_url
|
|
pnpm --filter @sammo-ts/infra prisma:migrate:deploy:game
|
|
pnpm --filter @sammo-ts/infra prisma:migrate:deploy:game
|
|
run_marked_tests app/game-api \
|
|
'NPC_POSSESSION_DATABASE_URL' \
|
|
"NPC possession PostgreSQL"
|
|
)
|
|
|
|
if [ "${TURN_DIFFERENTIAL_REFERENCE:-}" = "1" ]; then
|
|
reference_workspace_root=${TURN_DIFFERENTIAL_WORKSPACE_ROOT:-"$workspace_root/.."}
|
|
reference_stack=${TURN_DIFFERENTIAL_STACK_DIR:-"$reference_workspace_root/docker_compose_files/reference"}
|
|
if [ ! -f "$reference_stack/compose.yml" ]; then
|
|
echo "reference compose file is missing; set TURN_DIFFERENTIAL_WORKSPACE_ROOT or TURN_DIFFERENTIAL_STACK_DIR" >&2
|
|
exit 69
|
|
fi
|
|
if [ ! -f "$reference_workspace_root/ref/sam/d_setting/RootDB.php" ] ||
|
|
[ ! -f "$reference_workspace_root/ref/sam/hwe/d_setting/DB.php" ]; then
|
|
echo "reference runtime database configuration is missing under $reference_workspace_root/ref/sam" >&2
|
|
exit 69
|
|
fi
|
|
if ! docker compose -f "$reference_stack/compose.yml" ps --status running --services | grep -qx db ||
|
|
! docker compose -f "$reference_stack/compose.yml" exec -T db healthcheck.sh --connect --innodb_initialized \
|
|
>/dev/null 2>&1; then
|
|
echo "TURN_DIFFERENTIAL_REFERENCE=1 requires a healthy bootstrapped reference db stack" >&2
|
|
exit 69
|
|
fi
|
|
reference_tables=$(
|
|
docker compose -f "$reference_stack/compose.yml" exec -T db sh -c '
|
|
export MYSQL_PWD="$(cat /run/secrets/db_root_password)"
|
|
mariadb --batch --skip-column-names -u root -e "
|
|
SELECT COUNT(*) FROM information_schema.TABLES
|
|
WHERE TABLE_SCHEMA = '\''$MARIADB_DATABASE'\'' AND TABLE_NAME = '\''member'\'';
|
|
SELECT COUNT(*) FROM information_schema.TABLES
|
|
WHERE TABLE_SCHEMA = '\''$REF_HWE_DB_NAME'\'' AND TABLE_NAME IN ('\''general'\'', '\''select_npc_token'\'');
|
|
"
|
|
' 2>/dev/null
|
|
) || {
|
|
echo "failed to inspect reference database bootstrap state" >&2
|
|
exit 69
|
|
}
|
|
if [ "$reference_tables" != "$(printf '1\n2')" ]; then
|
|
echo "reference root/HWE databases are not bootstrapped" >&2
|
|
exit 69
|
|
fi
|
|
npc_possession_differential_database_url=$(build_database_url "$npc_possession_differential_schema")
|
|
(
|
|
cleanup_npc_possession_differential_schema() {
|
|
printf 'DROP SCHEMA IF EXISTS "%s" CASCADE;\n' "$npc_possession_differential_schema" |
|
|
DATABASE_URL=$npc_possession_differential_database_url \
|
|
pnpm --filter @sammo-ts/infra exec prisma db execute --stdin >/dev/null
|
|
}
|
|
handle_npc_possession_differential_exit() {
|
|
exit_status=$?
|
|
trap - EXIT HUP INT TERM
|
|
if ! cleanup_npc_possession_differential_schema && [ "$exit_status" -eq 0 ]; then
|
|
exit_status=1
|
|
fi
|
|
exit "$exit_status"
|
|
}
|
|
trap handle_npc_possession_differential_exit EXIT
|
|
trap 'exit 129' HUP
|
|
trap 'exit 130' INT
|
|
trap 'exit 143' TERM
|
|
export POSTGRES_SCHEMA=$npc_possession_differential_schema
|
|
export DATABASE_URL=$npc_possession_differential_database_url
|
|
export NPC_POSSESSION_DIFFERENTIAL_DATABASE_URL=$npc_possession_differential_database_url
|
|
export TURN_DIFFERENTIAL_WORKSPACE_ROOT=$reference_workspace_root
|
|
export TURN_DIFFERENTIAL_STACK_DIR=$reference_stack
|
|
pnpm --filter @sammo-ts/infra prisma:db:push:game
|
|
cd "$workspace_root/tools/integration-tests"
|
|
pnpm exec vitest run --no-file-parallelism --maxWorkers=1 \
|
|
test/npcPossessionSelectionReference.integration.test.ts
|
|
)
|
|
|
|
live_sortie_schema=${LIVE_SORTIE_PERSISTENCE_SCHEMA:-conditional_live_sortie_persistence}
|
|
case "$live_sortie_schema" in
|
|
''|[!a-z_]*|*[!a-z0-9_]*)
|
|
echo "live sortie persistence schema must be a lowercase PostgreSQL identifier" >&2
|
|
exit 64
|
|
;;
|
|
esac
|
|
live_sortie_database_url=$(build_database_url "$live_sortie_schema")
|
|
export POSTGRES_SCHEMA=$live_sortie_schema
|
|
export DATABASE_URL=$live_sortie_database_url
|
|
export LIVE_SORTIE_PERSISTENCE_DATABASE_URL=$live_sortie_database_url
|
|
pnpm --filter @sammo-ts/infra prisma:db:push:game
|
|
run_marked_tests tools/integration-tests \
|
|
'LIVE_SORTIE_PERSISTENCE_DATABASE_URL' \
|
|
"live sortie PostgreSQL persistence"
|
|
export POSTGRES_SCHEMA=$integration_schema
|
|
export DATABASE_URL=$database_url
|
|
fi
|
|
|
|
run_marked_tests app/game-api 'process\.env\.REDIS_URL' "Redis"
|
|
|
|
scenario_database_url=$(build_database_url "$scenario_schema")
|
|
(
|
|
export POSTGRES_SCHEMA=$scenario_schema
|
|
export DATABASE_URL=$scenario_database_url
|
|
pnpm --filter @sammo-ts/infra prisma:db:push:game
|
|
cd "$workspace_root/app/game-engine"
|
|
pnpm exec vitest run --no-file-parallelism --maxWorkers=1 test/scenarioSeeder.test.ts
|
|
)
|
|
|
|
echo "conditional PostgreSQL and Redis integration tests passed"
|