mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-08-31 08:11:27 +02:00
Adds a matrix entry that starts a SQLite-backed Francis runtime next to Pocket ID and points FRANCIS_HOST at it, so the same Playwright suite runs with the actor state, alarms, and placement owned by the runtime instead of embedded in Pocket ID. The suite needs no changes to work in that topology: the E2E reset seeds every actor through actors.Service() and deliberately leaves the actor store alone, so it behaves the same whichever side owns it. The CLI spec is the exception, since export and import are the two commands whose behaviour genuinely differs. It now picks the right Compose file, expects an export to carry no francis.bin, feeds the import an archive without one, and gains a case asserting that an archive that does carry one is refused. The runtime is reached over the Compose network on its UDP port, so nothing is published to the host, and the cluster CA is left unpinned, which exercises the same trust-on-first-use path an operator gets without FRANCIS_CA. Pinning is covered by a unit test instead.
223 lines
7.8 KiB
YAML
223 lines
7.8 KiB
YAML
name: E2E Tests
|
|
on:
|
|
push:
|
|
branches: [ main ]
|
|
paths-ignore:
|
|
- "docs/**"
|
|
- "**.md"
|
|
- ".github/**"
|
|
pull_request:
|
|
branches: [ main, breaking/** ]
|
|
paths-ignore:
|
|
- "docs/**"
|
|
- "**.md"
|
|
- ".github/**"
|
|
|
|
permissions:
|
|
contents: read
|
|
actions: write
|
|
id-token: write
|
|
|
|
jobs:
|
|
test:
|
|
if: github.event.pull_request.head.ref != 'i18n_crowdin'
|
|
runs-on: depot-ubuntu-24.04-32
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
# "francis" selects where the actor runtime lives: embedded in Pocket ID, or a standalone runtime it connects to
|
|
include:
|
|
- db: sqlite
|
|
storage: filesystem
|
|
francis: embedded
|
|
- db: postgres
|
|
storage: filesystem
|
|
francis: embedded
|
|
- db: sqlite
|
|
storage: s3
|
|
francis: embedded
|
|
- db: sqlite
|
|
storage: database
|
|
francis: embedded
|
|
- db: postgres
|
|
storage: database
|
|
francis: embedded
|
|
- db: sqlite
|
|
storage: filesystem
|
|
francis: remote
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v6
|
|
|
|
- name: Setup pnpm
|
|
uses: pnpm/action-setup@v6
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v6.5.0
|
|
with:
|
|
node-version: 24
|
|
cache: "pnpm"
|
|
|
|
- name: Set up Depot CLI
|
|
uses: depot/setup-action@v1
|
|
|
|
- name: Set up Depot Docker builder
|
|
run: depot configure-docker
|
|
|
|
- name: Cache Playwright Browsers
|
|
uses: actions/cache@v5
|
|
id: playwright-cache
|
|
with:
|
|
path: ~/.cache/ms-playwright
|
|
key: ${{ runner.os }}-playwright-${{ hashFiles('pnpm-lock.yaml') }}
|
|
|
|
- name: Cache PostgreSQL Docker image
|
|
uses: actions/cache@v5
|
|
id: postgres-cache
|
|
with:
|
|
path: /tmp/postgres-image.tar
|
|
key: postgres-17-${{ runner.os }}
|
|
- name: Pull and save PostgreSQL image
|
|
if: matrix.db == 'postgres' && steps.postgres-cache.outputs.cache-hit != 'true'
|
|
run: |
|
|
docker pull postgres:17
|
|
docker save postgres:17 > /tmp/postgres-image.tar
|
|
- name: Load PostgreSQL image
|
|
if: matrix.db == 'postgres' && steps.postgres-cache.outputs.cache-hit == 'true'
|
|
run: docker load < /tmp/postgres-image.tar
|
|
|
|
- name: Cache SCIM Test Server Docker image
|
|
uses: actions/cache@v5
|
|
id: scim-cache
|
|
with:
|
|
path: /tmp/scim-test-server-image.tar
|
|
key: scim-test-server-${{ runner.os }}
|
|
- name: Pull and save SCIM Test Server image
|
|
if: steps.scim-cache.outputs.cache-hit != 'true'
|
|
run: |
|
|
docker pull ghcr.io/pocket-id/scim-test-server
|
|
docker save ghcr.io/pocket-id/scim-test-server > /tmp/scim-test-server-image.tar
|
|
- name: Load SCIM Test Server image
|
|
if: steps.scim-cache.outputs.cache-hit == 'true'
|
|
run: docker load < /tmp/scim-test-server-image.tar
|
|
|
|
- name: Cache Localstack S3 Docker image
|
|
if: matrix.storage == 's3'
|
|
uses: actions/cache@v5
|
|
id: s3-cache
|
|
with:
|
|
path: /tmp/localstack-s3-image.tar
|
|
key: localstack-4.14.0-${{ runner.os }}
|
|
- name: Pull and save Localstack S3 image
|
|
if: matrix.storage == 's3' && steps.s3-cache.outputs.cache-hit != 'true'
|
|
run: |
|
|
docker pull localstack/localstack:4.14.0
|
|
docker save localstack/localstack:4.14.0 > /tmp/localstack-s3-image.tar
|
|
- name: Load Localstack S3 image
|
|
if: matrix.storage == 's3' && steps.s3-cache.outputs.cache-hit == 'true'
|
|
run: docker load < /tmp/localstack-s3-image.tar
|
|
|
|
- name: Resolve Francis runtime image
|
|
if: matrix.francis == 'remote'
|
|
id: francis-image
|
|
working-directory: ./tests/setup
|
|
# The Compose file is the single source of truth for the version, so the cache key follows it automatically
|
|
run: |
|
|
IMAGE=$(grep -oP '(?<=image: )ghcr\.io/italypaleale/francis:\S+' docker-compose-francis.yml)
|
|
echo "image=$IMAGE" >> "$GITHUB_OUTPUT"
|
|
echo "key=$(echo "$IMAGE" | tr '/:' '--')" >> "$GITHUB_OUTPUT"
|
|
- name: Cache Francis runtime Docker image
|
|
if: matrix.francis == 'remote'
|
|
uses: actions/cache@v5
|
|
id: francis-cache
|
|
with:
|
|
path: /tmp/francis-image.tar
|
|
key: ${{ steps.francis-image.outputs.key }}-${{ runner.os }}
|
|
- name: Pull and save Francis runtime image
|
|
if: matrix.francis == 'remote' && steps.francis-cache.outputs.cache-hit != 'true'
|
|
run: |
|
|
docker pull "${{ steps.francis-image.outputs.image }}"
|
|
docker save "${{ steps.francis-image.outputs.image }}" > /tmp/francis-image.tar
|
|
- name: Load Francis runtime image
|
|
if: matrix.francis == 'remote' && steps.francis-cache.outputs.cache-hit == 'true'
|
|
run: docker load < /tmp/francis-image.tar
|
|
|
|
- name: Install test dependencies
|
|
run: pnpm --filter pocket-id-tests install --frozen-lockfile
|
|
|
|
- name: Install Playwright Browsers
|
|
working-directory: ./tests
|
|
if: steps.playwright-cache.outputs.cache-hit != 'true'
|
|
run: pnpm exec playwright install --with-deps chromium
|
|
|
|
- name: Run Docker containers
|
|
working-directory: ./tests/setup
|
|
run: |
|
|
DOCKER_COMPOSE_FILE=docker-compose.yml
|
|
|
|
cat > .env <<EOF
|
|
FILE_BACKEND=${{ matrix.storage }}
|
|
SCIM_SERVICE_PROVIDER_URL=http://localhost:18123/v2
|
|
SCIM_SERVICE_PROVIDER_URL_INTERNAL=http://scim-test-server:8080/v2
|
|
EOF
|
|
|
|
if [ "${{ matrix.francis }}" = "remote" ]; then
|
|
DOCKER_COMPOSE_FILE=docker-compose-francis.yml
|
|
elif [ "${{ matrix.db }}" = "postgres" ]; then
|
|
DOCKER_COMPOSE_FILE=docker-compose-postgres.yml
|
|
elif [ "${{ matrix.storage }}" = "s3" ]; then
|
|
DOCKER_COMPOSE_FILE=docker-compose-s3.yml
|
|
fi
|
|
|
|
docker compose -f "$DOCKER_COMPOSE_FILE" up -d --build
|
|
|
|
{
|
|
LOG_FILE="/tmp/backend.log"
|
|
while true; do
|
|
CID=$(docker compose -f "$DOCKER_COMPOSE_FILE" ps -q pocket-id)
|
|
if [ -n "$CID" ]; then
|
|
echo "[$(date)] Attaching logs for $CID" >> "$LOG_FILE"
|
|
docker logs -f --since=0 "$CID" >> "$LOG_FILE" 2>&1
|
|
else
|
|
echo "[$(date)] Container not yet running…" >> "$LOG_FILE"
|
|
fi
|
|
sleep 1
|
|
done
|
|
} &
|
|
|
|
if [ "${{ matrix.francis }}" = "remote" ]; then
|
|
docker compose -f "$DOCKER_COMPOSE_FILE" logs -f --no-log-prefix francis-runtime > /tmp/francis-runtime.log 2>&1 &
|
|
fi
|
|
|
|
- name: Run Playwright tests
|
|
working-directory: ./tests
|
|
run: pnpm exec playwright test
|
|
|
|
- name: Upload Test Report
|
|
uses: actions/upload-artifact@v7
|
|
if: always() && github.event.pull_request.head.ref != 'i18n_crowdin'
|
|
with:
|
|
name: playwright-report-${{ matrix.db }}-${{ matrix.storage }}-francis-${{ matrix.francis }}
|
|
path: tests/.report
|
|
include-hidden-files: true
|
|
retention-days: 15
|
|
|
|
- name: Upload Backend Test Report
|
|
uses: actions/upload-artifact@v7
|
|
if: always() && github.event.pull_request.head.ref != 'i18n_crowdin'
|
|
with:
|
|
name: backend-${{ matrix.db }}-${{ matrix.storage }}-francis-${{ matrix.francis }}
|
|
path: /tmp/backend.log
|
|
include-hidden-files: true
|
|
retention-days: 15
|
|
|
|
- name: Upload Francis Runtime Report
|
|
uses: actions/upload-artifact@v7
|
|
if: always() && matrix.francis == 'remote' && github.event.pull_request.head.ref != 'i18n_crowdin'
|
|
with:
|
|
name: francis-runtime-${{ matrix.db }}-${{ matrix.storage }}
|
|
path: /tmp/francis-runtime.log
|
|
include-hidden-files: true
|
|
retention-days: 15
|