JMeter: How to count JSON objects in an Array using jsonpath - arrays

In JMeter I want to check the number of objects in a JSON array, which I receive from the server.
For example, on a certain request I expect an array with 5 objects.
[{...},{...},{...},{...},{...}]
After reading this: count members with jsonpath?, I tried using the following JSON Path Assertion:
JSON Path: $
Expected value: hasSize(5)
Validate against expected value = checked
However, this doesn't seem to work properly. When I actually do receive 5 objects in the array, the response assertion says it doesn't match.
What am I doing wrong?
Or how else can I do this?

Although JSONPath Extractor doesn't provide hasSize function it still can be done.
Given the example JSON from the answer by PMD UBIK-INGENIERIE, you can get matches number on book array in at least 2 ways:
1. Easiest (but fragile) way - using Regular Expression Extractor.
As you can see, there are 4 entries for category like:
{ "category": "reference",
{ \"category\": \"fiction\"
...
If you add a Regular Expression Extractor configured as follows:
It'll capture all the category entries and return matches number as below:
So you will be able to use this ${matches_matchNr} variable wherever required.
This approach is straightforward and easy to implement but it's very vulnerable to any changes in the response format. If you expect that JSON data may change in the foreseeable future continue with the next option.
2. Harder (but more stable) way - calling JsonPath methods from Beanshell PostProcessor
JMeter has a Beanshell scripting extension mechanism which has access to all variables/properties in scope as well as to the underlying JMeter and 3rd-party dependencies APIs. In this case you can call JsonPath library (which is under the hood of JsonPath Extractor) directly from Beanshell PostProcessor.
import com.jayway.jsonpath.Criteria;
import com.jayway.jsonpath.Filter;
import com.jayway.jsonpath.JsonPath;
Object json = new String(data);
List categories = new ArrayList();
categories.add("fiction");
categories.add("reference");
Filter filter = Filter.filter(Criteria.where("category").in(categories));
List books = JsonPath.read(json, "$.store.book[?]", new Filter[] {filter});
vars.put("JSON_ARRAY_SIZE", String.valueOf(books.size()));
The code above evaluates JSONPath expression of $.store.book[?] against parent sampler response, counts matches number and stores it into ${JSON_ARRAY_SIZE} JMeter Variable
which can later be reused in an if clause or an assertion.
References:
JMeter – Working with JSON – Extract JSON response
JMeter's User Manual Regular Expressions entry
JSON Path Documentation and Examples
How to use BeanShell: JMeter's favorite built-in component

This is not possible with the plugin you are using (JMeter-plugins).
But it can be done with JSON Extractor since JMeter 3.0, this plugin has been donated by UbikLoadPack (http://jmeter.apache.org/changes_history.html)
Example:
Say you have this JSON that contains an array of books:
{ "store": {"book": [
{ "category": "reference","author": "Nigel Rees","title": "Sayings of the Century","price": 8.95},
{ "category": "fiction","author": "Evelyn Waugh","title": "Sword of Honour","price": 12.99},
{ "category": "fiction","author": "Herman Melville","title": "Moby Dick","isbn": "0-553-21311-3","price": 8.99},
{ "category": "fiction","author": "J. R. R. Tolkien","title": "The Lord of the Rings","isbn": "0-395-19395-8","price": 22.99}
],
"bicycle": {"color": "red","price": 19.95}} }
To have this count:
1/ Add JSON Extractor:
The count will be then available bookTitle_matchNr which you can access through:
${bookTitle_matchNr}
Running this Test Plan would display this:
As you can see, Debug Sampler-${bookTitle_matchNr} shows Debug Sampler-4

Related

Mongo query to filter with an array specific index based on parameters

I have a few documents in a mongoDB that have the following structure
In a API web application that I am developing with spring boot I have to code the following query. I can receive a voltageLevelCode to filter register that will contains this voltage level code in the array (That it is easy) but the problem is that i can also receive a voltageLevelCode and a Type, so in this case I have to filter documents that will contains this voltage level code in the array and also WITHIN this voltage level code filter the ones that contains this type (But remember, the type within the voltage level)
I have been trying to write the query but I dont know how to dynamically set the index to filter the types within this voltage level. Something like:
{"voltageLevel.<TheIndexByTheDefinenVoltageLevelCode>.types" : "X" }
Example:
public List<MyClassRepresenting> findByFilter(String type,String voltageLevelCode);
{$and: [{'voltageLevel.voltageLevelCode' : ?1 },{'voltageLevel.<HowTogetIndexForSelectingVoltageLevelCode>.types' : ?2}]}
In this case depending on the tensionLevel received the type parameter must filter according to types within this tensionLevel
Same happens to me with another query. In SQL the equivalent is the SELECT within another SELECT to select the sub registers but no idea about how to do it in mongo.
When asking a question on stackoverflow, it's always interesting to include what you already tried.
I think what you need is a simple $elemMatch:
db.mycoll.find(
{ voltageLevel: { $elemMatch: { voltageLevelCode: "MT", types: "E" } } }
)

how get all id from json to array on other variables - jmeter

I have two JSON. In the both I have name. How can I get names from first JSON and add to array? Later I want do this same with second JSON later i want both array compare? How can I do this?
jsonArray1 = [{'name': "doug", 'id':5}, {'name': "dofug", 'id':23}];
jsonArray2 = [{'name': "goud", 'id':1}, {'name': "doaaug", 'id':52}];
for example I want:
a = [doug, dofug] b = [goud, doaaug]
and later check if these are the same arrays
i don't know how can i do this in jmeter, help
To convert one array to another:
Add JSR223 PostProcessor as a child of the request which returns first JSON Array
Put the following code into "Script" area:
def builder = new groovy.json.JsonBuilder()
builder(com.jayway.jsonpath.JsonPath.read(prev.getResponseDataAsString(),'$..name').collect())
vars.put('array1', builder.toPrettyString())
That's it, you should be able to access the newly generated JSON Array as ${array1} where required
Repeat the same steps for the second JSON array.
There are several options on how to compare 2 JSON entities, depending on what you're trying to achieve you can go for:
Response Assertion
a JSR223 Assertion and a 3rd-party library like:
Jackson
Gson
JSONassert

Object id is missing in Django framework when posted from AngularJS MongoDB

I am posting the following object
{
skillName : "Professional Skills"
_id : {$oid: "5adf23946ab671bf6cb36aff"}
}
to the DjangoService given below:
#csrf_exempt
#api_view(['GET','POST'])
def saveSubjectView(request): #this service will add & update Subject
if request.method == 'POST':
try:
stream = StringIO(request.body)
subject = JSONParser().parse(stream)
print("The subejct is ")
pp.pprint(subject)
serializedsubject = json.loads(json_util.dumps(subject))
print("serializedsubject")
pp.pprint(serializedsubject)
The output that I am getting is
'skillType': { u'_id': { }, u'skillName': u'Professional Skills'}
The ObjectId posted from the front end (AngularJS) is not printed in the service. I know that I can fix it by removing the $oid while posting from the AngularJS application. But I would like to know why this is not happening. I have searched the documents and I couldn't get a proper reply. May be the keywords I used are wrong. Keywords used are : "JSON serialisation of ObjectId", "$oid json serialization using Django".
The complete object I am posting to the Django service is given below:
Exactly. $oid or anything prefixed with $ is an internal format and reserved, so you cannot post field names. The convention is from MongoDB Extended JSON where such prefixes are used to identify the BSON Type for proper conversion, and used as a serializable transport since these "types" are not supported in basic JSON.
So the solution is to actually use the bson.json_util to "deserialize" the JSON string right from the start:
from bson import json_util
# serializedsubject = json.loads(json_util.dumps(subject))
serializedsubject = json_util.loads(request.body) # correct usage
Or more succinctly self contained:
input = '{ "skillName" : "Professional Skills" ,"_id" : { "$oid": "5adf23946ab671bf6cb36aff"} }'
json_util.loads(input)
Returns
{u'skillName': u'Professional Skills', u'_id': ObjectId('5adf23946ab671bf6cb36aff')}
This correctly casts objects from any keys notated with the Extended JSON Syntax to their correct BSON Type, as also supported in the driver functions. And naturally the driver will then convert back to BSON when sending to MongoDB.
If for some reason your request.body contains anything other than a "string" which is valid for input to the function, then it is up to your code to convert it to that point. But there should be no need to "parse to JSON" and then "stringify" again just to input to the function.
NOTE: If you have not already done so within your JavaScript client side of the application, there is also the bson package available. This would allow where such Extended JSON is "received" from the server the translation into the BSON Types as JavaScript Objects, and of course then the serialization of such objects back into the Extended JSON Format.
This would in fact be recommended where "type" information needs to be maintained with the data transmitted and kept between client and server.

Finatra FeatureTests: How to manually deserialize returned json

I read the Finatra getting started guide and I was able to write the HelloWorld Service and its feature test.
Currently my feature test looks like
server.httpPost(
path = "/hi",
postBody = """{"name": "Foo", "dob": 136190040000}""",
andExpect = Ok,
withBody = """{"msg":"Hello Foo. You are 15780 days old today"}""")
This works fine and my tests pass. However my requirement is that I extract the json returned by the server and then manually perform asserts on the object returned.
I changed my code to
val response = server.httpPost(
path = "/hi",
postBody = """{"name": "Abhishek", "dob": 136190040000}""",
andExpect = Ok,
withBody = """{"msg":"Hello Abhishek. You are 15780 days old today"}""")
val json = response.contentString
This also works and I can see the json returned in side the variable json.
My question is that if I have to deserialize this json into an object. Should I just pull in any json library like circe? and then deserialize the object?
or can I use the jackson framework which comes inside of Finatra.
In all examples I could find, I see that Finatra "automatically" handles the json serialization and deserialization. But in my case I want to perform this manually.
You can use the FinatraObjectMapper by calling (using your example) server.mapper. That wraps a Jackson ObjectMapper that you could use if you wanted to use the Jackson library without any of the Finatra add ons.
Or you can import your a different JSON library. If you are using SBT, you can restrict libraries to certain areas of your code, so if you wanted to use circe only in the test code, you could add the following to your build.sbt
"org.scalatest" %% "scalatest" % "2.2.6" % "test"

Sumologic - split JSON array into multiple records

I am passing a JSON array object in the HTTP POST as
[{"level":"INFO","data": "Test 1"},{"level":"INFO","data": "Test 2"}]
This message is seen as 1 object/log message in SumoLogic. How can I tell SumoLogic to consider each JSON object as an independent object and show 2 log messages instead of one?
I believe this can't be done with the json operator. But, have a look at the docs for the "parse regex" operator. There's an option called "multi" which creates a new message for each match of the regex. In your case, something like this might do the trick:
parse regex "\{?<fieldname>.*?\}" multi
I didn't try this in the product itself, but here is Regex101 link to play with the regex.
I believe the actual answer to this is to not send your logs as an array. Instead include each json object in your body with a '\n' at the end for Sumo to consider these as individual log messages.
{"level":"INFO","data": "Test 1"}\n
{"level":"INFO","data": "Test 2"}\n

Resources