// k6 load-test: tenant-scoped mutating path (`POST /v1/entities/:slug/rows`). // // Profile: 30 VUs for 30s. Mutating writes are bounded by database write // contention, idempotency-key bookkeeping, and audit logging — so the // concurrency is intentionally lower than the read path. The p(99) latency // budget covers transactional write + audit + queue enqueue. // // Run: // K6_TARGET_URL=http://localhost:3000 \ // LOAD_TENANT_API_KEY=tnk_live_xxx \ // k6 run tests/load/api-mutating.js // // Required env: // LOAD_TENANT_API_KEY tenant-scoped API key for the test tenant // Optional env: // LOAD_ENTITY_SLUG entity slug to write to (default: load-test-entity) import http from "k6/http"; import { check, group } from "k6"; export const options = { scenarios: { api_mutating: { executor: "constant-vus", vus: 30, duration: "30s", tags: { suite: "api-mutating" }, }, }, thresholds: { http_req_failed: ["rate<0.02"], http_req_duration: ["p(99)<600"], }, discardResponseBodies: true, }; const TARGET_URL = __ENV.K6_TARGET_URL || "http://localhost:3000"; const TENANT_API_KEY = __ENV.LOAD_TENANT_API_KEY || "tnk_load_test_key"; const ENTITY_SLUG = __ENV.LOAD_ENTITY_SLUG || "load-test-entity"; export default function apiMutatingScenario() { group("api-mutating", function () { const payload = JSON.stringify({ data: { // Deterministic, non-PII synthetic payload — load tests must not seed // customer-shaped data into the target environment. label: `load-test-row-${__VU}-${__ITER}`, value: __ITER, }, }); const params = { headers: { accept: "application/json", "content-type": "application/json", authorization: `Bearer ${TENANT_API_KEY}`, // Idempotency key keeps re-runs from accumulating duplicate rows when // the target environment supports the standard idempotency contract. "idempotency-key": `load-${__VU}-${__ITER}`, }, tags: { name: "api-mutating" }, }; const res = http.post(`${TARGET_URL}/v1/entities/${ENTITY_SLUG}/rows`, payload, params); check(res, { "status is 2xx, 401, 404, or 409": (r) => (r.status >= 200 && r.status < 300) || r.status === 401 || r.status === 404 || r.status === 409, }); }); }