I calculate rate in handleSummary but code it not working

Help me. I will calculate rate but code it not working and i got this error.

handleSummary() failed with error “TypeError: Cannot read property ‘values’ of undefined”, falling back to the default summary

export function handleSummary(data) {
    for (let key in options.scenarios) {
        let duration = parseInt(options.scenarios[key].duration); // this is smart enough to get rid of 's' in the end; if duration is not in seconds, it must be additionally converted to them
        let ratePerScenario = data.metrics[`iterations{scenario:${key}}`].values.count / duration; // calculate new rate with scenario duration
        data.metrics[`iterations{scenario:${key}}`].values.rate = ratePerScenario; // set new rate in the main data object to pass it to standard summary output below
    }
    return {
        'stdout': textSummary(data, { indent: ' ', enableColors: true }),
    }
}

https://community.grafana.com/t/incorrect-counter-rate-when-using-multiple-scenarios-report/98657/4

Thank you.

1 Like

Hi @trinpha

Can you share the scenarios of your test or a complete (sanitized) script we can use to reproduce? Are you using the constant-arrival-rate executor?

As Olha mentioned in Incorrect counter rate when using multiple scenarios report - #2 by olhayevtushenko, it might not be that straightforward with other executors.

Cheers!

Hello @eyeveebee This is my sample code.

import http from 'k6/http';
import { check, sleep, group} from "k6";
import { htmlReport } from "https://raw.githubusercontent.com/benc-uk/k6-reporter/2.4.0/dist/bundle.js";
import { textSummary } from "https://jslib.k6.io/k6-summary/0.0.3/index.js";
import { Rate } from 'k6/metrics';

// Define a list of scenarios with different configurations
let EXEC_agentDetail = true
let EXEC_agentWallet = true
let EXEC_businessGroup = false


const scenariosStore = [
  { vus: 3, duration: '15s', name: 'agentDetail', enable: EXEC_agentDetail, execGroup: allCase.agentDetail_Testcase },
  { vus: 3, duration: '15s', name: 'agentWallet', enable: EXEC_agentWallet, execGroup: allCase.agentWallet_Testcase },
  { vus: 3, duration: '15s', name: 'businessGroup', enable: EXEC_businessGroup, execGroup: allCase.businessGroup_Testcase },

];

export let options = {
  scenarios: {},
  thresholds: {
    http_req_failed: ['rate<0.01'],
    
  },
  summaryTrendStats: ['count', 'avg', 'min', 'med', 'max', 'p(90)', 'p(95)', 'p(99)'],
};



let result = 0;
let isFirstScenario = true; // เพิ่มตัวแปรเพื่อตรวจสอบว่าเป็น Scenario แรก
for (let i = 0; i < scenariosStore.filter(element=>{
  return element.enable===true
}).length; i++) {

    let scenarioName = scenariosStore[i].name
    let groupName = scenariosStore[i].execGroup
    let VUS = scenariosStore[i].vus
    let DURATION = scenariosStore[i].duration

    if (isFirstScenario) {      // ตรวจสอบว่าเป็น Scenario แรก
      options.scenarios[scenarioName] = {
        executor: 'constant-vus',
        exec: groupName,
        vus: VUS,
        duration: DURATION,
        startTime: "0s", // ตั้งค่า startTime เป็น "0s" สำหรับ Scenario แรก
      };
      isFirstScenario = false; // กำหนดให้ไม่เป็น Scenario แรกในการประมวลผลถัดไป
    } else {
      options.scenarios[scenarioName] = {
        executor: 'constant-vus',
        exec: groupName,
        vus: VUS,
        duration: DURATION,
        startTime: result + "s", 
      };
  }
  result+=0.5
  let waitingTime = parseInt(DURATION);   // กำหนด startTime ตามค่า result และเพิ่ม 1 วินาที
  result+=waitingTime
}

for (let key in options.scenarios) {
  // Each scenario automaticall tags the metrics it generates with its own name
  let scenariosName = key
  let httpReqDuration = `http_req_duration{scenario:${scenariosName}}`;
  let iterationGroup = `iterations{scenario:${scenariosName}}`;
  let myRate = `myRate{scenario:${scenariosName}}`;
  // Check to prevent us from overwriting a threshold that already exists
  if (!options.thresholds[httpReqDuration]) {
      options.thresholds[httpReqDuration] = [];
      options.thresholds[iterationGroup] = [];
      options.thresholds[myRate] = [];
  }
  // 'max>=0' is a bogus condition that will always be fulfilled
  options.thresholds[httpReqDuration].push('max>=0', 'p(95) < 1000');
  options.thresholds[iterationGroup].push('rate>=0');
  options.thresholds[myRate].push('rate>=0');
}

const groupToken = [
  { enable: EXEC_agentDetail, tokenName: "agentDetail_Token", tokenSetup: "TOKEN" },
  { enable: EXEC_agentWallet, tokenName:"agentWallet_Token", tokenSetup: "TOKEN" },
  { enable: EXEC_businessGroup, tokenName:"businessGroup_Token", tokenSetup: "TOKEN" },
];

export function setup(){
  let sellingToken = execSetupToken(groupToken.filter(element=>{
    return element.enable===true
  }))
  return sellingToken
}

const myRate = new Rate('myRate');

export function execSetupToken(groupToken) {
  for (let i = 0; i < groupToken.length; i++) {
    console.log("get_some_token");
  }
}

export function agentDetail_Testcase() {
  group('agentDetail_Testcase', function () {
    const apiUrl = 'https://www.google.com/';
    let response = http.get(apiUrl);
    check(response, {
      'status is 200': (r) => r.status === 200,
    });
    myRate.add(response.timings.duration);
  });
}

export function agentWallet_Testcase() {
  group('agentWallet_Testcase', function () {
    const apiUrl = 'https://www.google.com/';
    let response = http.get(apiUrl);
    check(response, {
      'status is 200': (r) => r.status === 200,
    });
    myRate.add(response.timings.duration);
  });
}

export function businessGroup_Testcase() {
  group('businessGroup_Testcase', function () {
    const apiUrl = 'https://www.google.com/';
    let response = http.get(apiUrl);
    check(response, {
      'status is 200': (r) => r.status === 200,
    });
    myRate.add(response.timings.duration);
  });
}

const groupName = [
  {enable: EXEC_agentDetail, Testcase: agentDetail_Testcase},
  {enable: EXEC_agentWallet, Testcase: agentWallet_Testcase},
  {enable: EXEC_businessGroup, Testcase: businessGroup_Testcase},

];

export default function allCase() {  
  execTestcase(groupName.filter(element=>{
    return element.enable===true
  }));
  sleep(1);
};

function execTestcase(groupName) {
  for (let i = 0; i < groupName.length; i++) {
    groupName[i].Testcase();
  }
}

export function handleSummary(data) {
  for (let key in options.scenarios) {
    let duration = parseInt(options.scenarios[key].duration); 
    let ratePerScenario = data.metrics[`iterations{scenario:${key}}`].values.count / duration; 
    data.metrics[`iterations{scenario:${key}}`].values.rate = ratePerScenario; 
  }
  return {
    "sellingScenario.html": htmlReport(data),
    stdout: textSummary(data, { indent: " ", enableColors: true }),
  };
}

this summary report. I’m wondering about the iteration scenario and why it divides the values by total scenario from the http_req_duration of scenario. I would like to get the correct values for iteration of scenario and rate/s.

http_req_duration…: count=114 avg=328.96ms
{ expected_response:true }…: count=114 avg=328.96ms
✓ { scenario:agentDetail }…: count=58 avg=320.7ms
✓ { scenario:agentWallet }…: count=56 avg=337.51ms

iterations…: 57 1.776754/s
✓ { scenario:agentDetail }…: 29 0.903962/s
✓ { scenario:agentWallet }…: 28 0.872791/s

     checks.........................: 100.00% ✓ 114      ✗ 0
     data_received..................: 3.1 MB  96 kB/s
     data_sent......................: 36 kB   1.1 kB/s
     group_duration.................: count=114 avg=337.67ms min=207.7ms  med=331.77ms max=602.08ms p(90)=430.2ms  p(95)=447.17ms p(99)=509.96ms
     http_req_blocked...............: count=114 avg=8.31ms   min=0s       med=0s       max=166.51ms p(90)=0s       p(95)=52.81ms  p(99)=163.79ms
     http_req_connecting............: count=114 avg=1.56ms   min=0s       med=0s       max=35.37ms  p(90)=0s       p(95)=8.24ms   p(99)=34.76ms
     http_req_duration..............: count=114 avg=328.96ms min=207.1ms  med=313.89ms max=601.54ms p(90)=421.79ms p(95)=447.07ms p(99)=509.94ms
       { expected_response:true }...: count=114 avg=328.96ms min=207.1ms  med=313.89ms max=601.54ms p(90)=421.79ms p(95)=447.07ms p(99)=509.94ms
     ✓ { scenario:agentDetail }.....: count=58  avg=320.7ms  min=207.1ms  med=309.11ms max=601.54ms p(90)=406.5ms  p(95)=426.47ms p(99)=513.79ms
     ✓ { scenario:agentWallet }.....: count=56  avg=337.51ms min=217.25ms med=338.42ms max=515.81ms p(90)=439.53ms p(95)=454.12ms p(99)=491ms
   ✓ http_req_failed................: 0.00%   ✓ 0        ✗ 114
     http_req_receiving.............: count=114 avg=33.94ms  min=2.62ms   med=23.67ms  max=318.69ms p(90)=53.98ms  p(95)=63.63ms  p(99)=101.16ms
     http_req_sending...............: count=114 avg=240.31µs min=0s       med=139.29µs max=668.8µs  p(90)=543.83µs p(95)=594.62µs p(99)=632.82µs
     http_req_tls_handshaking.......: count=114 avg=4.43ms   min=0s       med=0s       max=98.88ms  p(90)=0s       p(95)=22.55ms  p(99)=95.69ms
     http_req_waiting...............: count=114 avg=294.78ms min=181.4ms  med=283.58ms max=497.79ms p(90)=384.97ms p(95)=417.86ms p(99)=449.11ms
     http_reqs......................: 114     3.553507/s
     iteration_duration.............: count=58  avg=1.65s    min=1.02ms   med=1.66s    max=2.05s    p(90)=1.79s    p(95)=1.85s    p(99)=1.98s
     iterations.....................: 57      1.776754/s
     ✓ { scenario:agentDetail }.....: 29      0.903962/s
     ✓ { scenario:agentWallet }.....: 28      0.872791/s
     myRate.........................: 100.00% ✓ 114      ✗ 0
     ✓ { scenario:agentDetail }.....: 100.00% ✓ 58       ✗ 0
     ✓ { scenario:agentWallet }.....: 100.00% ✓ 56       ✗ 0
     vus............................: 1       min=1      max=5
     vus_max........................: 6       min=6      max=6

and I apologize, I’m new to k6 and JavaScript. and I’m not very proficient in English

Hey @trinpha,
unfortunately options. is not very reliable to be used directly in the code. For this reason, we have introduced test.options as part of the k6/execution API.

You should replace your occurances of options with something like:


import exec from 'k6/execution';

export default function() {
    ...
    let myOption = exec.test.options.<here the variable you want to access>
}

Let me know if it helps.

1 Like

Thank you for reply.
i found this solution. i use scenariosStore for execution and the last step i get name to use in handleSummary.

But I will adapt your solution to my code.

const scenariosStore = [
  { vus: 3, duration: '15s', name: 'agentDetail', enable: EXEC_agentDetail, execGroup: allCase.agentDetail_Testcase },
  { vus: 3, duration: '15s', name: 'agentWallet', enable: EXEC_agentWallet, execGroup: allCase.agentWallet_Testcase },
  { vus: 3, duration: '15s', name: 'businessGroup', enable: EXEC_businessGroup, execGroup: allCase.businessGroup_Testcase },
  { vus: 3, duration: '15s', name: 'district', enable: EXEC_district, execGroup: allCase.district_Testcase },
  { vus: 3, duration: '15s', name: 'driverAgeAll', enable: EXEC_driverAgeAll, execGroup: allCase.driverAgeAll_Testcase }
]
export function handleSummary(data) {
  let scenariosLength = scenariosStore.filter(element => element.enable).length
  for (let scenario of scenariosStore.filter(element => element.enable)) {
    let scenariosName = scenario.name
    let duration = parseInt(scenario.duration); 
    let httpReqDuration = `http_req_duration{scenario:${scenariosName}}`;
    let http_req_durationRatePerScenario = data.metrics[httpReqDuration].values.count / duration; 
    data.metrics[httpReqDuration].values.rate = http_req_durationRatePerScenario
    // let iterationsRatePerScenario = data.metrics[`iterations{scenario:${scenariosName}}`].values.count * scenariosLength / duration; 
    data.metrics[`iterations{scenario:${scenariosName}}`].values.rate = http_req_durationRatePerScenario; 
  }
  return {
    "sellingScenario.html": htmlReport(data),
    stdout: textSummary(data, { indent: " ", enableColors: true }),
  };
}
1 Like