Files
kite/backend/load_tests
curo1305andClaude Sonnet 4.6 0fa23f5211 fix(auth): catch IntegrityError on register race → 409 + locustfile pre-auth rewrite
Two fixes from manual SLA validation (06-LOCUST-01):

1. backend/api/auth.py: concurrent registrations with same email/handle caused
   UniqueViolation to bubble as 500. Now wraps session.commit() in try/except
   IntegrityError → 409 Conflict. Regression covered by existing auth API tests.

2. backend/load_tests/locustfile.py: rewrote from single-shared-account to
   pre-authenticated unique accounts. New @events.test_start listener creates
   50 accounts in 9-user batches (65 s pause between batches to stay under
   10 req/min IP rate limit). Added min-request guard to SLA check so a
   run-time-consumed-by-setup result never silently "passes".
   Run command updated to --run-time 12m.

Known open issue: _account_key in services/rate_limiting.py falls back to IP
when request.state.current_user is not yet set (rate limiter key_func runs
before handler body). Fix: extract sub from JWT directly. See next session.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 12:25:04 +02:00
..

DocuVault Load Tests

Phase 6 load test suite targeting the D-04/D-05/D-06 SLA requirements.

Prerequisites

  1. Install load-test dependencies (host or dedicated venv — not the production container):

    pip install -r backend/requirements-dev.txt
    
  2. Start the full stack:

    docker compose up
    

    Backend, PostgreSQL, and MinIO must all be healthy before running.

Running the load test

locust --headless \
       --users 50 \
       --spawn-rate 10 \
       --run-time 5m \
       --host http://localhost:8000 \
       --csv backend/load_tests/results \
       -f backend/load_tests/locustfile.py

Exit code 0 = SLA targets met. Exit code 1 = at least one threshold breached.

Environment variables

Variable Default Description
LOAD_TEST_EMAIL loadtest@example.com Email used to register/login the load-test user
LOAD_TEST_PASSWORD Loadtest123!@# Password for the load-test account (meets AUTH-01 strength rules)

Override before running:

LOAD_TEST_EMAIL=mytest@staging.example.com \
LOAD_TEST_PASSWORD='MyS3cure!Pass' \
locust --headless ...

SLA thresholds (D-06)

Metric Threshold On breach
p95 response time < 200 ms exit code 1
p99 response time < 500 ms exit code 1
Error ratio ≤ 1% exit code 1

Task weights (D-05 realistic session)

Task Weight Endpoint
List documents 5 GET /api/documents/
Get document 3 GET /api/documents/{id}
Upload document 2 POST /api/documents/upload (direct multipart, target_backend=minio)
Refresh token 1 POST /api/auth/refresh

Credential strategy

on_start() uses self-bootstrapping (Option A): it calls POST /api/auth/register first (idempotent — 409 is silently ignored if the user already exists), then logs in. No manual seeding step required.

Cleanup

Remove the load-test user from the database when no longer needed:

docker compose exec postgres psql -U docuvault -c \
    "DELETE FROM users WHERE email='loadtest@example.com';"

Results

CSV files are written to backend/load_tests/results_*.csv by the --csv flag. These files are gitignored. To view a summary after a headless run, add --html backend/load_tests/report.html.

Notes

  • Load tests run outside the production container — install on the host or a test venv.
  • Do not run against a production URL without an explicit --host override and stakeholder sign-off.
  • The synthetic upload file (_FAKE_PDF) is a minimal valid PDF — it will be stored in MinIO during the run and cleared when the load-test user is deleted.