111 lines
3.6 KiB
JavaScript

/**
* SCENARIO: obstacle-logging.js
* High-frequency obstacle detection log — simulasi YOLO inference results.
*
* WalkGuide menjalankan YOLO pada 5 FPS, setiap obstacle terdeteksi dikirim ke backend.
* Ini endpoint write-heavy terbesar karena obstacle bisa sangat sering.
*
* Target: p95 < 400ms, throughput > 200 req/s pada 50 VUs
*/
import { sleep, check } from "k6";
import {
DEFAULT_THRESHOLDS,
handleSummary,
} from "../modules/metrics-helper.js";
import * as api from "../modules/api-client.js";
import { testData } from "../modules/test-data.js";
export const options = {
scenarios: {
obstacle_burst: {
executor: "ramping-vus",
startVUs: 0,
stages: [
{ duration: "20s", target: 10 },
{ duration: "60s", target: 50 },
{ duration: "120s", target: 50 }, // sustain high load
{ duration: "20s", target: 0 },
],
gracefulRampDown: "10s",
},
},
thresholds: {
...DEFAULT_THRESHOLDS,
walkguide_obstacle_latency_ms: ["p(95)<400", "p(99)<800"],
http_reqs: ["rate>100"], // throughput > 100 req/s
},
};
// ── Per-VU state ──────────────────────────────────────────────────────────────
let vuToken = null;
export default function obstacleLogging() {
// ── Init: register + login ─────────────────────────────────────────────────
if (!vuToken) {
const suffix = `obs_${__VU}_${Date.now()}`;
const payload = testData.userRegisterPayload(suffix);
const res = api.register(payload);
if (res.status === 200) {
const body = api.parseBody(res);
if (body && body.data) vuToken = body.data.accessToken;
}
if (!vuToken) {
sleep(2);
return;
}
// Start walkguide
api.startWalkguide(vuToken);
sleep(0.3);
}
// ── Burst mode: kirim 5 obstacle logs (simulasi 5 FPS selama 1 detik) ──────
const burst = testData.obstacleLogBurst(5);
let allSuccess = true;
for (const obstaclePayload of burst) {
const res = api.logObstacle(vuToken, obstaclePayload);
const ok = check(res, {
"obstacle-log: status 2xx": (r) => r.status >= 200 && r.status < 300,
"obstacle-log: fast response": (r) => r.timings.duration < 600,
});
if (!ok) allSuccess = false;
// Minimal sleep (5 FPS = 200ms per frame)
sleep(0.2);
}
// ── Setiap 10 iteration, kirim obstacle dengan confidence tinggi ────────────
if (__ITER % 10 === 0) {
const criticalObstacle = {
label: "person",
confidence: 0.95,
direction: "CENTER",
estimatedDist: "Very Close",
lat: testData.randomSurabayaCoord().lat,
lng: testData.randomSurabayaCoord().lng,
};
const res = api.logObstacle(vuToken, criticalObstacle);
check(res, {
"critical-obstacle: 2xx": (r) => r.status >= 200 && r.status < 300,
"critical-obstacle: fast": (r) => r.timings.duration < 300,
});
}
// ── Think time minimal — obstacle logging adalah high-frequency ─────────────
sleep(testData.randomFloat(0.1, 0.5, 1));
}
export function setup() {
const res = api.ping();
if (res.status !== 200)
throw new Error(`Backend not reachable: ${res.status}`);
console.log("✅ Obstacle logging stress test starting.");
}
export { handleSummary };