ci: run external-state invariants
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
237899745
2026-07-26 06:36:06 +08:00
parent f8f5da04db
commit 380e89b058
3 changed files with 166 additions and 2 deletions

1
.gitattributes vendored
View File

@@ -1 +1,2 @@
migrations/*.sql text eol=crlf
*.sh text eol=lf

View File

@@ -8,6 +8,32 @@ on:
jobs:
verify:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_PASSWORD: codex_test
POSTGRES_DB: imageforge_test
options: >-
--health-cmd "pg_isready -U postgres -d imageforge_test"
--health-interval 5s
--health-timeout 3s
--health-retries 20
redis:
image: redis:7-alpine
options: >-
--health-cmd "redis-cli ping"
--health-interval 5s
--health-timeout 3s
--health-retries 20
env:
DATABASE_URL: postgres://postgres:codex_test@postgres:5432/imageforge_test
REDIS_URL: redis://redis:6379/
IMAGEFORGE_TEST_DATABASE_URL: postgres://postgres:codex_test@postgres:5432/imageforge_test
IMAGEFORGE_TEST_REDIS_URL: redis://redis:6379/
JWT_SECRET: imageforge-ci-jwt-secret
API_KEY_PEPPER: imageforge-ci-api-key-pepper
EXPECTED_EXTERNAL_TESTS: '9'
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -40,10 +66,13 @@ jobs:
run: cargo fmt --all -- --check
- name: Run Clippy
run: cargo clippy --all-targets -- -D warnings
run: cargo clippy --all-targets --all-features --locked -- -D warnings
- name: Run Rust tests
run: cargo test --all-targets
run: cargo test --all-targets --locked
- name: Run external-state tests
run: bash scripts/run_external_state_tests.sh
- name: Install cargo-audit
run: cargo install cargo-audit --locked --version 0.22.2

View File

@@ -0,0 +1,134 @@
#!/usr/bin/env bash
set -Eeuo pipefail
EXPECTED_EXTERNAL_TESTS="${EXPECTED_EXTERNAL_TESTS:-9}"
WORK_DIR="$(mktemp -d)"
POSTGRES_CONTAINER=""
REDIS_CONTAINER=""
MINIO_PID=""
cleanup() {
local status=$?
trap - EXIT INT TERM
set +e
if [[ -n "$MINIO_PID" ]]; then
kill "$MINIO_PID" 2>/dev/null
wait "$MINIO_PID" 2>/dev/null
fi
if [[ -n "$POSTGRES_CONTAINER" ]]; then
docker rm -f "$POSTGRES_CONTAINER" >/dev/null 2>&1
fi
if [[ -n "$REDIS_CONTAINER" ]]; then
docker rm -f "$REDIS_CONTAINER" >/dev/null 2>&1
fi
rm -rf "$WORK_DIR"
exit "$status"
}
trap cleanup EXIT INT TERM
wait_for_command() {
local description=$1
shift
for _ in $(seq 1 60); do
if "$@" >/dev/null 2>&1; then
return 0
fi
sleep 1
done
echo "Timed out waiting for ${description}" >&2
return 1
}
if [[ -z "${IMAGEFORGE_TEST_DATABASE_URL:-}" || -z "${IMAGEFORGE_TEST_REDIS_URL:-}" ]]; then
if ! command -v docker >/dev/null 2>&1; then
echo "Set IMAGEFORGE_TEST_DATABASE_URL and IMAGEFORGE_TEST_REDIS_URL, or install Docker." >&2
exit 1
fi
suffix="$$-${RANDOM}"
postgres_port="${IMAGEFORGE_TEST_POSTGRES_PORT:-25432}"
redis_port="${IMAGEFORGE_TEST_REDIS_PORT:-26379}"
POSTGRES_CONTAINER="imageforge-test-postgres-${suffix}"
REDIS_CONTAINER="imageforge-test-redis-${suffix}"
docker run -d \
--label imageforge.external-tests=true \
--name "$POSTGRES_CONTAINER" \
-e POSTGRES_PASSWORD=codex_test \
-e POSTGRES_DB=imageforge_test \
-p "127.0.0.1:${postgres_port}:5432" \
postgres:16-alpine >/dev/null
docker run -d \
--label imageforge.external-tests=true \
--name "$REDIS_CONTAINER" \
-p "127.0.0.1:${redis_port}:6379" \
redis:7-alpine >/dev/null
wait_for_command PostgreSQL docker exec "$POSTGRES_CONTAINER" \
pg_isready -U postgres -d imageforge_test
wait_for_command Redis docker exec "$REDIS_CONTAINER" redis-cli ping
export IMAGEFORGE_TEST_DATABASE_URL="postgres://postgres:codex_test@127.0.0.1:${postgres_port}/imageforge_test"
export IMAGEFORGE_TEST_REDIS_URL="redis://127.0.0.1:${redis_port}/"
fi
arch="$(uname -m)"
case "$arch" in
x86_64) minio_arch=amd64 ;;
aarch64|arm64) minio_arch=arm64 ;;
*) echo "Unsupported MinIO architecture: ${arch}" >&2; exit 1 ;;
esac
MINIO_BIN="${MINIO_BIN:-${WORK_DIR}/minio}"
MC_BIN="${MC_BIN:-${WORK_DIR}/mc}"
if [[ ! -x "$MINIO_BIN" ]]; then
curl --fail --silent --show-error --location --retry 3 \
"https://dl.min.io/server/minio/release/linux-${minio_arch}/minio" \
--output "$MINIO_BIN"
chmod +x "$MINIO_BIN"
fi
if [[ ! -x "$MC_BIN" ]]; then
curl --fail --silent --show-error --location --retry 3 \
"https://dl.min.io/client/mc/release/linux-${minio_arch}/mc" \
--output "$MC_BIN"
chmod +x "$MC_BIN"
fi
export IMAGEFORGE_TEST_S3_ENDPOINT="${IMAGEFORGE_TEST_S3_ENDPOINT:-http://127.0.0.1:19000}"
export IMAGEFORGE_TEST_S3_BUCKET="${IMAGEFORGE_TEST_S3_BUCKET:-imageforge-test}"
export IMAGEFORGE_TEST_S3_ACCESS_KEY="${IMAGEFORGE_TEST_S3_ACCESS_KEY:-codexminio}"
export IMAGEFORGE_TEST_S3_SECRET_KEY="${IMAGEFORGE_TEST_S3_SECRET_KEY:-codexminio123}"
if [[ "$IMAGEFORGE_TEST_S3_ENDPOINT" == "http://127.0.0.1:19000" ]]; then
MINIO_ROOT_USER="$IMAGEFORGE_TEST_S3_ACCESS_KEY" \
MINIO_ROOT_PASSWORD="$IMAGEFORGE_TEST_S3_SECRET_KEY" \
"$MINIO_BIN" server "${WORK_DIR}/minio-data" \
--address 127.0.0.1:19000 >"${WORK_DIR}/minio.log" 2>&1 &
MINIO_PID=$!
wait_for_command MinIO curl --fail --silent \
"${IMAGEFORGE_TEST_S3_ENDPOINT}/minio/health/ready"
fi
"$MC_BIN" alias set imageforge-test \
"$IMAGEFORGE_TEST_S3_ENDPOINT" \
"$IMAGEFORGE_TEST_S3_ACCESS_KEY" \
"$IMAGEFORGE_TEST_S3_SECRET_KEY" >/dev/null
"$MC_BIN" mb --ignore-existing \
"imageforge-test/${IMAGEFORGE_TEST_S3_BUCKET}" >/dev/null
export DATABASE_URL="$IMAGEFORGE_TEST_DATABASE_URL"
export REDIS_URL="$IMAGEFORGE_TEST_REDIS_URL"
export JWT_SECRET="${JWT_SECRET:-imageforge-external-test-jwt-secret}"
export API_KEY_PEPPER="${API_KEY_PEPPER:-imageforge-external-test-api-key-pepper}"
test_log="${WORK_DIR}/external-tests.log"
cargo test --all-targets --locked -- \
--ignored --test-threads=1 --nocapture 2>&1 | tee "$test_log"
expected_summary="test result: ok. ${EXPECTED_EXTERNAL_TESTS} passed; 0 failed; 0 ignored;"
if ! grep --fixed-strings --quiet "$expected_summary" "$test_log"; then
echo "External-state test count mismatch; expected: ${expected_summary}" >&2
exit 1
fi
echo "External-state gate passed: ${EXPECTED_EXTERNAL_TESTS} passed, 0 failed, 0 ignored."