Files
kite/backend/load_tests/locustfile.py
T
curo1305 594eb46efe feat(06-01): add backend/load_tests/ package skeleton with Locust stub (D-04/D-05/D-06)
- backend/load_tests/__init__.py — empty package marker; stops pytest discovery
- backend/load_tests/locustfile.py — DocuVaultUser skeleton (on_start,
  _auth_headers, list_documents, upload_document, refresh_token methods)
  and check_sla SLA listener; all bodies raise NotImplementedError
- No application imports; TEST_EMAIL/TEST_PASSWORD from env vars only
- Full implementation in plan 06-03
2026-06-03 18:37:23 +02:00

73 lines
2.5 KiB
Python

"""Locust load test for DocuVault — D-04, D-05, D-06.
Run:
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
Prerequisites: a user with LOAD_TEST_EMAIL/LOAD_TEST_PASSWORD must exist in the
DB, or on_start will register one automatically (idempotent — 409 is ignored).
Full implementation is in plan 06-03. This skeleton defines the class shape and
SLA listener so downstream CI tooling can import the file without errors.
"""
import os
from locust import HttpUser, between, events, task
TEST_EMAIL = os.environ.get("LOAD_TEST_EMAIL", "loadtest@example.com")
TEST_PASSWORD = os.environ.get("LOAD_TEST_PASSWORD", "Loadtest123!@#")
class DocuVaultUser(HttpUser):
"""Simulated DocuVault end-user.
Scenarios (weighted tasks):
- list_documents (weight 5) — GET /api/documents/
- upload_document (weight 2) — POST /api/documents/upload-url flow
- refresh_token (weight 1) — POST /api/auth/refresh
"""
wait_time = between(0.5, 2.0)
access_token: str = ""
def on_start(self) -> None:
"""Authenticate before running tasks.
Registers the load-test user if it does not exist (409 is silently
ignored), then performs a login to obtain an access token.
"""
raise NotImplementedError("implementation in 06-03")
def _auth_headers(self) -> dict:
"""Return Authorization header dict for authenticated requests."""
raise NotImplementedError("implementation in 06-03")
@task(5)
def list_documents(self) -> None:
"""GET /api/documents/ — highest-frequency task."""
raise NotImplementedError("implementation in 06-03")
@task(2)
def upload_document(self) -> None:
"""Two-step presigned upload: POST /upload-url → PUT MinIO → POST /{id}/confirm."""
raise NotImplementedError("implementation in 06-03")
@task(1)
def refresh_token(self) -> None:
"""POST /api/auth/refresh — rotates the httpOnly refresh cookie."""
raise NotImplementedError("implementation in 06-03")
@events.quitting.add_listener
def check_sla(environment, **kwargs) -> None:
"""Fail the Locust run if SLA thresholds are breached.
Thresholds (from D-06):
- p95 response time > 200 ms → exit code 1
- p99 response time > 500 ms → exit code 1
- error ratio > 1% → exit code 1
"""
raise NotImplementedError("implementation in 06-03")