mirror of https://github.com/rancher/dartboard.git
203 lines
6.2 KiB
JavaScript
203 lines
6.2 KiB
JavaScript
import { check, fail, sleep } from 'k6';
|
|
import exec from 'k6/execution';
|
|
import http from 'k6/http';
|
|
import { getCookies, login, generateAuthorizationHeader, addMinutes } from "../rancher/rancher_utils.js";
|
|
import { getPrincipalIds, getCurrentUserId, getClusterIds, getCurrentUserPrincipal, createUser } from "../rancher/rancher_users_utils.js"
|
|
|
|
|
|
// Parameters
|
|
const tokenCount = Number(__ENV.TOKEN_COUNT)
|
|
const vus = Number(__ENV.K6_VUS) || 1
|
|
const perVuIterations = __ENV.PER_VU_ITERATIONS
|
|
|
|
|
|
// Option setting
|
|
const baseUrl = __ENV.BASE_URL
|
|
const username = __ENV.USERNAME
|
|
const password = __ENV.PASSWORD
|
|
|
|
// Option setting
|
|
export const options = {
|
|
insecureSkipTLSVerify: true,
|
|
|
|
setupTimeout: '8h',
|
|
|
|
scenarios: {
|
|
useTokens: {
|
|
executor: 'shared-iterations',
|
|
exec: 'useTokens',
|
|
vus: vus,
|
|
iterations: perVuIterations,
|
|
maxDuration: '1h',
|
|
},
|
|
},
|
|
// thresholds: {
|
|
// checks: ['rate>0.99']
|
|
// }
|
|
thresholds: {
|
|
http_req_failed: ['rate<=0.01'], // http errors should be less than 1%
|
|
http_req_duration: ['p(99)<=500'], // 95% of requests should be below 500ms
|
|
checks: ['rate>0.99'], // the rate of successful checks should be higher than 99%
|
|
}
|
|
}
|
|
|
|
export function setup() {
|
|
// log in
|
|
if (login(baseUrl, {}, username, password).status !== 200) {
|
|
fail(`could not login into cluster`)
|
|
}
|
|
const cookies = getCookies(baseUrl)
|
|
|
|
// delete leftovers, if any
|
|
cleanup(cookies)
|
|
|
|
// return data that remains constant throughout the test
|
|
let data = {
|
|
cookies: cookies,
|
|
principalIds: getPrincipalIds(baseUrl, cookies),
|
|
myUserId: getCurrentUserId(baseUrl, cookies),
|
|
myUserPrincipal: getCurrentUserPrincipal(baseUrl, cookies),
|
|
clusterIds: getClusterIds(baseUrl, cookies),
|
|
fullTokens: []
|
|
}
|
|
let createdTokens = []
|
|
for (let i = 0; i < tokenCount; i++) {
|
|
createdTokens.push(createToken(baseUrl, data, i))
|
|
}
|
|
|
|
createdTokens.forEach(r => {
|
|
data["fullTokens"].push(r)
|
|
})
|
|
return data
|
|
}
|
|
|
|
export function daysToMilliseconds(days) {
|
|
return days * 24 * 60 * 60 * 1000;
|
|
}
|
|
|
|
function createToken(baseUrl, data, idx) {
|
|
const clusterId = data.clusterIds[idx % data.clusterIds.length]
|
|
const id = `dartboard-${idx}`
|
|
const ttl = daysToMilliseconds(90) // Default ttl from UI is 90 days, but the API uses milliseconds
|
|
|
|
const body = {
|
|
// "clusterId": clusterId,
|
|
// "current": false,
|
|
"description": `Dartboard test token ${id}`,
|
|
// "enabled": true,
|
|
// "expired": false,
|
|
// "isDerived": true,
|
|
// "userId": data.myUserId,
|
|
// "userPrincipal": data.myUserPrincipal.id,
|
|
"metadata": {},
|
|
"ttl": ttl,
|
|
"type": "token",
|
|
}
|
|
|
|
const res = http.post(
|
|
`${baseUrl}/v3/tokens`,
|
|
JSON.stringify(body),
|
|
{ cookies: data.cookies }
|
|
)
|
|
|
|
let token = JSON.parse(res.body)
|
|
|
|
check(res, {
|
|
'POST v3/tokens returns status 201': (r) => r.status === 201,
|
|
})
|
|
|
|
return JSON.parse(res.body)
|
|
}
|
|
|
|
export function deleteTokens(data) {
|
|
let tokensData = getTokens(baseUrl, data)
|
|
tokensData.filter(r => ("description" in r) && r["description"].startsWith("Dartboard test")).forEach(r => {
|
|
let res = http.del(`${baseUrl}/v3/tokens/${r["id"]}`, { cookies: data.cookies })
|
|
check(res, {
|
|
'DELETE /v3/tokens returns status 200': (r) => r.status === 200 || r.status === 204,
|
|
})
|
|
})
|
|
}
|
|
|
|
export function getTokens(data) {
|
|
let res = http.get(`${baseUrl}/v3/tokens`, { cookies: data.cookies })
|
|
check(res, {
|
|
'GET /v3/tokens returns status 200': (r) => r.status === 200 || r.status === 204,
|
|
})
|
|
return JSON.parse(res.body)["data"]
|
|
}
|
|
|
|
export function getTokensByClusterID(data, clusterId) {
|
|
const clusterIdParam = `?clusterId=${clusterId}`
|
|
const checkString = `GET /v3/tokens${clusterIdParam} returns status 200`
|
|
let res = http.get(`${baseUrl}/v3/tokens${clusterIdParam}`, { cookies: data.cookies })
|
|
check(res, {
|
|
checkString: (r) => r.status === 200 || r.status === 204,
|
|
})
|
|
}
|
|
|
|
function getUsers(baseUrl, params) {
|
|
let res = http.get(`${baseUrl}/v3/users`, params);
|
|
check(res, { 'GET users returns status 200': (r) => r.status === 200, });
|
|
return res;
|
|
}
|
|
|
|
function useToken(baseUrl, bearerToken) {
|
|
let params = {
|
|
insecureSkipTLSVerify: true,
|
|
...generateAuthorizationHeader(bearerToken)
|
|
};
|
|
let res = getUsers(baseUrl, params)
|
|
check(res, { 'auth with bearer token': (r) => r.status === 200, });
|
|
return res, params
|
|
}
|
|
|
|
export function useTokens(data) {
|
|
let tokensData = getTokens(data);
|
|
let tokens = tokensData.filter(r => ("description" in r) && r["description"].startsWith("Dartboard test"));
|
|
let lastUsedAtTS = {};
|
|
// Use the tokens for the first time
|
|
tokens.forEach(token => {
|
|
let bearerToken = data["fullTokens"].find(f => token.id == f.id).token;
|
|
useToken(baseUrl, bearerToken)
|
|
});
|
|
tokensData = getTokens(data);
|
|
tokens = tokensData.filter(r => ("description" in r) && r["description"].startsWith("Dartboard test"));
|
|
|
|
// Track lastUsedAtTS for each token
|
|
tokens.forEach(token => {
|
|
// Make sure we're storing a valid number
|
|
const timestamp = Number(token.lastUsedAtTS);
|
|
if (isNaN(timestamp)) {
|
|
console.error(`Invalid timestamp for token ${token.id}:`, token.lastUsedAtTS);
|
|
};
|
|
lastUsedAtTS[token.id] = timestamp;
|
|
});
|
|
|
|
// Utilize each token and verify that lastUsedAtTS is updated to a newer timestamp
|
|
tokens.forEach(token => {
|
|
let bearerToken = data["fullTokens"].find(f => token.id == f.id).token;
|
|
let _, params = useToken(baseUrl, bearerToken)
|
|
createUser(baseUrl, params, `${token.id}-${exec.scenario.iterationInTest}`);
|
|
});
|
|
|
|
tokensData = getTokens(data);
|
|
tokens = tokensData.filter(r => ("description" in r) && r["description"].startsWith("Dartboard test"));
|
|
check(true, {
|
|
'all tokens lastUsedAtTS are newer after utilizing them': () =>
|
|
tokens.every(r => r.lastUsedAtTS > lastUsedAtTS[r.id])
|
|
});
|
|
}
|
|
|
|
function cleanup(data) {
|
|
deleteTokens(data);
|
|
let res = getUsers(baseUrl, { cookies: data.cookies });
|
|
let users = JSON.parse(res.body)["data"];
|
|
users.filter(r => r["description"].startsWith("Dartboard Test User ")).forEach(r => {
|
|
let res = http.del(`${baseUrl}/v3/users/${r["id"]}`, { cookies: data.cookies });
|
|
check(res, {
|
|
'DELETE /v3/users returns status 200': (r) => r.status === 200 || r.status === 204,
|
|
});
|
|
})
|
|
}
|