In JMeter, How do i loop until a result is found - jmeter

I have a request in Jmeter that I need to loop until I find the result I am looking for. I have read a few bits about a while controller but found them unhelpful as they seem to glance over vital information or are using an older version of Jmeter
I'm currently using Jmeter 5.0, and I have attempted to implement a while controller but failed as I think I do not understand how to properly handle the response, or even grab it, and then use it as a comparison to assert if the item exists.
I get a response from the HTTP request call response that looks a little somthing like this:
{"data":{"getIDs":{"Page": 1,"PageSize": 25,"PageCount": 1,"isFirstPage": true,"batches":[{"id":"b601a257-13fe-4de3-b779-a5922e89765a"},{"id":"b601a257-13fe-4de3-b779-a5922e89765b"},{"id":"b601a257-13fe-4de3-b779-a5922e89765c"}]}}
I need to recall the endpoint until I have found the ID I am looking for or cancel after 10 attempts

So after a bit of fumbling around I, I figured on my own answer that seems to work well. But I would suggest looking at other sources before taking mine as gospel.
The basic structure looks as follows:
Within a thread I set the variables then create the while loop as the next step. Within the While loop I created a counter then added the request I wanted to loop after. To make the loop work for me, I have three items sat under the request.
A Response Assertion: this check for a 200 status as the call should never fail
A Constant Timer: There is a delay between polls of the end point
A JSR223 Assertion: groovy code used ensure the while loop logic is handled
User Defined Variables:
Here i have setup two variables:
DONE: Done is a string value I alter if my JSR223 Assertion finds the values I'm looking for in the HTTP request
MyValue (this is dynamically driven in my actual test, for demo purpose, I’m just declaring a value to look for i.e. 12345)
While Controller:
I still feel i may not understand this correctly, however after some googling I came across the following code that works for me despite some errors in the JMeter console:
${__javaScript(("${DONE}" != "yep" && ${Counter} < 10),)}
This code is saying that the while loop will continue until either of these two conditions are met:
DONE, the variable created earlier, is equal to the value yep
Counter is less than 10 (Counter is declared beneath the while loop)
Counter:
this was a simple configuration step that just worked once I understood it needed to be within the while loop, i configured the following:
Starting value = 1
Increment = 1
Exported Variable Name = Counter
Ticked 'Track Counter independently for each user'
Ticked 'Reset counter on each thread group iteration'
(Exported Variable Name: you can call this whatever you want, I’ve named it counter for the purpose of this demo)
JSR223 Assertion:
This is a simple script assertion that just uses a Boolean and a couple of if statements to assert the state of the test.
import org.apache.commons.lang3.StringUtils;
def done = vars.get("DONE");
String response = prev.getResponseDataAsString(); //retrieves the http request response as text
String MyValue = vars.get("MyValue");
def counter = vars.get("Counter");
//Find Substring within response string and stor result as boolean
String container = response;
String content = MyValue;
boolean containerContainsContent = StringUtils.containsIgnoreCase(container, content);
//Check if the true condition is met and change the value so the loop exits
if (containerContainsContent == true){
log.info("------------------------Got Here");
vars.put("DONE", "yep");
}
//Force test to fail after 10 loops
if (Counter.toString() == "10"){
assert 1 == 2
}

Related

JMETER : While condition is failing with syntax error

I have a scenario where in I need to wait for the response text .I need to send the same request till i get the required response text. I included my http samples in while loop with a counter. Now I am not able get the correct while condition.
Tried with below conditions.
${__javaScript(("${recordTypeLabel1}"!="asdf" && ${counter} < 5),)}
${__jexl3("${recordTypeLabel1}" != "asdf",)}
Both are failing. How to handle this?
Pleasae help.
Threadgroup
Once only controller Login
loop controller
HTTP req
HTTP req
While loop {
Counter
HTTP request
HTTP Request
JSON extractor
}
HTTP req
Once only Controller Logout
The correct syntax for the __jexl3() function would be:
${__jexl3("${recordTypeLabel1}" != "asdf" && ${__jm__While Controller__idx} < 5,)}
Don't use __javascript() function as it is some form of a performance anti-pattern, stick to __jexl3() or __groovy() functions if you need to script some extra logic
Also you don't need to introduce a Counter, since JMeter 5.0 you have a special pre-defined variable called ${__jm__While Controller__idx} which holds zero-based iteration number of the While Controller. (If you change the While Controller's label to something else - make sure to amend the variable accordingly)
Exit when loop number exceeds the threshold
Exit when variable value becomes expected:

vars.put function not writing the desired value into the jmeter parameter

Below is the code which i have been trying to address the below UseCase in JMETER.Quick help is appreciated.
Usecase:
A particular text like "History" in a page response needs to be validated and the if the text counts is more than 50 a random selection of the options within the page needs to be made.And if the text counts is less than 50 1st option needs to be selected.
I am new to Jmeter and trying to solve this usingJSR223 POST processor but somehow stuck at vars.put function where i am unable to see the desired number being populated within the V paramter.
Using a boundary extractor where match no 1 should suffice the 1st selection and 0 should suffice the random selection.
def TotalInstanceAvailable = vars.get("sCount_matchNr").toInteger()
log.info("Total Instance Available = ${TotalInstanceAvailable}");
def boundary_analyzer =50;
def DesiredNumber,V
if (TotalInstanceAvailable < boundary_analyzer)
{
log.info("I am inside the loop")
DesiredNumber = 0;
log.info("DesiredNumber= ${DesiredNumber}");
vars.put("V", DesiredNumber)
log.info("v= ${V}");
}
else{
DesiredNumber=1;
log.info("DesiredNumber=${DesiredNumber}");
vars.put("V", "DesiredNumber")
log.info("v= ${V}");
}
def sCount = vars.get("sCount")
log.info("Text matching number is ${sCount_matchNr}")
You cannot store an integer in JMeter Variables using vars.put() function, you either need to cast it to String first, to wit change this line:
vars.put("V", DesiredNumber)
to this one
vars.put("V", DesiredNumber as String)
alternatively you can use vars.putObject() function which can store literally everything however you will be able to use the value only in JSR223 Elements by calling vars.getObject()
Whenever you face a problem with your JMeter script get used to look at jmeter.log file or toggle Log Viewer window - in absolute majority of cases you will find the root cause of your problem in the log file:

how to Bypass the Sampler based on previous response value in jmeter?

I have caught up in a situation, where in i need to verify the response of the Previous Sampler for one of the value and if the Value for that is [], then i need to trigger the below request or else then switch to another Sampler.
Flow:
Check Response of Sampler for One of the attribute
IF(attribute value==[])
Execute the Sampler under IF Conditions.
ELSE
New Sampler
Sample Response:
{"id":8,"merchant_id":"39","title":"Shirts-XtraLarge","subtitle":null,"price":110,"description":null,"images":"image_thumbs":[[]],"options":[],"options_available":[],"custom_options":[]}
I need to check if the attribute custom_options is empty or not! If Empty do some actions and if not empty do some other action !
Need if condition to simulate this!
Help is useful!
A nice to have feature in JMeter would be Else statement, but until then you will have to use 2 If Controllers
If Controller allows the user to control whether the test elements below it (its children) are run or not.
Assuming you hold your attribute value using regex/json/css/other post processor extractor add two condition, first is positive and under it the Sampler:
${__groovy("${attributeValue}" == "[]")}
Second is negative and under it add the New Sampler
${__groovy("${attributeValue}" != "[]")}
__groovy is encourage to use over default Javascript
Checking this and using __jexl3 or __groovy function in Condition is advised for performances
Go for Switch Controller
Add JSR223 PostProcessor as a child of the request which returns your JSON
Put the following code into "Script" area:
def size = com.jayway.jsonpath.JsonPath.read(prev.getResponseDataAsString(), '$..custom_options')[0].size()
if (size == 0) {
vars.put('size', 'empty')
} else {
vars.put('size', 'notempty')
}
Add Switch Controller to your Test Plan and use ${size} as "Switch Value"
Add Simple Controller as a child of the Switch Controller and give empty name to it. Put request(s) related to empty "custom_options" under that empty Simple Controller
Add another Simple Controller as a child of the Switch Controller and give notempty name to it. Put request(s) related to not empty "custom_options" under that notempty Simple Controller.
More information: Selection Statements in JMeter Made Easy

I want to check if a response attribute of one http request exits in another http request as well. How can I do that?

HTTP request
.. regular expression to pick up a token "PostID"
HTTP request
..Beanshell assertion to verify if ${PostID} exists in the response
I am using the while controller to loop the request till PostID is found
while condition being ${__javaScript("${count}" != 1)}
Beanshell assertion is failing though I see the PostID in the response of "FetchSentPost" request
I need the while loop to end on the first encounter of Post ID in the HTTP request "FetchSentPost"
Where Am I going wrong?
You have a syntax error in your Beanshell script:
String ID = vars.get(PostID);
^^^^^^
should be
String ID = vars.get("PostID");
Going forward you can add debug(); directive to the beginning of your JMeter script for troubleshooting. I would also recommend switching to JSR223 Assertion and Groovy language, Groovy performs much better and more Java-compliant.
There are several mistakes made in the script.
Condition must be changed to ${__javaScript(${count} != 1)}. No double quotes.
In BeanShell Assertion, instead of count += 1, you must assign count value using vars.put as follows vars.put("count", 1);
As Dmitri mentioned, other mistake is:
String ID = vars.get("PostID");
Related to contains vs regex matching, try both after making above changes. I tried with contains, it is working.
Using contains:
while(!str.contains(ID)){
vars.put("count", 1);
}
created a user defined variable 'PostIdFound' with value 'False' outside the while loop.
Changed the while condition to ${__javaScript(${PostIdFound} != true)}
and then changed the BeanShell script as follows
import java.util.regex;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
String ID = vars.get("PostID");
String str= SampleResult.getResponseDataAsString();
vars.get("PostIdFound");
if(str.contains(ID)){
vars.put("PostIdFound","true");
}
Issue Resolved. Thankyou #Dmitri T and #Naveen for the help

Same random number and string for each thread

I need to generate the same JSON data twice for each thread for an HTTP request. I am having problem setting that up in JMeter.
My structure is:
Test Plan
- HTTP Header Manager
- Thread Group 1 users, 5 loop
- Random Variable,
- HTTP Request
I tried the combination of Per Thread User set to true and using seed for random function, but I can't achieve what I want. It keep on generating new number/string per loop.
Basically for each user, I want the exact same JSON request data.
I see three decisions for your case:
Use User Defined Variables before HTTP Request. Specify variables here. In this case it will be better to use __Random() function instead Random Variable.
Test Plan
- HTTP Header Manager
- Thread Group 1 users, 5 loop
- User Defined Variables, (Name:varName; Value:${__Random(1,100)})
- HTTP Request
Use Loop Controller (loop count=5) before HTTP Request (instead loop=5 in Thread Group)
I can suggest another solution which seems to me verbose and awkward but no other idea.
You create file using BSF (or BeanShell) PreProcessor and write value of random variable into file. Then read file before every request. In the next example I used Groovy and BSF PreProcessor.
import java.util.Random
def out= new File('File1.txt') // create file if it is not exists
if(!out.exists())
{
out.createNewFile()
Random rand = new Random()
int max = 10
def a = rand.nextInt(max+1)
out << a // write text to file
}
//then read value of generated variable
String fileContents = new File('File1.txt').text
//then put your variable into User defined Variable that I named HELLO
vars.putObject("HELLO",fileContents)
And in needed request use ${HELLO}

Resources