19908436b8
## Summary Speeds up webapp test jobs by balancing measured work across runners, reducing repeated container setup, and ensuring test workers release shutdown resources promptly. Unit tests run across 24 duration-aware shards, while E2E tests run across two balanced shards. ## Design `RunEngine` shutdown now closes processing resources before support resources, continues cleanup if one close fails, and reuses one shutdown promise for concurrent callers. Redis workers clear completed shutdown deadlines so finished tests no longer wait on idle timers. Container-heavy suites are split only where it improves parallelism, and repeated replication and engine fixtures are consolidated where one end-to-end case provides coverage. Timing weights are refreshed for all affected files. Dependency installation overlaps container pulls, and both workflows use WarpBuild's Node setup action.
199 lines
7.0 KiB
YAML
199 lines
7.0 KiB
YAML
name: "🧪 Unit Tests: Webapp"
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
on:
|
|
workflow_call:
|
|
secrets:
|
|
DOCKERHUB_USERNAME:
|
|
required: false
|
|
DOCKERHUB_TOKEN:
|
|
required: false
|
|
|
|
jobs:
|
|
unitTests:
|
|
name: "🧪 Unit Tests: Webapp"
|
|
# Webapp test throughput is limited per-machine (one docker daemon + disk absorbing
|
|
# all the per-file Postgres/ClickHouse container spin-up), so many machines beats
|
|
# few big ones - fewer/bigger (3x32) measured slower than 10x8. The 16x (vs 8x)
|
|
# gives the fork pool the CPU headroom the 8x runners lacked.
|
|
runs-on: warp-ubuntu-latest-x64-16x
|
|
strategy:
|
|
# one flaky shard shouldn't cancel its siblings - lets us re-run only the failed shard
|
|
fail-fast: false
|
|
matrix:
|
|
shardIndex:
|
|
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
|
|
shardTotal: [24]
|
|
env:
|
|
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
SHARD_INDEX: ${{ matrix.shardIndex }}
|
|
SHARD_TOTAL: ${{ matrix.shardTotal }}
|
|
steps:
|
|
- name: 🔧 Disable IPv6
|
|
run: |
|
|
sudo sysctl -w net.ipv6.conf.all.disable_ipv6=1
|
|
sudo sysctl -w net.ipv6.conf.default.disable_ipv6=1
|
|
sudo sysctl -w net.ipv6.conf.lo.disable_ipv6=1
|
|
|
|
- name: 🔧 Configure docker address pool
|
|
run: |
|
|
CONFIG='{
|
|
"default-address-pools" : [
|
|
{
|
|
"base" : "172.17.0.0/12",
|
|
"size" : 20
|
|
},
|
|
{
|
|
"base" : "192.168.0.0/16",
|
|
"size" : 24
|
|
}
|
|
]
|
|
}'
|
|
mkdir -p /etc/docker
|
|
echo "$CONFIG" | sudo tee /etc/docker/daemon.json
|
|
|
|
- name: 🔧 Restart docker daemon
|
|
run: sudo systemctl restart docker
|
|
|
|
- name: ⬇️ Checkout repo
|
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
with:
|
|
fetch-depth: 1
|
|
persist-credentials: false
|
|
|
|
- name: ⎔ Setup pnpm
|
|
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
|
|
with:
|
|
version: 10.33.2
|
|
|
|
- name: ⎔ Setup node
|
|
uses: WarpBuilds/setup-node@bc639b444d583175926b588962199c247d23e8d3 # v6
|
|
with:
|
|
node-version: 24.18.0
|
|
cache: "pnpm"
|
|
|
|
# ..to avoid rate limits when pulling images
|
|
- name: 🐳 Login to DockerHub
|
|
if: ${{ env.DOCKERHUB_USERNAME }}
|
|
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
|
|
with:
|
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
- name: 🐳 Skipping DockerHub login (no secrets available)
|
|
if: ${{ !env.DOCKERHUB_USERNAME }}
|
|
run: echo "DockerHub login skipped because secrets are not available."
|
|
|
|
- name: 📥 Prepare deps and testcontainer images
|
|
run: |
|
|
# Pull images concurrently with dependency installation. Retry each pull because
|
|
# DockerHub registry timeouts are a recurring transient CI flake.
|
|
pull() {
|
|
for attempt in 1 2 3; do
|
|
docker pull "$1" && return 0
|
|
echo "::warning::docker pull $1 failed (attempt ${attempt}/3); retrying in 10s"
|
|
sleep 10
|
|
done
|
|
echo "::error::docker pull $1 failed after 3 attempts"
|
|
return 1
|
|
}
|
|
|
|
pull_images() {
|
|
local pids=()
|
|
local failed=0
|
|
for image in \
|
|
postgres:14 \
|
|
postgres:17 \
|
|
clickhouse/clickhouse-server:26.2.19.43-alpine@sha256:c6ad6a7eb2fb5999df3adfb8b69a0c7222c68fa9b8f6b04a088564ebbc959251 \
|
|
redis:7.2 \
|
|
testcontainers/ryuk:0.14.0 \
|
|
electricsql/electric:1.2.4@sha256:20da3d0b0e74926c5623392db67fd56698b9e374c4aeb6cb5cadeb8fea171c36 \
|
|
minio/minio:latest
|
|
do
|
|
pull "$image" &
|
|
pids+=("$!")
|
|
done
|
|
for pid in "${pids[@]}"; do
|
|
if ! wait "$pid"; then
|
|
failed=1
|
|
fi
|
|
done
|
|
return "$failed"
|
|
}
|
|
|
|
echo "Installing dependencies and pre-pulling Docker images..."
|
|
pull_images &
|
|
pull_pid=$!
|
|
install_status=0
|
|
pnpm install --frozen-lockfile || install_status=$?
|
|
pull_status=0
|
|
wait "$pull_pid" || pull_status=$?
|
|
if (( install_status != 0 || pull_status != 0 )); then
|
|
exit 1
|
|
fi
|
|
echo "Dependency install and image pre-pull complete"
|
|
|
|
- name: 📀 Generate Prisma Client
|
|
run: pnpm run generate
|
|
|
|
- name: 🧪 Run Webapp Unit Tests
|
|
run: pnpm run test:webapp --reporter=default --reporter=blob --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} --passWithNoTests
|
|
env:
|
|
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/postgres
|
|
DIRECT_URL: postgresql://postgres:postgres@localhost:5432/postgres
|
|
SESSION_SECRET: "secret"
|
|
MAGIC_LINK_SECRET: "secret"
|
|
ENCRYPTION_KEY: "dummy-encryption-keeeey-32-bytes"
|
|
DEPLOY_REGISTRY_HOST: "docker.io"
|
|
CLICKHOUSE_URL: "http://default:password@localhost:8123"
|
|
|
|
- name: Gather all reports
|
|
if: ${{ !cancelled() }}
|
|
run: |
|
|
mkdir -p .vitest-reports
|
|
find . -type f -path '*/.vitest-reports/blob-*.json' \
|
|
-exec bash -c 'src="$1"; basename=$(basename "$src"); pkg=$(dirname "$src" | sed "s|^\./||;s|/\.vitest-reports$||;s|/|_|g"); cp "$src" ".vitest-reports/${pkg}-${basename}"' _ {} \;
|
|
|
|
- name: Upload blob reports to GitHub Actions Artifacts
|
|
if: ${{ !cancelled() }}
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
with:
|
|
name: webapp-blob-report-${{ matrix.shardIndex }}
|
|
path: .vitest-reports/*
|
|
include-hidden-files: true
|
|
retention-days: 1
|
|
|
|
merge-reports:
|
|
name: "📊 Merge Reports"
|
|
if: ${{ !cancelled() }}
|
|
needs: [unitTests]
|
|
runs-on: warp-ubuntu-latest-x64-2x
|
|
steps:
|
|
- name: ⬇️ Checkout repo
|
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
with:
|
|
fetch-depth: 1
|
|
persist-credentials: false
|
|
|
|
- name: ⎔ Setup pnpm
|
|
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
|
|
with:
|
|
version: 10.33.2
|
|
|
|
- name: ⎔ Setup node
|
|
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
with:
|
|
node-version: 24.18.0
|
|
# no cache enabled, we're not installing deps
|
|
|
|
- name: Download blob reports from GitHub Actions Artifacts
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
with:
|
|
path: .vitest-reports
|
|
pattern: webapp-blob-report-*
|
|
merge-multiple: true
|
|
|
|
- name: Merge reports
|
|
run: pnpm dlx vitest@4.1.7 run --merge-reports --pass-with-no-tests
|