Files
OpenFrame/docker-compose.test.yml
T

160 lines
6.0 KiB
YAML

# Disposable infrastructure for the automated test suites. Everything here is
# on non-default ports so it can never collide with the dev stack in
# docker-compose.yml.
#
# The `openframe-test` network is declared external so that the test runner
# container can reach these services by service name. Create it once with:
# podman network create openframe-test
#
# Two tiers, split by compose profile:
#
# (no profile) postgres-test. Needed by the `api` Vitest project and by the
# Playwright suite. Started by `bun run test:db:up`.
# e2e minio-test + minio-test-init (real S3-compatible storage for
# the direct video upload flow) and app-test (the app under
# test). Started by `scripts/test.sh e2e`.
#
# Usage:
# podman compose -f docker-compose.test.yml up -d --wait postgres-test
# podman run --rm --network openframe-test -v "$PWD":/workspace:z -w /workspace \
# docker.io/oven/bun:alpine sh -c "bun run test:api"
#
# podman compose -f docker-compose.test.yml --profile e2e up -d --wait \
# postgres-test minio-test
# scripts/test.sh e2e
#
# app-test is opt-in and only needed when you want the app under test to run as
# a container instead of being started by Playwright's own `webServer`:
# podman compose -f docker-compose.test.yml --profile e2e up -d --wait app-test
# E2E_BASE_URL=http://app-test:3100 scripts/test.sh e2e
services:
postgres-test:
image: postgres:16-alpine
container_name: openframe-postgres-test
environment:
POSTGRES_USER: openframe
POSTGRES_PASSWORD: openframe
POSTGRES_DB: openframe_test
# fsync off: the data directory is a tmpfs that is thrown away anyway, so
# durability buys nothing and costs a lot of wall clock time.
command: ['postgres', '-c', 'fsync=off', '-c', 'full_page_writes=off']
tmpfs:
- /var/lib/postgresql/data
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U openframe -d openframe_test']
interval: 2s
timeout: 3s
retries: 30
ports:
- '127.0.0.1:55432:5432'
networks:
- openframe-test
# S3-compatible object storage for the direct video upload path. The browser
# PUTs the file straight at this endpoint with a presigned URL, so the
# hostname the app signs for has to be the hostname the browser resolves:
# both the Playwright container and the app under test are on this network,
# so both use `minio-test:9000`. MinIO's default CORS policy allows every
# origin and exposes ETag, which is exactly what lib/client/r2-video-upload.ts
# needs, so no bucket CORS configuration is involved.
minio-test:
profiles: ['e2e']
image: quay.io/minio/minio@sha256:14cea493d9a34af32f524e538b8346cf79f3321eff8e708c1e2960462bd8936e
container_name: openframe-minio-test
command: ['server', '/data', '--console-address', ':9001']
environment:
MINIO_ROOT_USER: openframe
MINIO_ROOT_PASSWORD: openframe-test-secret
# lib/r2.ts builds its S3 client with `region: 'auto'`, so MinIO has to
# accept that region name in the SigV4 signature.
MINIO_REGION_NAME: auto
# Same reasoning as postgres-test: the data is disposable, so keep it in RAM.
tmpfs:
- /data
healthcheck:
test: ['CMD', 'mc', 'ready', 'local']
interval: 2s
timeout: 3s
retries: 30
ports:
- '127.0.0.1:59000:9000'
- '127.0.0.1:59001:9001'
networks:
- openframe-test
# Creates the bucket. Nothing at runtime does: ensureR2BucketExists() lives in
# scripts/self-host-bootstrap.ts, not on the request path, so a missing bucket
# would surface as a presigned PUT returning NoSuchBucket.
minio-test-init:
profiles: ['e2e']
image: quay.io/minio/minio@sha256:14cea493d9a34af32f524e538b8346cf79f3321eff8e708c1e2960462bd8936e
container_name: openframe-minio-test-init
depends_on:
minio-test:
condition: service_healthy
entrypoint:
- sh
- -c
- >
mc alias set testminio http://minio-test:9000 openframe openframe-test-secret &&
mc mb --ignore-existing testminio/openframe-test &&
mc ls testminio
networks:
- openframe-test
# The app under test, for the case where you do not want Playwright to start
# it. This is the same command playwright.config.ts uses for its `webServer`,
# run against the mounted working tree so `.next` stays warm between runs.
#
# NODE_ENV is left to `next build` / `next start` (production). The runtime
# values below are duplicated from .env.test.example on purpose: `next build`
# never loads `.env.test`, and NEXT_PUBLIC_APP_URL is inlined at build time.
app-test:
profiles: ['e2e']
image: docker.io/oven/bun:alpine
container_name: openframe-app-test
depends_on:
postgres-test:
condition: service_healthy
minio-test:
condition: service_healthy
working_dir: /workspace
volumes:
- .:/workspace:z
environment:
DATABASE_URL: postgresql://openframe:openframe@postgres-test:5432/openframe_test?schema=public
NEXTAUTH_URL: http://app-test:3100
NEXTAUTH_SECRET: test-secret-not-used-for-anything-real
NEXT_PUBLIC_APP_URL: http://app-test:3100
OPENFRAME_ENABLE_STRIPE: 'true'
STRIPE_SECRET_KEY: sk_test_openframe_dummy
STRIPE_PRICE_ID: price_test_openframe_dummy
OPENFRAME_REQUIRE_INVITE_CODE: 'true'
INVITE_CODE: test-invite
TRUSTED_PROXY_MODE: none
OPENFRAME_ENABLE_S3_VIDEO_UPLOADS: 'true'
OPENFRAME_ENABLE_BUNNY_UPLOADS: 'false'
R2_ENDPOINT: http://minio-test:9000
R2_ACCESS_KEY_ID: openframe
R2_SECRET_ACCESS_KEY: openframe-test-secret
R2_BUCKET_NAME: openframe-test
PORT: '3100'
command:
- sh
- -c
- './node_modules/.bin/next build && ./node_modules/.bin/next start -p 3100 -H 0.0.0.0'
healthcheck:
test: ['CMD-SHELL', 'wget -q -O /dev/null http://127.0.0.1:3100/login']
interval: 5s
timeout: 5s
retries: 120
ports:
- '127.0.0.1:3100:3100'
networks:
- openframe-test
networks:
openframe-test:
external: true