Files
AI-Horde/tests/docker-compose.yml
tazlin 415277541a feat: build out test framework, CI test stack, and load-surfaced hardening
Establishes additional unit/integration testing, the CI to run it, and the runtime fixes those tests surfaced

Testing
- Add unit (ORM/function) and integration (API route) tiers over a shared dependency runtime that auto-provisions Postgres, Redis, and S3-compatible object storage (Garage) via testcontainers, with an external-deps mode.
- Add fixtures/factories plus coverage for user roles, kudos pricing, worker.can_generate, countermeasures, WP activation, and adversarial malformed-input route sweeps.
- Modularize the locust suite into locustsuite/ and add a stability-only smoke gate (check_smoke_results.py).

CI / tooling
- Rework pr/main/trusted-fork/publish workflows around composite actions (setup-test-python, start-test-stack) and a Dockerized PG+Redis+Garage stack.
- Bump the Python floor to 3.12 (+3.13 matrix) and consolidate on uv.

Runtime hardening
- Make telemetry activation opt-in (telemetry_enabled): the image stays telemetry-capable but a bare server.py is inert unless an OTLP endpoint or AI_HORDE_TELEMETRY_ENABLED is set.
- Turn NUL bytes, out-of-range user ids, and duplicate worker names into clean 4xx responses instead of session-poisoning 500s.
- Fix get_anon() to resolve the anon account by oauth_id (re-enabling the kudos-transfer guards); shrink and instrument the SQLAlchemy pool (15/5) to expose connection-hold inefficiency as pool timeouts rather than PG refusals.
2026-07-05 13:36:59 -04:00

83 lines
3.1 KiB
YAML

# SPDX-FileCopyrightText: 2026 Tazlin <tazlin.on.github@gmail.com>
#
# SPDX-License-Identifier: AGPL-3.0-or-later
# Optional long-lived Postgres + Redis + Garage stack for local unit/integration
# work when you want to provide external deps instead of letting pytest manage
# them with testcontainers.
#
# Brought up locally with: docker compose -f tests/docker-compose.yml up -d
#
# Host-side published ports are configurable so the stack can coexist with
# other local services:
# AI_HORDE_TEST_POSTGRES_PORT
# AI_HORDE_TEST_REDIS_PORT
# AI_HORDE_TEST_GARAGE_S3_PORT
# AI_HORDE_TEST_GARAGE_ADMIN_PORT
# AI_HORDE_TEST_GARAGE_RPC_PORT
#
# One-command local image-test flow against an external long-lived stack:
# bash tests/run_with_test_stack.sh -- .venv/bin/python -m pytest tests/integration/test_image.py -q -rs
#
# To force pytest to use caller-provided services instead of auto-provisioning,
# either run:
# AI_HORDE_TEST_DEPS_MODE=external pytest tests/integration/ -q -rs
# or let the wrapper handle stack-up + bootstrap + env injection for one command.
#
# Pytest CI uses the shared auto-provisioning runtime. Server-backed CI smoke
# jobs use this compose stack because the server process is not owned by pytest.
services:
postgres:
image: ghcr.io/haidra-org/ai-horde-postgres:latest
command: ["postgres", "-c", "cron.database_name=${AI_HORDE_TEST_POSTGRES_DB:-postgres}"]
environment:
POSTGRES_USER: ${AI_HORDE_TEST_POSTGRES_USER:-postgres}
POSTGRES_PASSWORD: ${AI_HORDE_TEST_POSTGRES_PASSWORD:-postgres}
POSTGRES_DB: ${AI_HORDE_TEST_POSTGRES_DB:-postgres}
POSTGRES_HOST_AUTH_METHOD: trust
ports:
- "${AI_HORDE_TEST_POSTGRES_BIND:-127.0.0.1}:${AI_HORDE_TEST_POSTGRES_PORT:-5432}:5432"
healthcheck:
test: ["CMD", "pg_isready", "-U", "${AI_HORDE_TEST_POSTGRES_USER:-postgres}"]
interval: 5s
timeout: 3s
retries: 10
redis:
image: redis
ports:
- "${AI_HORDE_TEST_REDIS_BIND:-127.0.0.1}:${AI_HORDE_TEST_REDIS_PORT:-6379}:6379"
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 10
garage:
image: dxflrs/garage:v2.1.0
# Garage reads its rpc/admin/metrics secrets from this git-ignored file,
# generated by tests/garage/ensure_test_credentials.sh. Run that script (or
# use tests/run_with_test_stack.sh, which does it for you) before bringing
# the stack up.
env_file:
- path: ./garage/.test-credentials.env
required: false
volumes:
- ./garage/garage.toml:/etc/garage.toml:ro
- garage_meta:/var/lib/garage/meta
- garage_data:/var/lib/garage/data
ports:
- "${AI_HORDE_TEST_GARAGE_S3_BIND:-127.0.0.1}:${AI_HORDE_TEST_GARAGE_S3_PORT:-3900}:3900"
- "${AI_HORDE_TEST_GARAGE_ADMIN_BIND:-127.0.0.1}:${AI_HORDE_TEST_GARAGE_ADMIN_PORT:-3903}:3903"
- "${AI_HORDE_TEST_GARAGE_RPC_BIND:-127.0.0.1}:${AI_HORDE_TEST_GARAGE_RPC_PORT:-3901}:3901"
healthcheck:
test: ["CMD", "/garage", "-c", "/etc/garage.toml", "status"]
interval: 5s
timeout: 3s
retries: 10
volumes:
garage_meta:
garage_data: