Run k6 test parallely with different environment variables

I have a test.js which has setup function that logs in with an user based on the credentials from environment variables that is passed when trigegring from command line or using docker.

k6 run test.js -e env=test -e user=user1 -e pwd=pwd1

or

docker run -v C:/Repos/test/:/src loadimpact/k6 run src/test.js -e env=test -e user=user1 -e pwd=pwd1

By any chance is it possible to run the same command parallely with different user credentials ?

The reason why am not using a data.json and the solution described in this post is that i do not want to login each time with every iteration of the virtual user.

Am trying to achieve, setup function logins an user and default function run the test script for defined VUs and iterations with the same login. And the tests should be run parallel with different user credentials.

Please let me know if this is possible with the current version of k6.

Not sure I understand your whole question, but I’ll try to give an example where each VU has its own credentials, and you’re not logging in every iteration.

Say you have a JSON file users.js (or many such files, if you parametrize like I explained here) like this:

[
    {
        "username": "user1",
        "password": "pass1"
    },
    {
        "username": "user2",
        "password": "pass2"
    },
    {
        "username": "user3",
        "password": "pass3"
    }
]

Then, you can write your k6 script like this:

import http from "k6/http";
import { sleep } from "k6";

let users = JSON.parse(open(__ENV.MY_USERS_FILE));

export let options = {
    vus: users.length, // VUs stands for "virtual users", after all
    duration: "10s",
};

export function setup() {
    // Transform users into login requests
    let loginRequests = users.map(u => ["POST", "https://httpbin.org/anything", u]);

    // log in all users in parallel
    let loginResponses = http.batch(loginRequests);

    // this is just a demo, but maybe extract some cookies or tokens or whatever in the actual case
    let loginData = loginResponses.map(r => r.json().headers['X-Amzn-Trace-Id']);
    console.log(JSON.stringify(loginData, null, "  "));

    return loginData; // return some array with login details for each user
}

export default function (setupData) {
    let vuData = setupData[__VU - 1]; // Starts from 1
    console.log(`VU ${__VU} is operating with data ` + JSON.stringify(vuData));
    http.get(`https://httpbin.org/anything?userdata=${vuData}`);
    sleep(1);
}

And run it with k6 run --env MY_USERS_FILE=users.json zt.js. Then, each user should only be logged in in the setup() function and you can use their cookies/tokens/whatever in the iteration.

Or, you can use the __ITER execution context variable (until we implement Per-VU init lifecycle function · Issue #785 · grafana/k6 · GitHub) to log in each VU only in their fist iteration, and never again, like this:

export default function () {
    if (__ITER == 0) {
        initVU();
    }
    normalVUCode();
}
2 Likes

@ned the code looks promising and i tried it out.

I am having trouble with the value of ‘__VU’ . Max vus is defined to be 20, and __VU seems to go beyond 20.

My test data file has only 20 data, and the below code fails when __VU goes beyound 20.

console.log("VU:" + __VU + "/U:" + users[ __VU - 1 ].username + "/P:" + users[ __VU - 1 ].password );

any idea on how do i tackle this issue.

Do you have ramp-downs and ramp-ups in the number of VUs via the stages options? If so, that could be the cause of the __VU value exceeding the max number of VUs. It’s a known bug that we’ve fixed in https://github.com/loadimpact/k6/pull/1007, but we haven’t yet released.

To work around the issue, you can use modulo division, like this:

let dataNumber = (__VU - 1) % users.length;
console.log("VU:" + __VU + "/U:" + users[dataNumber].username + "/P:" + users[dataNumber].password );
3 Likes

k6 v0.27.0 should make this easier. See how different environment variables are passed to the same function in the my_api_test_1 and my_api_test_2 scenarios from the example:

1 Like

Thanks for this answer! This works perfectly within my setup!