JMeter - what's the usage of __logn function? - jmeter

JMeter have great functions but I don't understand why __logn function exists? It does the same (less than) as __log function.
Is there a special case for using it? (also logn can be confused with complexity)

As per documentation:
The logn function logs a message, and returns the empty string
The only difference between them is that:
__log() function prints message to the jmeter.log file and returns the generated message
__logn() function just prints message to the jmeter.log file (returns nothing
Demo:
Check out Apache JMeter Functions - An Introduction for comprehensive information on JMeter functions.

Related

Set decimal separator for JMeter JavaScript engine

The problem
My JMeter test calculates amount of threads that should be allocated to a thread group using JS expressions like this:
threadsGroupA expression: ${__javaScript(${__property(threads)}*${__property(threadPercentageA)})}
threadsGroupB expression: ${__javaScript(${__property(threads)}*${__property(threadPercentageB)})}
The properties passed to script:
threads=100
threadPercentageA=0.3
threadPercentageB=0.7
The expected result is: 30 threads assigned to group A and 70 threads assigned to group B.
This works as expected on my workstation. However, when I try to run it on a server, it does not create threads unless I use comma as a decimal separator in properties file:
threads=100
threadPercentageA=0,3
threadPercentageB=0,7
I am looking for a way to run the test with same property file in any environment.
What I tried
I have tried to force JVM to use locale with a decimal point . by adding -Duser.language=en -Duser.country=US -Duser.region=us (in different permutations) as variablesJMETER_OPTS, JMETER_LANGUAGE and also directly passed to JMeter as command line arguments(JMeter doc reference). None of that seemed to have any effect.
My thoughts
My conclusion at this point is that the problem is happening in JS engine that evaluates __javaScript()function. If there was a way to set locale for JS engine, I would be able to check this, hence the question in subject.
Use __groovy function and cast to integer/double the values before multiply:
${__groovy(props.get("threads").toInteger() * Double.parseDouble(props.get("threadPercentageB")),)}
Try using parseFloat() function for your decimal values like:
${__javaScript(${__property(threads)}*parseFloat(${__property(threadPercentageA))})}
If the output is decimal as well - in JavaScript there is Number.prototype.toLocaleString() function where you can explicitly set the locale for the Number object so you will have the confidence that it will return dot or comma no matter where it is run.
Also be aware that JavaScript engine is removed from the latest JDK/JRE versions so if you have a lot of JavaScript in your JMeter tests it makes sense to consider migrating to GraalVM or switching to __jexl3() or __groovy() functions
JS solution
Use parseFloat(), which always expects ., regardless of locale:
${__javaScript((${__property(threads)}*parseFloat("${__property(threadPercentageA)}")).toFixed())}
Credits for original idea to Dmitri T's answer
Groovy solution
${__groovy((props.get("threads").toInteger() * Double.parseDouble("${props.get('threadPercentageA')}")).round())}
Credits for original idea to user7294900's answer
Note about JMeter thread count handling
Turns out JMeter will not accept number of threads with decimal part, even if it is .0. Therefore, answers above include rounding functions.

Is it a JMeter bug if ctx.getThreadNum() returns number starting from 0 instead of 1?

I'm facing an issue while using the ctx.getThreadNum() inside JSR223 Post Processor.
From the JMeter API documentation of getThreadNum(), it shows:
the threadNum starting from one
But what I'm actually getting from the code is: returning the threadNum starting from ZERO
Seeing the attached image below:
I even try to compare with the function ${__threadNum}, and this function returns the number as expected (1) instead of ctx.getThreadNum() returns 0.
Could anyone please help to give me an advice if I'm doing something wrong? Or this is a bug from JMeter?
You are right that it's a documentation bug
threadNum actually start with 0 and not as stated in documentation
I opened a bug JMeterContext getThreadNum start at 0 and not 1
It'll be fixed next JMeter version
Notice java indexes start with 0, so it is valid implementation, but I agree that at least documentation should be changed
It's not a bug, that's how it works, it is documented here:
https://jmeter.apache.org/usermanual/functions.html#__threadNum
But there was a javadoc bug that has been reported and is now fixed:
https://bz.apache.org/bugzilla/show_bug.cgi?id=63616
So just add 1 to java code when comparing, but anyway never use ${} or a function ${__threadNum} inside JSR223 Groovy code, it will break caching of Compiled JSR223.
You can use rather the Parameters field to call the function ${__threadNum}

unable to print Beanshell response in log file and cmd

I am trying to print the below code in Beanshell PostProcessor
but i am getting
Code : log.info(ctx.getPreviousResult.getTime());
Error Message: Cannot access field: getPreviousResult
JMeterContext.getPreviousResult() is a function, not field, you need to add parentheses after it
You cannot print a Long value to jmeter.log directly, you need to cast it to String first
There is prev shorthand which stands for parent SampleResult so you can actually shorten your code
Assuming all above amend your code to:
log.info(prev.getTime().toString());
Also be aware that starting from JMeter 3.1 it's recommended to use JSR223 Test Elements and Groovy language mostly because Groovy has much better performance comparing to Beanshell so consider migrating to JSR223 PostProcessor on next available opportunity, you will not have to change the code.
getPreviousResult is a method so syntax is:
ctx.getPreviousResult().getTime()
So you code should be:
log.info("{}", ctx.getPreviousResult().getTime());

Jmeter. __base64Encode function doesn't encode in JSR223 Sampler

Every time I need to achieve something in Jmeter, I ask a question in SO...
To make a story short: my goal is to read Base64 encoded values from csv file line by line and save them into separate variables. According to this page (in order to decode them), there are functions ${__base64Encode} and ${__base64Decode}. I installed Custom Jmeter Functions Plugin and restarted the Jmeter. Another referral to this answer, there is an advisory to use JSR223 PostProcessor / Sampler, verbatim:
it is recommended to use Groovy for any form of scripting to consider
migrating to JSR223 PostProcessor
so I decided to give it a try. Below is my script to read csv files:
def csvFileLocation = new File("C://JohnDoe//MyWork//sensitive_data.csv")
def lines = csvFileLocation.readLines()
lines.eachWithIndex {line, idx ->
vars.put("Id_value_" + idx, line)
}
${__base64Decode(${Id_value_0}, first_variable)}
${__base64Decode(${Id_value_1}, second_variable)}
${__base64Decode(${Id_value_2}, third_variable)}
Then I saw something interesting:
2018-01-01 12:30:60,767 ERROR o.a.j.p.j.s.JSR223Sampler: Problem in
JSR223 script JSR223 Sampler, message: javax.script.ScriptException:
org.codehaus.groovy.control.MultipleCompilationErrorsException:
startup failed: Script10.groovy: 8: unexpected token: ! # line 8,
column 1. !ßïj[žÿ
I simply decided to test it on https://www.base64encode.org/ with a string this is the test of base64 encoding
However, Jmeter _base64Encode function produces completely different result:
vars.put("jmeter_variable", "this is the test of base64 encoding");
${__base64Encode(${jmeter_variable}, my_variable)}
log.info(${my_variable});
OUTPUT:
JHtqbWV0ZXJfdmFyaWFibGV9
My question: what type of encoding algorithm Jmeter uses? Should I be able to save already encoded values into the csv file and retrieve them to the original value with the help of __base64Decode function? Thanks for the help...
You need to replace these lines:
${__base64Decode(${Id_value_0}, first_variable)}
${__base64Decode(${Id_value_1}, second_variable)}
${__base64Decode(${Id_value_2}, third_variable)}
With these ones:
vars.put('first_variable', vars.get('Id_value_0').decodeBase64() as String())
vars.put('second_variable', vars.get('Id_value_2').decodeBase64() as String())
vars.put('third_variable', vars.get('Id_value_2').decodeBase64() as String())
vars is a shorthand for JMeterVariables class instance, it provides read/write access to JMeter Variables in current test element's scope.
As per JSR223 Sampler documentation you should avoid inlining JMeter Functions and/or variables into Groovy scripts as they may resolve into something which can cause your script compilation failure (like in your case) or unexpected behaviour. Moreover it does not align with Groovy's compilation caching feature therefore performance of your Groovy script even if everything will be fine from syntax perspective will be a big question mark.
So the most "natural" way from Groovy perspective will be using String.decodeBase64() function like demonstrated above. See The Groovy Templates Cheat Sheet for JMeter article to learn what else could be done with Groovy and how.

JMeter unescapeHtml on a variable value

If I have a BeanShell PostProcessor with the following script:
vars.put("avar", ${__unescapeHtml("<escele>esceleValue</escele>")});
vars.put("bvar", "<escele>esceleValue</escele>");
vars.put("cvar", ${__unescapeHtml(vars.get("bvar"))});
I get the following in the Debug PostProcessor:
avar=<escele>esceleValue</escele>
bvar=<escele>esceleValue</escele>
cvar=<escele>esceleValue</escele>
I would expect cvar's value to match avar's value. Is there a way to do this?
Ultimately I am trying to get a statement like the following to work with escaped XML in the response data. In the process I tried PostProcessor extractors that successfully put all the response data in a variable and then tried to unescape the variable as in the above test case. I assume the issue is the same using a variable or using "prev.getResponseDataAsString()".
vars.put("avar", ${__unescapeHtml(prev.getResponseDataAsString())});
I would recommend stop inlining JMeter Functions and/or Variables into scripting-enabled test elements as it may cause unexpected behaviour w.r.t ValueReplacer and in case of JSR223 Sampler and Groovy language will definitely lead to performance degradation as scripts containing variables and functions references cannot be compiled into bytecode.
Given you:
Already using Beanshell
Know that __unescapeHtml() function is using StringEscapeUtils under the hood according to the function documentation
Why just not to call code directly like:
import org.apache.commons.lang3.StringEscapeUtils;
vars.put("avar", ${__unescapeHtml("<escele>esceleValue</escele>")});
vars.put("bvar", "<escele>esceleValue</escele>");
vars.put("cvar", ${__unescapeHtml(vars.get("bvar"))});
vars.put("dvar", StringEscapeUtils.unescapeHtml4(vars.get("bvar")));
log.info(vars.get("dvar"));

Resources