Crosby
October 4, 2021, 1:22pm
1
Hi! Trying to adapt this example to our project:
But for some reason some parts of it doesn’t work as expected…
First of all I can’t use template literals (Template literals (Template strings) - JavaScript | MDN ) in such blocks:
duration: '1s',
vus: 1,
iterations: 1,
thresholds: {
endpoint_data_sent: ['count < 2048'],
`endpoint_data_sent{url:${__ENV.BASE_URL}/myEndpoint}`: ['count < 1024'],
`endpoint_data_recv{url:${__ENV.BASE_URL}/myEndpoint}}`: ['count < 2048']
},
tags: {
project_name: 'MyProject',
}
};
for some reason…
And even if I hardcode all values in
thresholds
block, then I got such errors:
TypeError: Cannot read property 'headers' of undefined source=console
And in the summary:
█ 01. methodName1
✗ Exception raised "TypeError: Cannot read property 'headers' of undefined"
↳ 0% — ✓ 0 / ✗ 1101
project_name_main_loop_iters_counter...: 1101 1081.475049/s
...
other metrics...
Though I can see that this particular transaction actually returns data:
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Type: application/json
Matched-Stub-Id: c27351fd-f162-4e80-a4ea-1a17003165fc
Server: Jetty(9.2.z-SNAPSHOT)
4a
{"result":{"status":"OK","reasonCode":0,"message":"Operation Successful"}}
0
group="::01. methodName1" iter=1098 project_name=MyProject request_id=add5067e-fd62-4ff0-6e68-96a95771cf87 scenario=default source=http-debug vu=1
By the way, I’m testing via wiremock stubs if it actually matters.
What am I doing wrong with this test?
Hi @Crosby , welcome to the community forum
From the looks of it w/e you provide doesn’t have headers
and given the code you’ve linked that can either be the response object or the response.request
, given that both are unlikely as k6 will always populate this unless there is another exception I would guess that is what is happening.
Can you please provide a full working script which blows up as this is likely some minor misstyping somewhere. You can use https://httpbin.test.k6.io
for the endpoints instead of your real endpoint.
Crosby
October 5, 2021, 10:37am
3
Full script body:
import { describe } from 'https://jslib.k6.io/expect/0.0.5/index.js';
import { Httpx, Request, Get, Post } from 'https://jslib.k6.io/httpx/0.0.4/index.js';
import { randomIntBetween, randomItem } from "https://jslib.k6.io/k6-utils/1.1.0/index.js";
import { Counter } from 'k6/metrics';
import { SharedArray } from "k6/data";
import http from "k6/http";
// So we could see for what project all these metrics actually are:
let myCounter = new Counter('project_name_main_loop_iters_counter');
export let epDataSent = new Counter('endpoint_data_sent');
export let epDataRecv = new Counter('endpoint_data_recv');
export let options = {
duration: '1s',
vus: 1,
iterations: 1,
thresholds: {
checks: [{threshold: 'rate == 1.00', abortOnFail: true}],
// We can setup thresholds on these custom metrics, "count" means bytes in this case.
endpoint_data_sent: ['count < 2048'],
'endpoint_data_sent{url:https://httpbin.test.k6.io/post}': ['count < 1024'],
'endpoint_data_recv{url:https://httpbin.test.k6.io/post}}': ['count < 2048'],
'endpoint_data_sent{url:https://httpbin.test.k6.io/get}': ['count < 1024'],
'endpoint_data_recv{url:https://httpbin.test.k6.io/get}': ['count < 2048']
},
tags: {
project_name: 'MyProject',
}
};
function sizeOfHeaders(hdrs) {
return Object.keys(hdrs).reduce(
(sum, key) => sum + key.length + hdrs[key].length,
0,
);
}
function trackDataMetricsPerURL(res) {
// Add data points for sent and received data
epDataSent.add(sizeOfHeaders(res.request.headers) + res.request.body.length, {
url: res.url,
});
epDataRecv.add(sizeOfHeaders(res.headers) + res.body.length, {
url: res.url,
});
}
export default function testSuite() {
myCounter.add(1);
describe('01. methodName1', (t) => {
let postmethodName1 = {
method: "POST",
url: `${__ENV.BASE_URL}/post`,
body: JSON.stringify({
"key1": "value1",
"key2": "value2",
"key3": "value3",
"key4": "value4"
}),
params: {headers: {"Content-Type": "application/json"}}
};
let responses = http.batch([postmethodName1], {
tags: {name: 'methodName1'},
});
trackDataMetricsPerURL(responses);
console.log(`methodName1: responses: ${responses}`)
responses.forEach(response => {
t.expect(response.status).as("response status").toEqual(200)
.and(response).toHaveValidJson()
});
})
&&
describe(`02. AccountmethodName2`, (t) => {
let active_user = testdata[0]
console.log(`02. AccountmethodName2: active_user: ${active_user["param"]}`)
let getAccountmethodName2 = {
method: "GET",
url: `${__ENV.BASE_URL}/get?param=param-pam-pam`,
params: {headers: {"Content-Type": "application/json"}}
};
let responses = http.batch([getAccountmethodName2],
{
tags: {my_tag: "AccountmethodName2"},
});
trackDataMetricsPerURL(responses);
responses.forEach(response => {
t.expect(response.status).as("response status").toEqual(200)
.and(response).toHaveValidJson()
})
})
}
Crosby
October 5, 2021, 10:39am
4
This is how I run it:
export VUs=1; \
export DURATION=1s; \
k6 run -e BASE_URL="https://httpbin.test.k6.io" \
--vus $VUs \
--duration $DURATION \
--verbose \
--http-debug="full" \
--summary-export=/Users/user/projects/qa-qc-t/perf-testing/k6.io/scenario-test.summary_VUs-$VUs_duration-$DURATION.json \
--out statsd \
--out json=/Users/user/projects/qa-qc-t/perf-testing/k6.io/scenario-test.report_VUs-$VUs_duration-$DURATION.json \
--out csv=/Users/user/projects/qa-qc-t/perf-testing/k6.io/scenario-test.report_VUs-$VUs_duration-$DURATION.csv \
/Users/user/projects/qa-qc-t/perf-testing/k6.io/scenario-test.js
Crosby
October 5, 2021, 10:41am
5
And I still get this error:
TypeError: Cannot read property 'headers' of undefined
This is the response logs:
INFO[0003] Request:
POST /post HTTP/1.1
Host: httpbin.test.k6.io
User-Agent: k6/0.34.1 (https://k6.io/)
Content-Length: 65
Content-Type: application/json
Accept-Encoding: gzip
{"key1":"value1","key2":"value2","key3":"value3","key4":"value4"} group="::01. methodName1" iter=0 project_name=MyProject request_id=b0e3fc2b-e6c2-4c62-46e1-1f058466942a scenario=default source=http-debug vu=1
...
INFO[0008] Response:
HTTP/2.0 200 OK
Content-Length: 568
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Content-Type: application/json
Date: Tue, 05 Oct 2021 10:38:17 GMT
Server: gunicorn/19.9.0
{
"args": {},
"data": "{\"key1\":\"value1\",\"key2\":\"value2\",\"key3\":\"value3\",\"key4\":\"value4\"}",
"files": {},
"form": {},
"headers": {
"Content-Length": "65",
"Content-Type": "application/json",
"Host": "httpbin.test.k6.io",
"User-Agent": "k6/0.34.1 (https://k6.io/)",
"X-Amzn-Trace-Id": "Root=1-615c2b19-46522bee378352147d975ebd"
},
"json": {
"key1": "value1",
"key2": "value2",
"key3": "value3",
"key4": "value4"
},
"origin": "95.57.108.193",
"url": "https://httpbin.test.k6.io/post"
}
group="::01. methodName1" iter=0 project_name=MyProject request_id=b0e3fc2b-e6c2-4c62-46e1-1f058466942a scenario=default source=http-debug vu=1
Cannot wrap my head around with what am I actually doing wrong here…
http.batch
returns an array of reponses while the trackDataMetricsPerURL
takes 1 response. If you change the call to trackDataMetricsPerURL(responses[0]);
as you have a single request it will work.
Alternatively, you can iterate over the responses or just not use http.batch
also apparently jslib’s expect is eating up exceptions cc @pawel .
1 Like
Crosby
October 5, 2021, 11:56am
7
Thank you so much! I can’t believe that I’ve completely forgot about array being returned!
Crosby:
export let options = {
duration: '1s',
vus: 1,
iterations: 1,
thresholds: {
endpoint_data_sent: ['count < 2048'],
`endpoint_data_sent{url:${__ENV.BASE_URL}/myEndpoint}`: ['count < 1024'],
`endpoint_data_recv{url:${__ENV.BASE_URL}/myEndpoint}}`: ['count < 2048']
},
tags: {
project_name: 'MyProject',
}
};
ERRO[0000] SyntaxError: file:///Users/user/projects/MyProject/loadtests/minimalBaseScenario.js: Unexpected token (42:4)
40 | // If we want to only consider data points for a particular URL/endpoint we can filter by URL:
41 | // TODO: change URLs to project-related:
> 42 | `endpoint_data_sent{url:${__ENV.BASE_URL}/myEndpoint}`: ['count < 1024'],
| ^
at <internal/k6/compiler/lib/babel.min.js>:2:28542(109)
Could you, please, help with this bit? It is not possible to use template literals as keys in options.thresholds
?
Could you, please, help with this bit? It is not possible to use template literals as keys in options.thresholds
?
No, but you can’t just use a literal template as an object key, which is what you are doing here basically. This is as it isn’t just a simple value but something that needs to be computed, this is supported and is called computed property names and as the link says you just need to put []
around the whole key.
1 Like