I'm in need of help understanding how JSON Path assertions work in Jmeter.
Given the following JSON,
{
"isCompressed": true,
"rows": [
{
"_2": "",
"_4": "CustomString_1401",
"_5": {
"latitude": 0.0,
"longitude": 0.0,
"elevation": 0.0
},
"_6": "CustomString_1401",
"_8": "User0",
"_9": "User",
"_10": [],
"_11": 1641561103991
},
{
"_2": "",
"_4": "CustomString_3930",
"_5": {
"latitude": 0.0,
"longitude": 0.0,
"elevation": 0.0
},
"_6": "CustomString_3930",
"_8": "User0",
"_9": "User",
"_10": [],
"_11": 1641561045657
}
]
}
Any of the following different JSON Path assertions do NOT fail in a JSON Assertion in Jmeter 5.4.3. I'm using just a simple JSON assertion with no value assertion.
$.rows[?(#._4=="Custom")]._4
$.rows[?(#._4=="Custom_3930")]._122
In the case of assertion 1, there is no array element that satisfies that condition.
In case of assertion 2, there's no key with that name in there.
Why is the assertion successful if those paths do not exist?
It sounds like a bug in JMeter connected with presence of the Filter Operators in your query, you should raise it via JMeter Bugzilla
In the meantime you can switch to JSR223 Assertion and Groovy language, the equivalent code would be something like:
def result = com.jayway.jsonpath.JsonPath.read(prev.getResponseDataAsString(), '$.rows[?(#._4=="Custom")]._4')
if (result.size() == 0) {
AssertionResult.setFailure(true)
AssertionResult.setFailureMessage('There were no nodes matching the Json Path query')
}
Related
I'm trying to get the values of these keys from this json response:
{
"wlan": {
"channel": 1,
"ssid": "WLAN-25UR7J",
"mac": "00:17:91:80:22:96",
"inet": [
{
"netmask": "255.255.255.0",
"ip": "192.168.2.112",
"family": "IPv4"
}
],
"stationinfo": {
"signal": -48,
"channelwidth": 0,
"bitrate": 72.2
},
"mode": "station",
"encryption": "WPA2-PSK"
}
}
I could get the values from wlan key by using this method.
json.decode(response.body)['wlan']['channel']
But I didn't work on the rest values like getting netmask or bitrate for example.
For netmask, you can access it like this:
json.decode(response.body)['wlan']['inet'][0]['netmask']
For bitrate, you can access it by:
json.decode(response.body)['wlan']['stationinfo']['bitrate']
If values inside any key is an array, either access them via index like value[0] or you can simply iterate the array and do the necessary action.
I have a JSON response that looks like this:
{
"results": [
{
"entityType": "PERSON",
"id": 679,
"graphId": "679.PERSON",
"details": [
{
"entityType": "PERSON",
"id": 679,
"graphId": "679.PERSON",
"parentId": 594,
"role": "Unspecified Person",
"relatedEntityType": "DOCUMENT",
"relatedId": 058,
"relatedGraphId": "058.DOCUMENT",
"relatedParentId": null
}
]
},
{
"entityType": "PERSON",
"id": 69678,
"graphId": "69678.PERSON",
"details": [
{
"entityType": "PERSON",
"id": 678,
"graphId": "678.PERSON",
"parentId": 594,
"role": "UNKNOWN",
"relatedEntityType": "DOCUMENT",
"relatedId": 145,
"relatedGraphId": "145.DOCUMENT",
"relatedParentId": null
}
]
}
The problem with this JSON response is that $.results[0] is not always the same, and it can have dozens of results. I know I can do individual JSON Assertion calls where I do the JSON with a wild card
$.results[*].details[0].entityType
$.results[*].details[0].relatedEntityType
etc
However I need to verify that both "PERSON" and "DOCUMENT" match correctly in the same path on one api call since the results come back in a different path each time.
Is there a way to do multiple calls in one JSON Assertion or am I using the wrong tool?
Thanks in advance for any help.
-Grav
I don't think JSON Assertion is flexible enough, consider switching to JSR223 Assertion where you have the full flexibility in terms of defining whatever pass/fail criteria you need.
Example code which checks that:
all attributes values which match $.results[*].details[0].entityType query are equal to PERSON
and all attributes values which match $.results[*].details[0].relatedEntityType are equal to DOCUMENT
would be:
def entityTypes = com.jayway.jsonpath.JsonPath.read(prev.getResponseDataAsString(), '$.results[*].details[0].entityType').collect().find { !it.equals('PERSON') }
def relatedEntityTypes = com.jayway.jsonpath.JsonPath.read(prev.getResponseDataAsString(), '$.results[*].details[0].relatedEntityType').collect().find { !it.equals('DOCUMENT') }
if (entityTypes.size() != 1) {
SampleResult.setSuccessful(false)
SampleResult.setResponseMessage('Entity type mismatch, one or more entries are not "PERSON" ' + entityTypes)
}
if (relatedEntityTypes.size() != 1) {
SampleResult.setSuccessful(false)
SampleResult.setResponseMessage('Entity type mismatch, one or more entries are not "DOCUMENT" ' + relatedEntityTypes)
}
More information:
SampleResult class JavaDoc
Groovy: Working with collections
Scripting JMeter Assertions in Groovy - A Tutorial
I have two requests that return response with similar JSON structure. When I try to use JSON extractor on one, it works properly but when I try to extract value in the same way from the second one, it doesn't work. But let's cut to the chase.
My first response looks like this:
{
"values": [
{
"id": 1,
"name": "Fendi",
"logoId": null,
"belongsToUser": true
},
{
"id": 2,
"name": "Jean Paul Gaultier",
"logoId": null,
"belongsToUser": true
},
{
"id": 3,
"name": "Nike",
"logoId": null,
"belongsToUser": false
},
{
"id": 4,
"name": "Adidas",
"logoId": null,
"belongsToUser": true
}
]
}
And I try to extract ID of the object that "belongsToUser": false in this JSON Extractor:
JSON path expression: values[?(#.belongsToUser == false)].id
Match No.: 0
Default Values: null
And it works perfecty fine.
However, when I try this way on my second response, it doesn't work.
The response looks like this:
{
"values": [
{
"id": 12,
"brandName": "Fendi",
"productCategoryName": "Shoes",
"size": "38",
"colorNames": [
"color_green"
],
"date": 1536537600000,
"imageId": null,
"title": "Money",
"numberOfOffers": 0,
"status": "ONGOING"
},
{
"id": 13,
"brandName": "Fendi",
"productCategoryName": "Shoes",
"size": "38",
"colorNames": [
"color_green"
],
"date": 1536537600000,
"imageId": null,
"title": "Exchange",
"numberOfOffers": 0,
"status": "ONGOING"
}
]
}
I try to get id of object that has title variable = "Money" with JSON extractor:
JSON path expression: values[?(#.title == 'Money')].id
Match No.: 0
Default Values: null
But it doesn't find id value and sets my JMeter variable to null.
I also tried to leave Money unquoted or in double quotes and tried different JSON path expresions, like
$.values[?(#.title == 'Money')].id
$..[?(#.title == 'Money')].id
$.[?(#.title == 'Money')].id
But none of these seems to work. Do you have any idea how my JSON path expression shoud look to work properly?
And why doesn't it work in second case when it works in first? Is it because objets in second response have inside array?
I have used your code and it is giving the correct results. Please check the below images.
I have tried with version 3.1 also and it is working fine.
Hope this helps.
Check the below image for different types of options in view result tree.
The $..[?(#.title == 'Money')].id expression should work just fine:
Most probably your JMeter installation is corrupt and you experience some form of jar hell due to some clashing library in JMeter Classpath (it might be caused by presence of deprecated JSON Plugins or similar) . So I would recommend obtaining clean latest version of JMeter and trying out your test on it. If you're using any plugins - install them using JMeter Plugin Manager
If you are not in position to re-install JMeter you can try to get to the bottom of the issue by looking into jmeter.log file. If there are no suspicious entries - add the next line to log4j2.xml file:
<Logger name="org.apache.jmeter.extractor.json" level="debug" />
just like the question asked here
I do a query or scan operation on dynamoDB using dynamoDB proxy service on AWS API Gateway to read data for the Client and I get DynamoDB formatted JSON data in reply.
Although I can use the "Method Response" to convert but when the Data is above 1000 records - I cannot handle it due to the limitation of foreach loop in Method Response.
Is there a flag or a setting somewhere in dynamodb or in api gateway such that I get normal json rather than the dynamoDB formatted JSON ?
DynamoDB Formatted JSON example
{
"videos": [
{
"file": {
"S": "file1.mp4"
},
"id": {
"S": "1"
},
"canvas": {
"S": "This is Canvas1"
}
},
{
"file": {
"S": "main.mp4"
},
"id": {
"S": "0"
},
"canvas": {
"S": "this is a canvas"
}
}
]
}
Normal Json example of the same
{
"videos": [
{
"file": "file1.mp4",
"id": "1",
"canvas": "This is Canvas1"
},
{
"file": main.mp4",
"id": "0",
"canvas": "this is a canvas"
}
]
}
Using an Integration Response mapper!
The mapper would probably look something like: (I'm using your provided response)
#set($inputRoot = $input.path('$'))
{
"videos": [
#foreach($elem in $inputRoot.Items)
{ "file": "$elem.file.S",
"id": "$elem.id.S",
"canvas": "$elem.canvas.S" }#if($foreach.hasNext), #end
#end
]
}
Please consult the linked documentation for more complete guidance on attaching AWS Services directly to API Gateway.
The possible solution for this is using a aws lambda to query/scan dynamoDb and reply back the domain object after converting it into a json using some json lib, like GSON or jackson.
If any one has knowledge about an alternate option - please do post here. Thanks
Please help me in parsing this Json sample as I'm not able to parse it because of the complexity of it as well as different objects inside it. I'm able to parse Json when a list of same objects & same structure but not like the one below.
[
{
"notificationBrowserHead":
{
"notificationId": 4,
"notificationType": "NEW_PRODUCT",
"creationTime": 1421933381000,
"notificationNormalUserId": 4,
"notificationViewed": false
},
"brandIdAndNameHolder":
{
"brandId": 1,
"name": "B1"
},
"brandLogo": null,
"productIdAndNameHolder":
{
"productId": 1,
"name": "JK product1"
}
},
{
"notificationBrowserHead":
{
"notificationId": 2,
"notificationType": "USER_INT_COMMENT",
"creationTime": 1421924403000,
"notificationNormalUserId": 2,
"notificationViewed": false
},
"uploadId": 22,
"uploadThumbnail": "/mediaUrl/location/thumbNail",
"uploadDescription": "upload 1 location desc",
"notificationCreator":
{
"normalUserId": 90,
"displayName": "amit"
},
"uploadRemoved": false
},
{
"notificationBrowserHead":
{
"notificationId": 1,
"notificationType": "NEW_LOCATION_VOTE",
"creationTime": 1421924403000,
"notificationNormalUserId": 1,
"notificationViewed": false
},
"locationIdAndNameHolder":
{
"locationId": 11,
"name": "Current King JK"
},
"locationLogo": null
}
]
Any help would be truly appreciated.
I presume that you receive different set of json properties when your NotificationType varies.
Solution 1:
Define all your members(the collection of all your properties that you receive for different types of notification) in a Class and use it for DeSerialization, so that the unwanted properties for your particular notification type will be null.
Solution 2:
Parser manually. Newtonsoft json documentation here
Make class "Notifications (or something)" and put inside everything you got back from json2csharp.com site, then use this framework http://www.newtonsoft.com/json to deserialize data as you download it from server and you should be able to get notificationType by Object.Notificationbrowserhead[x].notificationType or similar.