// k6 run k6/poll-ack-smoke.js import http from 'k6/http'; import { check, sleep } from 'k6'; import { Trend, Counter } from 'k6/metrics'; const latency = new Trend('api_latency'); const throttles = new Counter('rate_limits'); export const options = { vus: 5, duration: '1m' }; const BASE = __ENV.API || 'https://api.endorser.ch'; const JWT = __ENV.JWT || 'REDACTED'; function idem() { return crypto.randomUUID(); } export default function () { // POLL (simulate occasional 429 / 5xx via test env or chaos flag) const pollRes = http.post( `${BASE}/api/v2/report/plansLastUpdatedBetween`, JSON.stringify({ planIds: ['demo1','demo2'], limit: 3, afterId: __ITER === 0 ? undefined : __ENV.AFTER }), { headers: { 'Authorization': `Bearer ${JWT}`, 'Content-Type': 'application/json', 'X-Idempotency-Key': idem(), 'X-Client-Version': 'TimeSafari-Plugin/1.0.0' }, tags: { endpoint: 'poll' } } ); latency.add(pollRes.timings.duration); if (pollRes.status === 429) throttles.add(1); check(pollRes, { 'poll: 2xx or 429/5xx with JSON': (r) => [200,429,500,503].includes(r.status) && r.headers['Content-Type']?.includes('application/json'), }); if (pollRes.status === 200) { const body = pollRes.json(); const ids = (body?.data || []).map(x => x?.planSummary?.jwtId).filter(Boolean); // ACK if (ids.length) { const ackRes = http.post( `${BASE}/api/v2/plans/acknowledge`, JSON.stringify({ acknowledgedJwtIds: ids, acknowledgedAt: new Date().toISOString(), clientVersion: 'TimeSafari-Plugin/1.0.0' }), { headers: { 'Authorization': `Bearer ${JWT}`, 'Content-Type': 'application/json', 'X-Idempotency-Key': idem() }, tags: { endpoint: 'ack' } } ); check(ackRes, { 'ack: success/idem': (r) => [200, 409].includes(r.status) }); } } sleep(1); }