Files
goodgo-platform/load-tests/scripts/search.js
Ho Ngoc Hai 99fbc1aaca perf(load-tests): run K6 baseline and fix search.js URLSearchParams bug
- Fix search.js: replace URLSearchParams (unsupported in K6) with string interpolation
- Add baseline performance report with latency benchmarks across all 4 suites
- Add load-tests/results/*.json to .gitignore (large raw output files)

Note: pre-existing test failure in create-listing.handler.spec.ts (eventBus.publish mock) — unrelated to this change.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-09 09:29:20 +07:00

88 lines
2.6 KiB
JavaScript

import http from 'k6/http';
import { check, sleep } from 'k6';
import { Trend } from 'k6/metrics';
import { BASE_URL, SLA_THRESHOLDS } from '../lib/config.js';
const textSearchDuration = new Trend('text_search_duration', true);
const geoSearchDuration = new Trend('geo_search_duration', true);
export const options = {
scenarios: {
search_load: {
executor: 'ramping-vus',
startVUs: 0,
stages: [
{ duration: '30s', target: 50 },
{ duration: '2m', target: 200 }, // peak: 200 concurrent
{ duration: '30s', target: 0 },
],
gracefulRampDown: '10s',
},
},
thresholds: {
...SLA_THRESHOLDS,
text_search_duration: ['p(95)<500'],
geo_search_duration: ['p(95)<500'],
},
};
const TEXT_QUERIES = [
'căn hộ',
'nhà phố quận 1',
'đất nền',
'chung cư',
'biệt thự',
'apartment Ho Chi Minh',
'house Hanoi',
];
const GEO_SEARCHES = [
{ lat: 10.7769, lng: 106.7009, radius: 5000 }, // HCM center
{ lat: 21.0285, lng: 105.8542, radius: 5000 }, // Hanoi center
{ lat: 16.0544, lng: 108.2022, radius: 10000 }, // Da Nang
{ lat: 10.8231, lng: 106.6297, radius: 3000 }, // HCM Tan Binh
{ lat: 21.0067, lng: 105.8400, radius: 2000 }, // Hanoi Ba Dinh
];
export default function () {
const iter = __ITER;
if (iter % 2 === 0) {
// Full-text search
const query = TEXT_QUERIES[iter % TEXT_QUERIES.length];
const url = `${BASE_URL}/search?q=${encodeURIComponent(query)}&limit=20&offset=0`;
const res = http.get(url, {
tags: { name: 'GET /search (text)' },
});
textSearchDuration.add(res.timings.duration);
check(res, {
'text search: status 200|503': (r) => r.status === 200 || r.status === 503,
'text search: valid response': (r) => {
if (r.status === 503) return true; // Typesense unavailable — acceptable
try { return JSON.parse(r.body).data !== undefined; } catch { return false; }
},
});
} else {
// Geo search
const geo = GEO_SEARCHES[iter % GEO_SEARCHES.length];
const url = `${BASE_URL}/search/geo?lat=${geo.lat}&lng=${geo.lng}&radius=${geo.radius}&limit=20`;
const res = http.get(url, {
tags: { name: 'GET /search/geo' },
});
geoSearchDuration.add(res.timings.duration);
check(res, {
'geo search: status 200|503': (r) => r.status === 200 || r.status === 503,
'geo search: valid response': (r) => {
if (r.status === 503) return true;
try { return JSON.parse(r.body).data !== undefined; } catch { return false; }
},
});
}
sleep(Math.random() * 1 + 0.5);
}