111 lines
3.6 KiB
JavaScript
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 };
|