"""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")