Files
silverwind 1031e34987 test: run integration tests on random ports and speed up slow tests (#39842)
Integration test processes now get their own work directory, config file
and random ports, so several runs can execute in parallel on one
machine. The slowest tests also lose fixed sleeps and needlessly
expensive setup, with their assertions kept.

- Batch PostgreSQL sequence resets, the main per-test fixture cost there
- Cheap hashing params in hash and OAuth2 fixture tests, full-cost
vectors stay
- Single fetch for negative Actions runner assertions instead of 1s
polls
- Queue flushes and backdated timestamps instead of sleeps
- In-memory SQLite test journal, tmpfs for PostgreSQL in CI
- E2E instance writes SSH keys into its work directory instead of
`~/.ssh/authorized_keys`
2026-10-18 12:56:04 +00:00

197 lines
5.7 KiB
Bash
Executable File

#!/bin/bash
set -euo pipefail
CONTAINER_RUNTIME="${CONTAINER_RUNTIME:-docker}"
CONTAINER_NAME="gitea-e2e-runner-$$"
free_port() {
node -e "const s=require('net').createServer();s.listen(0,'127.0.0.1',()=>{process.stdout.write(String(s.address().port));s.close()})"
}
detect_playwright_mode() {
if [ "${PLAYWRIGHT_MODE:-auto}" = "local" ] || [ "${PLAYWRIGHT_MODE:-auto}" = "container" ]; then
return
fi
PLAYWRIGHT_MODE="local"
if [ "$(uname -s)" = "Linux" ]; then
# playwright only supports ubuntu/debian officially
if ! grep -qE '^ID(_LIKE)?=.*(ubuntu|debian)' /etc/os-release 2>/dev/null; then
PLAYWRIGHT_MODE="container"
fi
fi
}
wait_for_container() {
local max_wait=30
local elapsed=0
echo "Waiting for container to start..."
while ! (echo > "/dev/tcp/127.0.0.1/$PLAYWRIGHT_SERVER_PORT") 2>/dev/null; do
if [ "$("$CONTAINER_RUNTIME" inspect -f '{{.State.Running}}' "$CONTAINER_NAME" 2>/dev/null)" != "true" ]; then
echo "Error: container exited before becoming ready." >&2
"$CONTAINER_RUNTIME" logs "$CONTAINER_NAME" >&2 || true
return 1
fi
if [ "$elapsed" -ge "$max_wait" ]; then
echo "Error: container did not become ready after ${max_wait}s." >&2
"$CONTAINER_RUNTIME" logs "$CONTAINER_NAME" >&2 || true
return 1
fi
sleep 1
elapsed=$((elapsed + 1))
done
echo "Container is ready."
}
detect_playwright_mode
if [ "$PLAYWRIGHT_MODE" = "container" ]; then
if ! command -v "$CONTAINER_RUNTIME" >/dev/null 2>&1; then
echo "error: PLAYWRIGHT_MODE=container but '$CONTAINER_RUNTIME' is not installed." >&2
echo "Install docker/podman or set CONTAINER_RUNTIME to an available runtime." >&2
exit 1
fi
PLAYWRIGHT_VERSION=$(sed -n 's/.*"@playwright\/test"[[:space:]]*:[[:space:]]*"[^[:digit:]]*\([^"]*\)".*/\1/p' package.json)
if ! [[ "$PLAYWRIGHT_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.]+)?$ ]]; then
echo "error: invalid @playwright/test version in package.json: '${PLAYWRIGHT_VERSION}'" >&2
exit 1
fi
PLAYWRIGHT_IMAGE="mcr.microsoft.com/playwright:v${PLAYWRIGHT_VERSION}-noble"
echo "Running playwright in container"
if ! "$CONTAINER_RUNTIME" image inspect "$PLAYWRIGHT_IMAGE" >/dev/null 2>&1; then
"$CONTAINER_RUNTIME" pull "$PLAYWRIGHT_IMAGE"
fi
fi
# Create isolated work directory
WORK_DIR=$(mktemp -d)
# Find a random free port
FREE_PORT=$(free_port)
cleanup() {
if [ "$PLAYWRIGHT_MODE" = "container" ]; then
"$CONTAINER_RUNTIME" stop "$CONTAINER_NAME" >/dev/null 2>&1 || true
fi
if [ -n "${SERVER_PID:-}" ]; then
kill "$SERVER_PID" 2>/dev/null || true
wait "$SERVER_PID" 2>/dev/null || true
fi
rm -rf "$WORK_DIR"
}
trap cleanup EXIT
if [ "$PLAYWRIGHT_MODE" = "container" ]; then
PLAYWRIGHT_SERVER_PORT=$(free_port)
# --network=host: container needs host loopback to reach gitea.
"$CONTAINER_RUNTIME" run --network=host --name "$CONTAINER_NAME" -d --rm --init --workdir /home/pwuser --user pwuser "$PLAYWRIGHT_IMAGE" /bin/sh -c "npx -y playwright@${PLAYWRIGHT_VERSION} run-server --port ${PLAYWRIGHT_SERVER_PORT} --host 0.0.0.0"
if ! wait_for_container; then
exit 1
fi
fi
# Write config file for isolated instance
mkdir -p "$WORK_DIR/custom/conf"
cat > "$WORK_DIR/custom/conf/app.ini" <<EOF
[database]
DB_TYPE = sqlite3
PATH = $WORK_DIR/data/gitea.db
[server]
HTTP_PORT = $FREE_PORT
ROOT_URL = http://localhost:$FREE_PORT
STATIC_ROOT_PATH = $(pwd)
SSH_ROOT_PATH = $WORK_DIR/ssh
[security]
INSTALL_LOCK = true
[service]
ENABLE_CAPTCHA = false
DISABLE_REGISTRATION = false
[ui.notification]
EVENT_SOURCE_UPDATE_TIME = 500ms
[log]
MODE = console
LEVEL = Warn
[markup.test-external]
ENABLED = true
FILE_EXTENSIONS = .external
RENDER_COMMAND = cat
IS_INPUT_FILE = false
RENDER_CONTENT_MODE = iframe
EOF
export GITEA_WORK_DIR="$WORK_DIR"
export GITEA_TEST_E2E=true
# Start Gitea server
echo "Starting Gitea server on port $FREE_PORT (workdir: $WORK_DIR)..."
if [ -n "${GITEA_TEST_E2E_DEBUG:-}" ]; then
"./$EXECUTABLE" web &
else
"./$EXECUTABLE" web > "$WORK_DIR/server.log" 2>&1 &
fi
SERVER_PID=$!
# Wait for server to be reachable
E2E_URL="http://localhost:$FREE_PORT"
MAX_WAIT=120
ELAPSED=0
while ! curl -sf --max-time 5 "$E2E_URL" > /dev/null 2>&1; do
if ! kill -0 "$SERVER_PID" 2>/dev/null; then
echo "error: Gitea server process exited unexpectedly. Server log:" >&2
cat "$WORK_DIR/server.log" 2>/dev/null >&2 || true
exit 1
fi
if [ "$ELAPSED" -ge "$MAX_WAIT" ]; then
echo "error: Gitea server not reachable after ${MAX_WAIT}s. Server log:" >&2
cat "$WORK_DIR/server.log" 2>/dev/null >&2 || true
exit 1
fi
sleep 2
ELAPSED=$((ELAPSED + 2))
done
echo "Gitea server is ready at $E2E_URL"
GITEA_TEST_E2E_DOMAIN="e2e.gitea.com"
GITEA_TEST_E2E_USER="e2e-admin"
GITEA_TEST_E2E_PASSWORD="password"
GITEA_TEST_E2E_EMAIL="$GITEA_TEST_E2E_USER@$GITEA_TEST_E2E_DOMAIN"
# Create admin test user
"./$EXECUTABLE" admin user create \
--username "$GITEA_TEST_E2E_USER" \
--password "$GITEA_TEST_E2E_PASSWORD" \
--email "$GITEA_TEST_E2E_EMAIL" \
--must-change-password=false \
--admin
# timeout multiplier to make the tests pass on slow CI runners while using
# factor 1 on a fast local machine like a MacBook Pro M1+
if [ -z "${GITEA_TEST_E2E_TIMEOUT_FACTOR:-}" ]; then
if [ -n "${CI:-}" ]; then
GITEA_TEST_E2E_TIMEOUT_FACTOR=4
else
GITEA_TEST_E2E_TIMEOUT_FACTOR=1
fi
fi
export GITEA_TEST_E2E_URL="$E2E_URL"
export GITEA_TEST_E2E_DOMAIN
export GITEA_TEST_E2E_USER
export GITEA_TEST_E2E_PASSWORD
export GITEA_TEST_E2E_EMAIL
export GITEA_TEST_E2E_TIMEOUT_FACTOR
if [ "$PLAYWRIGHT_MODE" = "container" ]; then
export PW_TEST_CONNECT_WS_ENDPOINT="ws://127.0.0.1:${PLAYWRIGHT_SERVER_PORT}/"
fi
pnpm exec playwright test "$@"