JMeter Dynamic JSON list generation - json

i'm using the following groovy script :
def oldRequest = new groovy.json.JsonSlurper().parseText(sampler.getArguments().getArgument(0).getValue())
oldRequest.values().removeAll{it.equals('null')}
oldRequest.advancedFilters.values().removeAll{it.equals('null')}
def newRequest = new groovy.json.JsonOutput().toJson(oldRequest)
sampler.getArguments().removeAllArguments()
sampler.setPostBodyRaw(true)
sampler.addNonEncodedArgument('',new groovy.json.JsonOutput().prettyPrint(newRequest),'')
to remove Keys from JSON request where the values are "Null", i also want to include logic to convert below JSON:
{
"sortOrder": "A",
"sortField": "policyNumber",
"searchTerritories": [ter1|ter2|ter3],
"pageNumberRequested": "1",
"pageCountRequested": "50",
"policyStatus" : "${ActionStatus}",
"includeTerm : "null",
"advancedFilters": {
"test" : "null",
"test1" : [A|B],
"test1" : [C|D|E]}
}
to:
{
"sortOrder": "A",
"sortField": "policyNumber",
"searchTerritories": ["ter1","ter2","ter3"],
"pageNumberRequested": "1",
"pageCountRequested": "50",
"policyStatus" : "${ActionStatus}",
"advancedFilters": {
"test1" : ["A","B"],
"test2" : ["C","D","E"]}
}
I want the input JSON values to be converted from [ter1|ter2|ter3] to ["ter1","ter2","ter3"] and [A|B] [C|D|E] converted to ["A","B"] ["C","D","E"], please help me with the groovy script modifications required.

Your source data is not a valid JSON, you can check it using i.e. online JSON validation tool
Therefore unfortunately you will not be able to use JsonSlurper, you will have to treat the source data as normal text and amend it according to your needs using i.e. Regular Expressions
Example code:
def oldRequest = sampler.getArguments().getArgument(0).getValue()
log.info('Before: ' + oldRequest)
oldRequest = oldRequest.replaceAll('(\\w+)\\|', '"$1",').replaceAll('(\\w+)\\]', '"$1"]').replaceAll("(?m)^.*null.*(?:\\r?\\n)?","")
def matcher = (oldRequest =~ /test\d+/)
def i = 0
while (matcher.find()) {
oldRequest = oldRequest.replaceFirst(matcher.group(0), 'test' + ++i)
}
log.info('After: ' + oldRequest)
sampler.getArguments().removeAllArguments()
sampler.addNonEncodedArgument('', oldRequest, '')
sampler.setPostBodyRaw(true)
Demo:
More information:
Groovy Goodness: Matchers for Regular Expressions
Apache Groovy - Why and How You Should Use It

Related

Dynamic variables in json with Django settings values

I am working with a python library for a certain api service. And in order to connect to their account, they use the json file.
This is how the API connection looks like.
api = VoximplantAPI('credentials.json')
credentials.json
{
"account_email": "my email",
"account_id": "ac_id",
"key_id": "key_id",
"private_key": "private"
}
I removed the values.
I have a question, how can I add dynamic variables to json so that I can take values ​​from Django settings, for example using Jinja. I have been looking for an answer for several hours, but I have not found an answer.
Json in python is technically Dictionary, so you can update the same way you update dictionary
For example,
a = {"a": 123}
b = {"b": 456}
And by writing a.update(b) you will get in response
{"a": 123, "b": 456}
The same way loop through all the data you wan to add in json
For example,
final_json = {
"account_email": "my email",
"account_id": "ac_id",
"key_id": "key_id",
"private_key": "private"
}
users = User.objects.filter(name="test")
temp_dict = {}
count = 1
for user in users:
temp_dict.update({f"first_name{count}": user.first_name})
count += 1
And then update your final_json by
final_json.update(temp_dict)
You will get your json as:
{
"account_email": "my email",
"account_id": "ac_id",
"key_id": "key_id",
"private_key": "private",
"first_name1": "value_1",
"first_name2": "value_2",
..
..
..
}

Jmeter - Passing specific JSON response to HTTP request dynamically

I am having a specific requirement in Jmeter(2.13) where i need to pass two parameters multiple times dynamically as id and parentObjectApiName
{
"id":"SomeNumber",
"parentObjectApiName":"SomeName"
},
{
"id":"SomeNumber",
"parentObjectApiName":"SomeName"
},
}
Which i will be getting from a response as :
{
"detailMap": {
"RootNumber": [
{
"id": "SomeNumber",
"properties": {
},
"isDeleted": false,
"version": "2017-11-20T08:13:30+00:00",
"referenceId": null,
"parentObjectApiName": "SomeName"
},
{
"id": "SomeNumber",
"properties": {
},
"isDeleted": false,
"version": "2017-04-21T15:40:10.742+00:00",
"referenceId": null,
"parentObjectApiName": "SomeName"
},
{
:
},
]
}
"state": {
"errorDetails": []
}
}
Is there any workaround for the above requirement by using beanshell in Jmeter(2.13).
Your requirement can be achieved by following the steps below.
Add "JSON Extractor" to the request where the response contains the parameters which you want to pass in next request.(Image-1)
JSON Extractor configuration(Image-2)
Keeping the JSON Extractor as it is, Add "Beanshell PostProcessor" to the request and keep the following part of code and try. Your desired id & parentObjectApiName will be stored in variable "json". You can call it in your next request as ${json}
import java.io.file;
import java.util.*;
import org.apache.jmeter.services.fileserver;
StringBuilder output = new StringBuilder();
Random random = new Random();
int max = Integer.parseInt(vars.get("id_matchNr"));
for(int i=1;i<=max;i++)
{
output.append("{");
output.append("\"id\":\"" + vars.get("id_"+i) + "\",\"parentObjectApiName\":" + vars.get("parentObjectApiName_"+i));
output.append("}").append( "," );
}
String withoutLastComma = output.substring( 0, output.length( ) - ",".length( ) );
vars.put("json", withoutLastComma.toString());
Image-1
Image-2
Be aware that since JMeter 3.1 it is recommended to use JSR223 Test Elements and Groovy language for any scripting in JMeter. Groovy has much better performance than Beanshell does, moreover Groovy has built-in JSON support.
Add JSR223 PostProcessor as a child of the request which returns the above JSON
Make sure you have groovy selected in the "Language" dropdown and Cache compiled script if available box ticked
Put the following code into "Script" area:
import groovy.json.JsonBuilder
import groovy.json.JsonOutput
import groovy.json.JsonSlurper
import groovy.json.internal.LazyMap
def text = prev.getResponseDataAsString()
log.info('Original response: ' + text)
def json = new JsonSlurper().parseText(text)
def data = new ArrayList()
json.detailMap.RootNumber.each { rootNumber ->
def map = new LazyMap()
map.put("id", rootNumber.id)
map.put("parentObjectApiName", rootNumber.parentObjectApiName)
data.add(map)
}
vars.put('json',JsonOutput.prettyPrint(JsonOutput.toJson(data)))
log.info('Generated json: ' + vars.get('json'))
The above code will generate the following JSON:
[
{
"id": "SomeNumber",
"parentObjectApiName": "SomeName"
},
{
"id": "SomeOtherNumber",
"parentObjectApiName": "SomeOtherName"
}
]
You will be able to access it as ${json} where required (i.e. in next HTTP Request sampler "Body Data" tab)

Jmeter Dynamic Json Array Generation from CSV file

I have a following Json data to post.
{
"id": 1,
"name": "Zypher",
"price": 12.50,
"tags": [{
"tag": 1,
"tagName": "X"
},
{
"tag": 2,
"tagName": "Y"
},
{
"tag": 2,
"tagName": "Z"
}]
}
My Jmeter Test Plan is as following,
- Test Plan
- Thread Group
- Http Request Defaults
- Http Cookie Manager
- Simple Controller
- CSV Data Set Config (Sheet_1)
- Http Header Manager
- Http Request (The hard coded json was provided here as body data)
Every thing works fine. Now I want to use csv to parametrised my Json.
Sheet_1:
id,name,price
1,Zypher,12.50
I modified json with these 3 parameters and its works for me. Now I want to parametrise detail portion. I have no idea how to do this.
All I want to keep my json like this,
{
"id": ${id},
"name": ${name},
"price": ${price},
"tags": [
{
"tag": ${tag},
"tagName": ${tagName}
}]
}
How could I dynamically make json array tags for details portion from csv data? I want it to be looped as row provided in csv file.
Updated csv
id,name,price,tag,tagname
1,Zypher,12.50,7|9|11,X|Y|Z
It would be great in this format
id,name,price,tag
1,Zypher,12.50,7:X|9:Y|11:Z
tag has two properties dividing by :
You can do it using JSR223 PreProcessor and Groovy language, something like:
Given you have the following CSV file structure:
id,name,price,tag
1,Zypher,12.50,X|Y|Z
And the following CSV Data Set Config settings:
Add JSR223 PreProcessor as a child of the HTTP Request sampler and put the following code into "Script" area:
import groovy.json.JsonBuilder
def json = new JsonBuilder()
def tagsValues = vars.get("tags").split("\\|")
class Tag {int tag; String tagName }
List<Tag> tagsList = new ArrayList<>()
def counter = 1
tagsValues.each {
tagsList.add(new Tag(tag: counter, tagName: it))
counter++
}
json {
id Integer.parseInt(vars.get("id"))
name vars.get("name")
price Double.parseDouble(vars.get("price"))
tags tagsList.collect { tag ->
["tag" : tag.tag,
"tagName": tag.tagName]
}
}
sampler.addNonEncodedArgument("",json.toPrettyString(),"")
sampler.setPostBodyRaw(true)
Remove any hard-coded data from the HTTP Request sampler "Body Data" tab (it should be absolutely blank)
Run your request - JSON payload should be populated dynamically by the Groovy code:
References:
Parsing and producing JSON - Groovy
Groovy Is the New Black
Update:
for CSV format
id,name,price,tag
1,Zypher,12.50,7:X|9:Y|11:Z
Replace the below Groovy code:
List<Tag> tagsList = new ArrayList<>()
def counter = 1
tagsValues.each {
tagsList.add(new Tag(tag: counter, tagName: it))
counter++
}
with
List<Tag> tagsList = new ArrayList<>();
tagsValues.each {
String[] tag = it.split("\\:")
tagsList.add(new Tag(tag: Integer.parseInt(tag[0]), tagName: tag[1]))
}

Changing the labels jsonBuilder creates automatically in Groovy after converting Obj to JSON

I have a class called Case which is like:
class Case {
String caseId;
Map <String, List<String[]>> listOfCases = new HashMap<String, ArrayList<String[]>>();
}
I created several of these cases and add them to a list. Eventually I want to print the list in JSON format in groovy like:
for (...){
// creating many of these cases in a loop and adding to caseList
caseList.add(myCase);
}
// Finally printing them
println new JsonBuilder( caseList ).toPrettyString()
Result looks like this, I chose one only:
{
"caseId": "Case_1",
"listOfCases": {
"server-config.xml": [
[
"Core",
"8"
]
],
"server-beans.xml": [
[
"plugin",
"mmap"
],
[
"maxIdle",
"16"
],
[
"minIdle",
"16"
],
[
"maxCon",
"16"
]
]
}
}
I want the listOfCases be replaced with Case_1 so each time I create a new Case with the number incremented, the name follows. Is there anyway to customize the jsonBuilder in groovy to do this ?
As stated in How to modify JSON in groovy changing the content is dangerous, as it attempts to change the original object. The solution presented there is to send the proper map.
You can prepare a map from your data and pass this like this:
class Case {
String caseId
Map<String,List<List<String>>> listOfCases
}
def caseList = (1..3).collect{
new Case(caseId: "Case$it", listOfCases: [ 'abcde': [['1','2'],['4','5']]])
}
println new groovy.json.JsonBuilder(caseList.collect{[caseId: it.caseId, "$it.caseId": it.listOfCases]}).toPrettyString()
results in
[
{
"caseId": "Case1",
"Case1": {
"abcde": [
...

how json schema validate mixed property?

{ 'a': 343, 'b': 434 }
If I have a json data like above and the property 'a' and 'b' actually is a name give by user, so that can be any string. How can I create a json-schema to validate this?
Provided the validation library you're using is based on a relatively recent version of the JSON Schema, you should be able to use patternProperties to validate properties with user-defined keys.
Here is a quick example that uses the javascript library tv4 to perform the validation:
var schema = {
"patternProperties": {
"^[a-zA-Z0-9]+$": {
"title": "someUserDefinedPropertyName",
"type": "number"
}
}
};
var valid = { "a": 1234, "b": 5678 };
var invalid = { "a": "1234", "b": 5678 };
alert("Validates? [should be true]: " + tv4.validate(valid, schema));
alert("Validates? [should be false]: " + tv4.validate(invalid, schema));
alert('Variable invalid, error at data path: ' + tv4.error.dataPath + '\n\nError Description:\n' + tv4.error.message);
For more information, I suggest reading the section of the Schema linked above, as well as checking out the advanced examples on json-schema.org.