import http from 'k6/http'; import { check, sleep } from 'k6'; import { Rate } from 'k6/metrics'; // Custom metric to explicitly track the percentage of unauthorized requests const unauthorizedRate = new Rate('unauthorized_rate'); export const options = { // Test scenario: 1000 virtual users executing 1 iteration each vus: 1000, iterations: 1000, // We can also define thresholds for CI/CD pipelines thresholds: { 'http_req_duration': ['p(95)<500'], // 95% of requests must complete below 500ms 'unauthorized_rate': ['rate==0'], // 0% unauthorized errors (strict constraint) }, }; const BASE_URL = 'http://localhost:5064'; export default function () { // --- Setup / Login Phase --- // Each VU initializes its own secure session and receives a unique token. const initRes = http.post(`${BASE_URL}/Init`); check(initRes, { 'init status is 200': (r) => r.status === 200, 'init returned sequenceId': (r) => r.json('initialSequenceId') !== undefined, }); if (initRes.status !== 200) { return; // Stop VU if init fails to prevent cascading errors } // Local state for the virtual user let currentToken = initRes.json('initialSequenceId'); // --- Stateful Mutation Phase --- // The VU performs 50 sequential requests. In a real scenario, these would be GET/POST/PUT. for (let i = 0; i < 50; i++) { const res = http.get(`${BASE_URL}/Secure/data`, { headers: { 'X-Auth-Seq': currentToken, }, }); const success = check(res, { 'status is 200': (r) => r.status === 200, 'has X-Next-Seq header': (r) => r.headers['X-Next-Seq'] !== undefined, }); if (res.status === 401) { unauthorizedRate.add(1); console.error(`VU ${__VU} experienced sequence break on iteration ${i}! Received 401.`); break; // The chain is broken, stop further requests } else { unauthorizedRate.add(0); } if (success) { // Critical Step: Read X-Next-Seq from Response and save it for the next request in the chain currentToken = res.headers['X-Next-Seq']; } // Simulate real-world delay between operations (optional, but realistic) // sleep(Math.random() * 0.1); } }