JMeter JSR223 preprocessor cannot parse JSON with placeholder - jmeter

In a JMeter test plan I need to do the following...
Generate TID puts a more or less random number into vars.tid.
The Calculate checksum preprocessor calculates a checksum which is put into vars.checksum. This checksum, however, depends on the tid and further data (var1 and var2) from the JSON payload in Send request.
Example for the JSON body
{
"event": {
"checksum": "${checksum}",
"tid": ${tid},
},
"data": {
"var1": "value1",
"var2": "value2
}
}
Calculate checksum
import groovy.json.JsonSlurper
def jsonSlurper = new JsonSlurper()
def requestBodyString = sampler.getArguments().getArgument(0).getValue();
def json = jsonSlurper.parseText(requestBodyString)
def tid = vars.get('tid')
def checkusm = calculateChecksum(tid, json.var1, json.var2)
vars.put('checksum', checksum)
Now, the JsonSluper seems to no actually parse the content because of "tid": ${tid} which is not valid JSON. As a consequence, the checksum won't get replaced before sending the request.
Do you have any ideas how to work around this?

If you need to resolve the "placeholders" and replace them with the relevant variables values you need to use __eval() function in conjunction with __FileToString() function and pass the result to the JsonSlurper:
More information on JMeter Functions concept: Apache JMeter Functions - An Introduction

Related

Jmeter extracting values from response and sending to other requests

I have a JSON response below:
"books": [
{
"name" : "test1",
"id" : "T01"
},
{
"name" : "test2",
"id" : "T02"
},
{
"name" : "test3",
"id" : "T03"
},
]
I am extracting all respective ids and sending it as a body to another request.
Other request takes it as an array of strings but when I am extracting it, it is showing as integers:
Currently it shows: ids_ALL = [T01, T02, T03]
and I have to pass it like: ids_ALL = ["T01", "T02", "T03"]
Note: I am suffixing _ALL to get all ids.
Since it is not passing the array as string, I am getting an error.
Is there away to extract it and put it in array of strings or way to use post-processer and then convert the array and send to other request.
This one-liner will extract all the IDs and generate the JSON Array you're looking for:
vars.put('payload', (new groovy.json.JsonBuilder(new groovy.json.JsonSlurper().parse(prev.getResponseData()).books.id.collect()).toPrettyString()))
no other extractors are needed, you can refer the generated array as ${payload} later on where required
In Taurus it can be put into the JSR223 Block
More information:
Apache Groovy - Parsing and producing JSON
Apache Groovy - Why and How You Should Use It
You can use JSON Extractor or JSON JMESPath Extractor to extract all the ids from the response.
Place a JSR223 Post processor just below the JSON Path Extractor to create a list of Strings (ids)
def idCount=vars.get("booksIds_matchNr").toInteger()
def lstIds=[]
for(i in 1..idCount){
String currentId=vars.get("booksIds_" + i)
lstIds.add("\""+ currentId + "\"" )
//lstIds.add("${currentId}" )
}
vars.putObject("lstIds",lstIds)
You can access the list with vars.getObject("lstIds")
List of strings could be seen in the view result tree.
Another quick solution
Add a JSR223 Post Processor below the JSON Extractor to create strings with the available values.
String booksIds_ALL=vars.get("booksIds_ALL")
def lstIds = "\"" + booksIds_ALL.replace(",", "\",\"") + "\""
vars.putObject("lstIds",lstIds)

Read data from CSV and create Json Array in Jmeter

I have One POST request and below is the My Body Payload .
{
"ABC": "ITBK1",
"Code": "AH01001187",
"ScheduleDate": "2021-09-02T22:59:00Z",
"FilterType": 2,
"FilterData": [
"LoadTest92","LoadTest93"
]
}
I'm passing the ContractorId to filterData as below.
{
"ABC": "ITBK1",
"Code": "AH01001187",
"ScheduleDate": "${startTo}",
"FilterType": 2,
"FilterData": ["${contractorId}"]
}
but it taking one id at a time for this Json. How can i send multiple data for this FilterData jsonArray from csv please help on this.
First of all don't post code (including CSV file content) as image
As per CSV Data Set Config documentation:
By default, the file is only opened once, and each thread will use a different line from the file. However the order in which lines are passed to threads depends on the order in which they execute, which may vary between iterations. Lines are read at the start of each test iteration. The file name and mode are resolved in the first iteration.
So it means that you need to go to the next iteration in order to read the next line.
If you want to send all the values from column J as the "FilterData" you could do something like:
Add JSR223 PreProcessor as a child of the request you want to parameterize
Put the following code into "Script" area:
def lines = new File('/path/to/your/file.csv').readLines()
def payload = []
lines.each { line ->
def contractor = line.split(',')[9]
payload.add(contractor as String)
}
vars.put('payload', new groovy.json.JsonBuilder(payload).toPrettyString())
That's it, use ${payload} instead of your ["${contractorId}"] variable in the HTTP request.
More information:
JsonBuilder
JMeterVariables
Apache Groovy - Why and How You Should Use It

Is it possible to remove empty query string parameters in jMeter?

I want to test an endpoint using jmeter, that has a copule of query string parameters, one of which is optional, loading the values from a CSV file. The problem is, can I avoid sending the query string parameter if I don't have a value for it?
It is but it will require some Groovy coding
Add JSR223 PreProcessor as a child of the request which query string you want to modify (or according to JMeter Scoping Rules if you want to apply the approach to more than one request)
Put the following code into "Script" area:
def newData = new org.apache.jmeter.config.Arguments()
0.upto(sampler.getArguments().size() - 1, { idx ->
def arg = sampler.getArguments().getArgument(idx)
if (!arg.getValue().equals('')) {
newData.addArgument(arg)
}
})
sampler.setArguments(newData)
That's it, the PreProcessor will be executed before the HTTP Request sampler and will remove all arguments which don't have their respective values

How to assert a JSON response which have results in random order every time in JMeter?

I am using JSON Assertion to assert if a JSON path exists. Suppose I have a JSON response of an array of 'rooms' that 'contains' an array of cabinets, just like the following example
"rooms":
[
{
"cabinets":
[
{
"id":"HFXXXX",
"locationid":null,
"name":"HFXXXX",
"type":"Hosp"
},
{
"id":"HFYYYY",
"locationid":null,
"name":"HFYYYY",
"type":"Hosp"
},
{
"id":"HFZZZZ",
"locationid":null,
"name":"HFZZZZ",
"type":"Hosp"
}
],
"hasMap":false,
"id":"2",
"map":
{
"h":null,
"w":null,
"x":null,
"y":null
},
"name":"Fantastic Room#3"
}
],
[
{ "cabinets":
[
{
"id":"HFBBBB",
"locationid":null,
"name":"HFBBBB",
"type":"Hosp"
}
],
"hasMap":false,
"id":"3",
"map":
{
"h":null,
"w":null,
"x":null,
"y":null
},
"name":"BallRoom #4"
}
]
I want to Make sure that the 'id' of all the cabinets are correct, therefore I define the JSON path as rooms[*].cabinets[*].id and expect the value to be ["HFXXXX","HFYYYY","HFZZZZ","HFBBBB"]
This works perfectly except that sometimes the values are returned in a different order["HFBBBB", "HFXXX","HFYYYY","HFZZZZ"] instead of ["HFXXXX","HFYYYY","HFZZZZ","HFBBBB"], hence the assertion will fail. The problem is with the order of the returned array and not the values themselves.
Is there a way to sort the order of a response before Asserting and keep using the JSON assertion? or the only way of doing this is extracting the value i want to assert against and use it in JSR223 Assertion (groovy or javascript)?
if that is the case can you show me an example of how I could do it in JSR223 plugin.
I would recommend using a dedicated library, for instance JSONAssert, this way you will not have to reinvent the wheel and can compare 2 JSON objects in a single line of code
Download jsonassert-x.x.x.jar and put it somewhere to JMeter Classpath
Download suitable version of JSON in Java library and put it to JMeter Classpath as well. If you're uncertain regarding what is "JMeter Classpath" just drop the .jars to "lib" folder of your JMeter installation
Restart JMeter so it would be able to load the new libraries
Add JSR223 Assertion as a child of the request which returns the above JSON
Put the following code into "Script" area:
def expected = vars.get('expected')
def actual = prev.getResponseDataAsString()
org.skyscreamer.jsonassert.JSONAssert.assertEquals(expected, actual, false)
It will compare the response of the parent sampler with the contents of ${expected} JMeter Variable, the order of elements, presence of new lines, formatting do not matter, it compares only keys and values
In case of mismatch you will have the error message stating that as the Assertion Result and the full debugging output will be available in STDOUT (console where you started JMeter from)

Obtain index of random element from json array in JMeter Json Path Post Processor

I have strange case for jmeter. Imagine that we have an json array with elements like this:
{
"id" : 123456,
"name": "TEST"
}
So I want to get random element from array that has id. For this case I use Json Path PostProcessor with expression like this $.elements[?(#.id)]
But for some reasons I need an index of this element. So I can create BeanShellPostProcessor generate random index and then use same Json Path PostProcessor with expression like this $.elements[${PARAM_ElementIndex}].
But in some cases this array can be empty and Json Path PostProcessor wil fail with exception like this:
jmeter.extractor.json.jsonpath.JSONPostProcessor: Error processing JSON content in PARAM_ResumeId, message:No results for path: $['elements'][0]['id']
So may be someone can suggest any solution
I would recommend use Groovy instead of Beanshell as:
Well-behaved Groovy scripts can be compiled into bytecode therefore performance will be much higher
Groovy has built-in JSON support
So given you have JSON Response like:
{
"elements": [
{
"id": 123456,
"name": "TEST"
},
{
"id": 7890,
"name": "TEST2"
}
]
}
You can extract random ID along with its index using the following example Groovy code in the JSR223 PostProcessor:
import groovy.json.JsonSlurper
import java.util.concurrent.ThreadLocalRandom
String response = prev.getResponseDataAsString()
def jsonSlurper = new JsonSlurper()
def json = jsonSlurper.parseText(response)
int size = json.elements.size
if (size > 0){
def randomIndex = ThreadLocalRandom.current().nextInt(size)
def value = json.elements.get(randomIndex).id
log.info('Index: ' + randomIndex)
log.info('Value: ' + value)
}
Demo:
References:
Parsing and producing JSON
Beanshell vs JSR223 vs Java JMeter Scripting: The Performance-Off You've Been Waiting For!

Resources