117 lines
3.3 KiB
JavaScript
117 lines
3.3 KiB
JavaScript
import http from 'k6/http';
|
|
import { check, fail, sleep } from 'k6';
|
|
import exec from 'k6/execution';
|
|
|
|
const BASE_URL = (__ENV.BASE_URL || 'https://127.0.0.1:2288').replace(/\/$/, '');
|
|
const HOST_HEADER = (__ENV.HOST_HEADER || 'stend.4mont.ru').trim();
|
|
const SERVICE_A = __ENV.SERVICE_A || 'termidesk';
|
|
const SERVICE_B = __ENV.SERVICE_B || 'vmmanager';
|
|
const CLOSE_SESSION = (__ENV.CLOSE_SESSION || '1') !== '0';
|
|
const REQ_TIMEOUT = __ENV.REQ_TIMEOUT || '20s';
|
|
|
|
const users = (__ENV.USERS_CSV || '')
|
|
.split(';')
|
|
.map((v) => v.trim())
|
|
.filter(Boolean)
|
|
.map((pair) => {
|
|
const i = pair.indexOf(':');
|
|
return i > 0 ? { username: pair.slice(0, i), password: pair.slice(i + 1) } : null;
|
|
})
|
|
.filter(Boolean);
|
|
|
|
export const options = {
|
|
scenarios: {
|
|
burst_100_users: {
|
|
executor: 'per-vu-iterations',
|
|
vus: 100,
|
|
iterations: 1,
|
|
maxDuration: '3m',
|
|
},
|
|
},
|
|
insecureSkipTLSVerify: true,
|
|
thresholds: {
|
|
http_req_failed: ['rate<0.2'],
|
|
},
|
|
};
|
|
|
|
function hdr(extra = {}) {
|
|
return HOST_HEADER ? { ...extra, Host: HOST_HEADER } : extra;
|
|
}
|
|
|
|
function getCreds() {
|
|
if (users.length < 100) fail(`Need at least 100 users in USERS_CSV, got ${users.length}`);
|
|
const idx = (exec.vu.idInTest || 1) - 1;
|
|
return users[idx % users.length];
|
|
}
|
|
|
|
function login(username, password) {
|
|
const jar = http.cookieJar();
|
|
jar.clear(BASE_URL);
|
|
|
|
const landing = http.get(`${BASE_URL}/`, {
|
|
redirects: 0,
|
|
timeout: REQ_TIMEOUT,
|
|
headers: hdr(),
|
|
tags: { name: 'GET /' },
|
|
});
|
|
|
|
const csrfFromCookie = (jar.cookiesForURL(BASE_URL).csrf_token || [])[0] || '';
|
|
const csrf = csrfFromCookie || ((landing.cookies.csrf_token || [])[0] || {}).value || '';
|
|
if (!csrf) fail(`No CSRF for ${username}`);
|
|
|
|
const payload = [
|
|
`username=${encodeURIComponent(username)}`,
|
|
`password=${encodeURIComponent(password)}`,
|
|
`csrf_token=${encodeURIComponent(csrf)}`,
|
|
].join('&');
|
|
|
|
const loginRes = http.post(`${BASE_URL}/login`, payload, {
|
|
redirects: 0,
|
|
timeout: REQ_TIMEOUT,
|
|
headers: hdr({ 'Content-Type': 'application/x-www-form-urlencoded' }),
|
|
tags: { name: 'POST /login' },
|
|
});
|
|
|
|
const ok = check(loginRes, { 'login status 303': (r) => r.status === 303 });
|
|
if (!ok) fail(`Login failed ${username}, status=${loginRes.status}`);
|
|
}
|
|
|
|
function openService(slug) {
|
|
const res = http.get(`${BASE_URL}/go/${slug}`, {
|
|
redirects: 0,
|
|
timeout: REQ_TIMEOUT,
|
|
headers: hdr(),
|
|
tags: { name: 'GET /go/:slug' },
|
|
});
|
|
const ok = check(res, { [`open ${slug} -> 303`]: (r) => r.status === 303 });
|
|
const location = res.headers.Location || '';
|
|
const m = location.match(/\/s\/([0-9a-fA-F-]{36})\//);
|
|
return { ok, status: res.status, sessionId: m ? m[1] : '', location };
|
|
}
|
|
|
|
function closeSession(sessionId) {
|
|
if (!sessionId || !CLOSE_SESSION) return;
|
|
http.post(`${BASE_URL}/api/sessions/${sessionId}/close`, null, {
|
|
redirects: 0,
|
|
timeout: REQ_TIMEOUT,
|
|
headers: hdr(),
|
|
tags: { name: 'POST /api/sessions/:id/close' },
|
|
});
|
|
}
|
|
|
|
export default function () {
|
|
const { username, password } = getCreds();
|
|
login(username, password);
|
|
|
|
const a = openService(SERVICE_A);
|
|
sleep(0.1);
|
|
const b = openService(SERVICE_B);
|
|
|
|
closeSession(a.sessionId);
|
|
closeSession(b.sessionId);
|
|
|
|
if (!a.ok || !b.ok) {
|
|
fail(`open failed user=${username} a=${a.status} b=${b.status}`);
|
|
}
|
|
}
|