Counter variable not incrementing when accessing it in Groovy JSR223 Sampler - groovy

I have a simple loop controller and within it, a Counter config element, and a JSR223 Sampler running Groovy code. My Counter is set to begin at 0, increment by 1 up to a max of 3, and is set to a variable named 'idx'.
In my JSR223 Sampler, I log the value of idx using log.info(${idx}); -- it always prints the first iteration value (in my case 0), for every loop iteration.
I disabled this JSR223 sampler and added a BeanShell sampler, doing the same log statement, log.info(${idx});, and it is incrementing properly -- I get the values 0, 1, 2 for the iteration.
I need to take some JSON, map them to objects, do some tweaking, then map them back to JSON. There are JSONParser, JSONObject, and JSONArray classes that seem to be working in the BeanShell Sampler, but I'm much more comfortable with Groovy's JsonSlurper and JsonBuilder classes and would prefer to use these.
All of these steps are within a Test Fragment, if that makes a difference. Anyone have any ideas? Is this a bug?

Never refer JMeter Function or Variables directly in scripts, either use "Parameters" section for this like:
Or use vars shorthand which stands for JMeterVariables class instance like:
log.info(vars.get('idx'))
The reasons are in:
Function or variable may resolve into something which will cause compilation failure or unexpected behaviour
Referencing variables and/or functions prevents caching compiled Groovy scripts so it negatively impacts performance
Referencing functions and/or variables might conflict with Groovy GString Template
See Apache Groovy - Why and How You Should Use It article for more information on using Groovy scripting with JSR223 Elements in JMeter tests.

Related

How to set values of variable using postprocessor in Jmeter and use it in Preprocessor for same sampler?

My scenario is to pass different time (15 mins gap) till the script runs for each sampler run.
I am using preprocessor and postprocessor in the same step and now i want to use the the variable changed in postprocessor step, in side post processor step.
Below is the screenshot of code and script.
According to JMeter Test Elements Execution Order PreProcessor is executed before the PostProcessor therefore you cannot access the variables set in the PostProcessor in the PreProcessor
There is __timeShift() function which can generate the date in the given format with the given offset, for example you can add 15 minutes to current time as simple as:
${__timeShift(yyyy-MM-dd'T'HH:mm:ss.SSS'Z',,PT15M,,)}
There is no need to use these SimpleDateFormat/Calendar in Groovy, there is TimeCategory class which makes dates manipulation very easy. Moreover, Groovy's Date class provides format() function therefore you can add 15 minutes to the current date like:
use(groovy.time.TimeCategory) {
15.minutes.from.now.format("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
}
Demo:
Just found out the solution. I don't need to add preprocessor here. instead just using jsr223 sampler will work fine with onceonly controller.
preprocessor was resetting the starttime and endtime value here.

JMeter- How to share groovy scripts among a number of isolated Test Plan

I have a bunch of common groovy functions which I am reusing in different 'Test Plans'. I want to keep them in separate script files. I don't want to create jar. How can I import those files in JMeter JSR223 Assertion, Preprocessor and Postprocessor with minimum fuzz? These are more or less modular functions and I want to keep them separate for obvious reason.
I tried using "Script file" section of JSR223. But it seems that it is only for overriding the script.
How can I use an external groovy script file in JSR 223 assertion/preprocessor/post-processor?
If you have a bunch of functions which you`d like to re-use in different jsr223 elements you can:
In your test-plan create one initial JSR223 preprocessor (or sampler) and define your functions:
def sum(Integer a, Integer b) {
return a + b
}
def isA(Integer x, Integer y) {
}
def isB(Integer x, Integer y) {
}
Then using closure put them as objects:
vars.putObject('sum', this.&sum)
vars.putObject('isA', this.&isA)
vars.putObject('isB', this.&isB)
In any other JSR223 element in the script you can use those functions like that:
def sum= vars.getObject(‘sum’);
println sum(2, 2);
I don't really understand why Script file option doesn't work for you, you can save your Groovy code as separate files on the file system and reference them via "Script file" input.
Whatever.
You can make JSR223 Test Elements modular just like any other Test Element using:
Test Fragment
Module Controller
and Include Controller combination
You can define the Groovy functions in {JMETER_HOME}/bin/utility.groovy script file.
Optionally you can define the function in your own Groovy script and set the property groovy.utilities=bin/utility.groovy in user.properties file.
For example, add the following to the Groovy script
def getRandomRangeOption() {
Random random = new Random()
random.nextBoolean() ? "Between" : "Except"
}
You can call the function with
${__groovy(getRandomRangeOption())}
from anywhere in you JMX.

Save responses to a file in JMeter with PostProcessor

I try to use following code in JSR223 PostProcessor to save response to CSV file in each iteration.
if(${__groovy(ctx.getPreviousResult().getResponseCode(),)} == "200"){
vars.put("response", prev.getResponseDataAsString());
String res="${response}";
FileWriter fstream = new FileWriter("logresult.csv",true);
fstream.write(res+"\n");
fstream.close();
}
I assume csv file should be created in same folder as jmx, but it isn't present after execution. I execute test in one thread.
Don't use ${} syntax in JSR223 script as part of JMeter best practices
if(prev.getResponseCode() == "200"){
String res=prev.getResponseDataAsString();
vars.put("response", res);
FileWriter fstream = new FileWriter("logresult.csv",true);
fstream.write(res+"\n");
fstream.close();
}
ensure the script does not use any variable using ${varName} as caching would take only first value of ${varName}. Instead use :
vars.get("varName")
Your syntax is not correct, you need to amend the first line to look like:
if(prev.getResponseCode().equals('200')){
also you don't need this line at all
String res="${response}";
instead use the following:
fstream.write(vars.get('response')+"\n");
see JSR223 Sampler documentation for comprehensive explanation, the relevant quote:
JMeter processes function and variable references before passing the script field to the interpreter, so the references will only be resolved once. Variable and function references in script files will be passed verbatim to the interpreter, which is likely to cause a syntax error.
In general you're going into wrong direction, in case if you run your test with > 1 thread you might run into the race condition when 2 threads will be writing into the same file resulting in garbage if not worse.
If you have to store the responses into a separate file I would recommend:
Extracting the whole response into a JMeter Variable using i.e. Regular Expression Extractor
Defining Sample Variable property to hold this value
Write the value into the file using Flexible File Writer

JMeter - User defined counter not incrementing for a Loop

I am quite new to JMeter and I was trying to increment a counter variable pre-defined in User Defined Variables using a Loop Controller and a JSR223 PostProcessor and it seems not working well. I looked at various examples on JMeter loop and counter examples to work this out but the config element Counter was also not incrementing with the loop.
Could anybody please let me know what I am doing wrong?
This is the user defined variable counter:
This is how I do loop:
And this is how I am trying to increment the counter using post processor and the log displays that the counter is not incrementing for each loop. I want to get the counter upto 5:
[EDIT]
I guess I wasn't clear on why I used ${counter} to test out. I was trying to evaluate the counter variable within another variable as '${__V(transaction_${counter})}' because this needs to be appended to a text file. For example, if transaction_3 has a value "110001", if I do '${__V(transaction_'+vars.get('counter')+')}' to append, the text stored shows "transaction_3" and if I do '${__V(transaction_${counter})}' then I get the correct value "110001" stored in the text file while in next iteration the counter does not increment. Is there a possible way to solve this problem?
This is how I was using the variable within variable and it shows that the values are not changing because the counter is not changing.
And this image is how I am trying to do with vars.get() and it shows that it is just putting the variable name instead of evaluating the value of each item.
According to JSR223 Sampler documentation:
JMeter processes function and variable references before passing the script field to the interpreter, so the references will only be resolved once. Variable and function references in script files will be passed verbatim to the interpreter, which is likely to cause a syntax error. In order to use runtime variables, please use the appropriate props methods, e.g.
props.get("START.HMS");
props.put("PROP1","1234");
So amend the last line of your script to look like:
log.info(vars.get('counter'))
Demo:
Also be aware that it's much easier to use:
Counter test element or __counter() function, check out How to Use a Counter in a JMeter Test article for more details
Loop Controller exposes ${__jm__Loop Controller__idx} JMeter Variable which holds current iteration number
According to the JMeter Manual Best Practices -> 16.12 JSR223 Elements
When using JSR 223 elements, it is advised to check Cache compiled script if the available property to ensure the script compilation is cached if the underlying language supports it. In this case, ensure the script does not use any variable using ${varName} as caching would take only the first value of ${varName}. Instead use: vars.get("varName")`
If you change log.info('${counter}') to log.info('${vars.get("counter")}') that should do the trick!
Or uncheck this:

How to move variable from sampler to sampler in groovy Jmeter

I have a question about variables, in groovy in jmeter.
I want to create a test that in the first step read data via groovy sampler, and put it in variable budget, def = old_budget;
and in the end of the test I want to create another sampler and check if budget is old_budget - 5.
In the parameters of the second sampler I put ${old_budget}, but the sampler not recognized the variable from the previous sampler, what I am missing?
P.S. the variable is not user defined variable it is defined in the first sampler
In order to create a new JMeter Variable called old_budget having the value of budget variable you can do it like:
vars.put('old_budget', vars.get('budget'))
Looking into your screenshots it seems you're misusing the Parameters feature,
You need to separate variables you pass through "Parameters" section by spaces, not by commas
You can refer them individually using args[] shorthand like:
- `args[0]` - for "budget"
- `args[1]` - for RedisIP
- etc.
Demo:
More information:
JSR223 Sampler
Groovy is the New Black

Resources