Hi everybody,
I found this discussion which was a long time ago. But maybe the new version of k6 (V1.7.1) provides the solution of the issue?
I want to assign unique user data to each VU (for login). The user data doesn’t change after each iteration. It should be fix assigned to the VU the whole test time.
I can provide you a sample below. In the console output you’ll find the lines with error messages, i.e.
INFO[0054] ‘scnB’: VU-IT = 10-6 source=console
INFO[0054] Error in “scnB”: Error: Pool poolB is too small! source=console
What I need is a running number (starting with 0) which increments by 1 for each VU of the scenario. This number should be available with the VU data.
Here is my sample code:
import http from 'k6/http';
import { check, sleep, group } from 'k6';
import exec from 'k6/execution';
///////////////////////////////////////////////////////////////////////////////
/// DEFINITIONS
interface MyUser {
id: string;
}
let currentUser: MyUser | undefined;
const pools: { [key: string]: MyUser[] } = {
poolA: [...Array(11).keys()].map((i) => ({ id: `A${i}` })),
poolB: [...Array(6).keys()].map((i) => ({ id: `B${i}` })),
poolC: [...Array(4).keys()].map((i) => ({ id: `C${i}` })),
};
// Mapping Scenario → Pool name
const scenarioToPool: { [scenario: string]: string } = {
scnA: 'poolA',
scnB: 'poolB',
scnC: 'poolC',
};
// ----------------------
// Scenario-Config
// ----------------------
export const options = {
scenarios: {
scnA: {
executor: 'ramping-vus',
startVUs: 0,
stages: [
{ duration: '10s', target: 11 },
{ duration: '20s', target: 11 },
{ duration: '13s', target: 0 },
],
gracefulStop: '20s',
gracefulRampDown: '20s',
exec: 'scnA',
},
scnB: {
executor: 'constant-vus',
vus: 6,
duration: '60s',
gracefulStop: '20s',
exec: 'scnB',
},
scnC: {
executor: 'per-vu-iterations',
vus: 4,
iterations: 5,
maxDuration: '60s',
gracefulStop: '20s',
exec: 'scnC',
},
},
};
// ----------------------
// Scenario-Functions
// ----------------------
export function scnA() {
console.debug(`'scnA': >>>> Start | VU=${__VU} | Iteration=${__ITER}`);
console.log(`'scnA': VU-IT = ${exec.vu.idInInstance}-${__ITER}`);
const start = Date.now();
try {
const user = getUserForVU();
} catch (err) {
console.log('Error in "scnA": ', err);
sleep(9);
return;
}
sleep(1);
group('scnA', function () {
let url = 'https://quickpizza.grafana.com/';
let response = http.get(url);
sleep(1);
url = 'https://quickpizza.grafana.com/api/delay/11';
response = http.get(url);
});
console.debug(`'scnA': >>>> END | VU=${__VU} | Iteration=${__ITER}`);
}
export function scnB() {
console.debug(`'scnB': >>>> Start | VU=${__VU} | Iteration=${__ITER}`);
console.log(`'scnB': VU-IT = ${exec.vu.idInInstance}-${__ITER}`);
const start = Date.now();
try {
const user = getUserForVU();
} catch (err) {
console.log('Error in "scnB": ', err);
sleep(9);
return;
}
sleep(2);
group('scnB', function () {
let url = 'https://quickpizza.grafana.com/';
let response = http.get(url);
url = 'https://quickpizza.grafana.com/api/delay/6';
response = http.get(url);
});
console.debug(`'scnB': >>>> END | VU=${__VU} | Iteration=${__ITER}`);
}
export function scnC() {
console.debug(`'scnC': >>>> Start | VU=${__VU} | Iteration=${__ITER}`);
console.log(`'scnC': VU-IT = ${exec.vu.idInInstance}-${__ITER}`);
const start = Date.now();
try {
const user = getUserForVU();
} catch (err) {
console.log('Error in "scnC": ', err);
sleep(9);
return;
}
group('scnC', function () {
const url = 'https://quickpizza.grafana.com/';
const response = http.get(url);
const checkRes = check(response, {
'status is 200': (r) => r.status === 200,
'response time < 2000ms': (r) => r.timings.duration < 2000,
});
console.debug(`Response time: ${response.timings.duration} ms`);
});
sleep(4);
console.debug(`'scnC': >>>> END | VU=${__VU} | Iteration=${__ITER}`);
}
/// the goal of this function is to provide a unique user
/// to each VU; the user data come from the user pools
export function getUserForVU() {
const scenarioName = exec.scenario.name;
if (!currentUser) {
const poolName = scenarioToPool[scenarioName];
const pool = pools[poolName];
const index = exec.vu.idInInstance - 1;
if (index >= pool.length) throw new Error(`Pool ${poolName} is too small!`);
currentUser = pool[index];
console.log(
`'getUserForVU': Scenario ${scenarioName} | VU ${exec.vu.idInInstance} → User ${currentUser.id}`
);
}
return currentUser;
}
I would be happy about any ideas I can validate or maybe there is a solution available. To use 3rd party apps / services / servers is not possible.
Thank you in advance,
Niko