Save responses to a file in JMeter with PostProcessor - groovy

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

Related

Jmeter - While converting CSV data to base64 with groovy getting below error

Code >
Error >
Help to solve this error!
Purpose is to pass
${encodedPayload}
to http post request. Currently getting ${encodedPayload} instead of base64 encoded data.
From the error it seems that your ${type} string doesn't have any value.
If you're trying to use String Interpolation - make sure to define it beforehand:
def type = "some type"
//and then you can refer it anywhere as "${type}"
if you're trying to reference a JMeter Variable - make sure that it exists and has an anticipated value using Debug Sampler and View Results Tree listener combination. Additionally you should rather use vars shorthand for JMeterVariables class instance, i.e. instead of:
${type}
use
vars.get("type")
In general you don't need any scripting, if you just need to send Base64-encoded JSON you could just go for __base64Encode() custom JMeter Function (can be installed using JMeter Plugins Manager)

JMeter functions and variables

I'm new to JMeter so this question may sound absolutely dumb...
I have a loop in which a variable (let's say it is called "raw") is being changed and written to file every iteration. The variable contains HTML encoded text so it has to be converted into plain text. I found out this can be done using __unescapeHtml function. When I tried using it worked but I ended up always receiving the same text as on the first iteration. Then I learned that I have to use vars.get instead of ${} to access a variable. So I changed ${__unescapeHtml("${raw}")} to ${__unescapeHtml(vars.get("raw")} which kind of helped: vars.get is getting the new value of raw each iteration but __unescapeHtml didn't work at all now - it just returns the encoded text from raw. I didn't succeded finding anything about this exact problem so I'm kind of stuck.
Ended up using
import org.apache.commons.lang3.StringEscapeUtils
...
StringEscapeUtils.unescapeHtml4(vars.get("raw"))
Don't know if it is a good way to do this but at least it works.
I assume, that you are using the expression ${...} inside a JSR-223 sampler or similar context. The user manual for JSR-223 Sampler states, that those scripts can be cached by JMeter. That is why you only get the values from the first time the context gets created.
The same is true for simple variable evaluations as ${varname}, as for function calls like ${__unescapeHtml(...)}.
The solution here is:
don't use ${...} inside of JSR-223 contexts, that might be cached.
you can however pass those expressions (${...}) into the context by using them as parameters through the input labeled Parameters on the JSR-223 Sampler – again assuming, that you are using it.
you can use the features, that your chosen JSR-223 context gives you, as you have done, by using the StringEscapeUtils#unescapeHtml4

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.

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:

Counter variable not incrementing when accessing it in Groovy JSR223 Sampler

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.

Resources