/** * SCENARIO: auth-flow.js * Register → Login → Refresh Token → Logout flow * * Tujuan: Stress test auth endpoints yang dipakai setiap user saat app dibuka. * Target: p95 auth latency < 800ms, error rate < 1% */ import { sleep, check } from "k6"; import { DEFAULT_THRESHOLDS, handleSummary, pickThresholds, } from "../modules/metrics-helper.js"; import * as api from "../modules/api-client.js"; import { testData } from "../modules/test-data.js"; import { registerAndLogin, doRefreshToken } from "../modules/auth-helper.js"; const RUN_ID = __ENV.RUN_ID || `${Date.now()}`; // ── Konfigurasi test — override via --config atau env ─────────────────────── export const options = { scenarios: { auth_flow: { executor: "ramping-vus", startVUs: 0, stages: [ { duration: "30s", target: 10 }, // warm-up { duration: "60s", target: 30 }, // ramp-up { duration: "60s", target: 30 }, // sustain { duration: "30s", target: 0 }, // ramp-down ], gracefulRampDown: "15s", }, }, thresholds: pickThresholds( __ENV.BENCH_PROFILE === "local" ? { walkguide_auth_latency_ms: ["p(95)<35000", "p(99)<40000"] } : { ...DEFAULT_THRESHOLDS, walkguide_auth_latency_ms: ["p(95)<800", "p(99)<1500"], }, ), }; // ── Main VU function ────────────────────────────────────────────────────────── export default function authFlow() { const vuId = __VU; // ── Step 1: Register user baru (setiap VU punya unique email) ─────────────── const role = vuId % 2 === 0 ? "ROLE_GUARDIAN" : "ROLE_USER"; const suffix = `${RUN_ID}_${vuId}_${__ITER}`; const payload = role === "ROLE_GUARDIAN" ? testData.guardianRegisterPayload(suffix) : testData.userRegisterPayload(suffix); const regRes = api.register(payload); check(regRes, { "register: status 200": (r) => r.status === 200, "register: has accessToken": (r) => { const b = api.parseBody(r); return b && b.data && !!b.data.accessToken; }, }); let tokens = null; if (regRes.status === 200) { const body = api.parseBody(regRes); if (body && body.data) tokens = body.data; } sleep(0.5); // ── Step 2: Login ulang dengan credentials yang sama ──────────────────────── const loginRes = api.login(payload.email, payload.password); check(loginRes, { "login: status 200": (r) => r.status === 200, "login: accessToken set": (r) => { const b = api.parseBody(r); return b && b.data && !!b.data.accessToken; }, "login: refreshToken set": (r) => { const b = api.parseBody(r); return b && b.data && !!b.data.refreshToken; }, "login: role correct": (r) => { const b = api.parseBody(r); return b && b.data && b.data.role === role; }, }); if (loginRes.status === 200) { const body = api.parseBody(loginRes); if (body && body.data) tokens = body.data; } sleep(0.3); // ── Step 3: Refresh token (simulasi token expire) ─────────────────────────── if (tokens && tokens.refreshToken) { const refreshRes = api.refreshToken(tokens.refreshToken); check(refreshRes, { "refresh: status 200": (r) => r.status === 200, "refresh: new accessToken": (r) => { const b = api.parseBody(r); return b && b.data && !!b.data.accessToken; }, }); // Update access token if (refreshRes.status === 200) { const body = api.parseBody(refreshRes); if (body && body.data) tokens.accessToken = body.data.accessToken; } } sleep(0.3); // ── Step 4: Update FCM token (dilakukan tiap login di production) ─────────── if (tokens && tokens.accessToken) { const fakeFcm = `fcm_${Math.random().toString(36).slice(2, 30)}:APA91b${Math.random().toString(36).slice(2, 50)}`; const fcmRes = api.updateFcmToken(tokens.accessToken, fakeFcm); check(fcmRes, { "fcm-token: status 2xx": (r) => r.status >= 200 && r.status < 300, }); } sleep(0.2); // ── Step 5: Logout ────────────────────────────────────────────────────────── if (tokens && tokens.accessToken) { const logoutRes = api.logout(tokens.accessToken); check(logoutRes, { "logout: status 2xx": (r) => r.status >= 200 && r.status < 300, }); } // ── Think time: user nyata butuh beberapa detik antar aksi ────────────────── sleep(testData.randomFloat(0.5, 1.5, 1)); } // ── Health check sebelum test dimulai ──────────────────────────────────────── export function setup() { const res = api.ping(); if (res.status !== 200) { throw new Error( `Backend tidak reachable. Ping returned ${res.status}. URL: ${__ENV.BASE_URL || "http://202.46.28.160:8080"}`, ); } console.log("✅ Backend reachable. Auth flow test starting."); } export { handleSummary };