Files
silo-server/scripts/loadtest/continuum-sections.k6.js

139 lines
3.8 KiB
JavaScript

import http from "k6/http";
import { check, group, sleep } from "k6";
const BASE_URL = (__ENV.BASE_URL || "http://localhost:8080/api/v1").replace(
/\/$/,
"",
);
const TOKEN = __ENV.TOKEN || "";
const LIBRARY_IDS = (__ENV.LIBRARY_IDS || "")
.split(",")
.map((value) => Number(value.trim()))
.filter((value) => Number.isFinite(value) && value > 0);
const HOME_SECTION_CONCURRENCY = Number(__ENV.HOME_SECTION_CONCURRENCY || 5);
const LIBRARY_SECTION_CONCURRENCY = Number(
__ENV.LIBRARY_SECTION_CONCURRENCY || 4,
);
export const options = {
scenarios: {
home_surface: {
executor: "constant-vus",
vus: Number(__ENV.HOME_VUS || 3),
duration: __ENV.HOME_DURATION || "2m",
exec: "homeSurface",
},
library_surface: {
executor: "constant-vus",
vus: Number(__ENV.LIBRARY_VUS || 2),
duration: __ENV.LIBRARY_DURATION || "2m",
exec: "librarySurface",
},
aggregate_sections: {
executor: "constant-vus",
vus: Number(__ENV.AGGREGATE_VUS || 1),
duration: __ENV.AGGREGATE_DURATION || "1m",
exec: "aggregateSections",
},
},
thresholds: {
http_req_failed: ["rate<0.01"],
"http_req_duration{route:home_section_items}": ["p(95)<3000"],
"http_req_duration{route:library_section_items}": ["p(95)<2000"],
"http_req_duration{route:aggregate_sections}": ["p(95)<6000"],
},
};
function headers() {
const result = {
Accept: "application/json",
"Content-Type": "application/json",
};
if (TOKEN) {
result.Authorization = `Bearer ${TOKEN}`;
}
if (__ENV.PROFILE_ID) {
result["X-Profile-ID"] = __ENV.PROFILE_ID;
}
return result;
}
function getJSON(path, tags) {
const response = http.get(`${BASE_URL}${path}`, { headers: headers(), tags });
check(response, {
[`GET ${path} returned 2xx`]: (res) =>
res.status >= 200 && res.status < 300,
});
if (response.status < 200 || response.status >= 300) {
return null;
}
return response.json();
}
function fetchSectionBatches(paths, concurrency, route) {
for (let i = 0; i < paths.length; i += concurrency) {
const batch = paths
.slice(i, i + concurrency)
.map((path) => [
"GET",
`${BASE_URL}${path}`,
null,
{ headers: headers(), tags: { route } },
]);
const responses = http.batch(batch);
responses.forEach((response) => {
check(response, {
[`${route} returned 2xx`]: (res) =>
res.status >= 200 && res.status < 300,
});
});
}
}
export function homeSurface() {
group("home layout plus item batches", () => {
const layout = getJSON("/home/layout", { route: "home_layout" });
const sections = Array.isArray(layout?.sections) ? layout.sections : [];
const paths = sections.map(
(section) => `/home/sections/${section.id}/items`,
);
fetchSectionBatches(paths, HOME_SECTION_CONCURRENCY, "home_section_items");
});
sleep(1);
}
export function librarySurface() {
if (LIBRARY_IDS.length === 0) {
return;
}
const libraryID = LIBRARY_IDS[__VU % LIBRARY_IDS.length];
group("library layout plus item batches", () => {
const layout = getJSON(`/library/${libraryID}/layout`, {
route: "library_layout",
});
const sections = Array.isArray(layout?.sections) ? layout.sections : [];
const paths = sections.map(
(section) => `/library/${libraryID}/sections/${section.id}/items`,
);
fetchSectionBatches(
paths,
LIBRARY_SECTION_CONCURRENCY,
"library_section_items",
);
});
sleep(1);
}
export function aggregateSections() {
group("aggregate section endpoints", () => {
getJSON("/home/sections", { route: "aggregate_sections" });
LIBRARY_IDS.forEach((libraryID) => {
getJSON(`/library/${libraryID}/sections`, {
route: "aggregate_sections",
});
});
});
sleep(2);
}