Questions about passing failedrequestcounter from a subscript to the main script

Here is my code:

------mainScript.js-------
import { group, sleep} from "k6"
import tc1 from './testcase_1.js'
import tc2 from './testcase_2.js'

export let options = {
    thresholds: {
        failedRequestCounter: [{ threshold: 'count===0', abortOnFail: true }], // abort the test on any failed requests
    },
    vus: 1,
    iterations: 1
};
export default function () {
    tc1();
    tc2();
}
----testcase_1.js-------
import http from 'k6/http'
import { sleep } from "k6";
import * as checkHelper from './checkHelper.js'
export let options = {
    vus: 1,
    iterations: 1
};

export default function () {

    let res;
    res = http.get('https://test-api.loadimpact.com/public/crocodiles/a') // 404
    checkHelper.check(res.status, {
        "some other check in test case 1": (status) => status === 201
    });
    sleep(1);
}
-----testcase_2.js-------
import http from 'k6/http'
import { sleep } from "k6"
import * as checkHelper from './checkHelper.js'

export let options = {
    vus: 1,
    iterations: 1
};

export default function () {
    let res = http.get('https://test-api.loadimpact.com/public/crocodiles/');

    checkHelper.check(res.status, {
        "API in test case 2 is working": (status) => status === 200
    });

}
----checkHelper.js-------------
import { check as loadTestingCheck} from "k6";
import { Counter } from 'k6/metrics'

export let failedRequestCounter = new Counter('failedRequestCounter');
export let check = function (obj, conditionArray, tags) {
    let result = loadTestingCheck(obj, conditionArray, tags || {});
    failedRequestCounter.add(!result);
    return result;
};
---run script---
k6 run mainScript.js
 done [==========================================================] 0 / 1
WARN[0002] No data generated, because no script iterations finished, consider making the test duration longer 

    ✗ some other check in test case 1
     ↳  0% — ✓ 0 / ✗ 1

    checks.....................: 0.00% ✓ 0   ✗ 1  
  ✗ failedRequestCounter.......: 1     0.504474/s

----the test case 1 failed as I expected and the whole test is stopped before testcase_2.js is run. However, I don’t understand how this could work when checkHelper.js is only imported by child scripts, and the failedRequestCounter is only defined there, but not in mainScript.js even though the threshold is only set in mainScript.js.

My second question is: if I remove sleep(1) from testcase_1.js, the test case_2 will be executed even though failedRequestCounter reached the failure threshold. I am not sure if it has been documented that sleep(1) is required in order for data is returned to metrics.

The test files will all be loaded into the same javascript vm. As check and Counter both are javascript bindings for go code, it does not really matter whether they are defined in mainScript.js or not.

As a side-note here I’d like to mention that you can remove the exported options variable from your testcase_x.js files as only the one exported from the entrypoint (in this case mainScript.js) will be used anyway.

k6 does not really have test cases in the sense you might be familiar with from other test tools, so tc1 and tc2 that you’re calling are just as any other function call you’d make from your default function.

abortOnFail checks are executed on a timer, so for instance, if you want your test script to not make the next call if the first failed, you’d need a sleep for this. With that said, however, it does not really sound like a robust solution to depend on the timings to abort it for you. I’d rather suggest that you do something like this if you want to make sure nothing else is executed:

import { sleep } from "k6";
import { Counter } from "k6/metrics";

export let failedRequestCounter = new Counter("failedRequestCounter");

export let options = {
  vus: 1,
  duration: "10s",
  thresholds: {
    failedRequestCounter: [{ threshold: "count===0", abortOnFail: true }], // abort the test on any failed requests
  },
};

let abort = false;

export default function () {
  if (abort) {
    sleep(100000);
    return;
  }

  try {
    firstCase();
    secondCase();
  } catch (e) {
    failedRequestCounter.add(1);
    abort = true;
  }
}

function firstCase() {
  throw new Error("ERROR!");
}

function secondCase() {
  console.log("I will never be executed");
}

1 Like

@simme,
Thanks for the insight and the detailed code. Really appreciate it.

1 Like