139 lines
3.8 KiB
JavaScript
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);
|
|
}
|