JMeter - groovy MultipleCompilationErrorsException in JSR223 Sampler - jmeter

I'm using groovy for JMeter JSR223 sampler . Below code is working fine from JMeter GUI.
String user = vars.get("username"); # abc.com\user1
String domainVal = ""
String userVal = ""
System.out.println(user)
if(user.contains("\\")){
String[] arrOfStr = user.split("\\\\", 2);
domainVal =arrOfStr[0]
userVal = arrOfStr[1]
}else{
userVal = user
}
System.out.println(domainVal)
System.out.println(userVal)
But same script I'm trying from JMeter headless is giving me error
Caused by: org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
Script8.groovy: 20: Missing ')' # line 20, column 18.
if(user.contains("\")){
^
1 error
I am clueless , what is causing the issue .
Update
I found the root cause it is caused by , if I remove below line (Jmeter thread number) it's working fine. Not a groovy issue, JMeter issue for sure.
int thread_count = ${__threadNum};

Don't use JMeter function in JSR223 script, replacement for __threadNum:
int threadNum = ctx.getThreadNum()
The function returns a number between one and the max number of running threads. Note that if you're using JSR223 code with JMeterContext object (ctx variable), the below code returns a number between zero and (max number of running threads minus one)
ctx.getThreadNum()

I cannot reproduce your issue:
with regards to your int thread_count = ${__threadNum}; piece of "code", you shouldn't be inlining JMeter Functions or Variables into Groovy scripts because:
The syntax conflicts with Groovy's GString Template Engine
The values will be cached and re-used on next occurrence
So you should either use "Parameters" section or code-based equivalents
More information: JSR223 Sampler Documentation
where ctx stands for JMeterContext class, see Top 8 JMeter Java Classes You Should Be Using with Groovy article for more details on this and other JMeter API shorthands available for JSR223 Test Elements

Related

Jmeter JSR223 Unable to read data from CSV file

Requirement is ItemID should be read from external CSV file and passed in the JSR223 preprocessor script. This is the groovy code in JSR223 and it is working as expected in the grrovy executer.
def items = []
List<String> lines = new File("C:\\Users\\854986\\itemid.csv").readLines()
def itemNo = RandomUtils.nextInt(5, 10)
1.upto(itemNo) { index ->
def item = [:]
def lineFromCsv = lines.get(index as int)
item.put('itemId', lineFromCsv)
But it jmeter it is throwing error and below is the error message.
"2022-11-15 12:34:14,398 ERROR o.a.j.m.JSR223PreProcessor: Problem in JSR223 script, JSR223 PreProcessor 3
javax.script.ScriptException: org.apache.commons.jexl2.JexlException$Parsing: JsonBuilder#1:20 parsing error near '... ment, miss ...'
at org.apache.commons.jexl2.scripting.JexlScriptEngine.compile(JexlScriptEngine.java:237)"./
I have java 19.0.1, Jmeter 5.4.3 and groovy 4.0.2.
You're talking about "groovy code". Any reason to use jexl2 language in the JSR223 PreProcessor?
Make sure to choose groovy as the language and at least this error should go away. Groovy is the recommended scripting option since JMeter 3.1 mainly because Groovy provides maximum performance comparing to other engines

How to pass a 2-D array from one thread to another thread in Jmeter

So I am using a bean shell post processor and towards the end I am storing the result in a 2-D array. Result is stored this way.
testArray[0][0] = "1"
testArray[0][1] = "Test"
testArray[1][0] = "2"
testArray[1][1] = "STG"
My requirement is that I need to pass this 2-D array to the next thread. How am I supposed to proceed ?
First of all since JMeter 3.1 you're supposed to be using JSR223 Test Elements and Groovy language for scripting so consider migrating to Groovy.
Coming back to your question just use props shorthand like:
In first thread:
props.put("testArray", testArray);
in the other thread:
testArray = props.get("testArray");
you might also want to add the current thread number as the prefix/postfix so different threads could have different arrays with separate values like:
props.put("testArray_" + ctx.getThreadNum(), testArray);
where ctx stand for JMeterContext class instance
More information on these ctx, props and other JMeter API shortcuts available for JSR223 Test elements: Top 8 JMeter Java Classes You Should Be Using with Groovy

Jmeter how to find the difference in two time which is stored in string

I have below values
String CurrentTime1=${__groovy(${__groovy(Date.parse('yyyy-MM-dd hh:mm:ss.SSS','${Modified_date_1}').getTime(),)},)}
log.info("Current time1 ----> "+CurrentTime1);
String beforetime=vars.get("beforetime");
log.info(" after time -->"+beforetime);
Result:
Current time1 ----> 1611495406402
after time -->1611495402100
As there are stored in string, i am not able to get the difference between these values. Can you please help.
I need to get the difference between current time and before time which are dynamic values.
If you want to do this in Groovy - you need to convert the string to Long like:
def before = vars.get('beforetime') as long
def current = vars.get('CurrentTime1') as long
def delta = current - before
def deltaAsString = delta as String
If you prefer using JMeter Functions - you can go for __longSum()
${__longSum(${CurrentTime1},-${beforetime},)}
More information on this and other JMeter Functions: How to Use JMeter Functions - Part III
But don't mix both approaches like inlining JMeter functions in Groovy code, as per JSR223 Sampler documentation:
When using this feature, ensure your script code does not use JMeter variables or JMeter function calls directly in script code as caching would only cache first replacement. Instead use script parameters.

How to create simple counter using Beanshell?

I'm trying to create a simple counter that will print the iteration number to the log.
the problem is that I didn't find a way to initialize the int value of i to 0.
if I'll do it inside the Beanshell script it will keep initializing, I need it to run only once at the beginning of the test.
My code:
int i=0;
log.info(string.valueOf(i));
i=i+1;
Add Once Only Controller, under it JSR223 Sampler with the initialization
vars.putObject("i", 0);
Then you can increment it after it (not under the Controller) with other JSR223 Sampler:
myI = vars.getObject("i")
log.info(String.valueOf(myI));
vars.putObject("i", ((Integer)myI+1));
It is recommended to avoid scripting where possible, and if you cannot live without scripting you should be using the most performing option which is JSR223 Test Elements and Groovy language.
Particularly your case can be implemented without any scripting, you can use the following JMeter Functions:
__log() - which prints an arbitrary message to jmeter.log file
__iterationNum() - which returns the number of current iteration
So if you use the statement like: ${__log(Current iteration is: ${__iterationNum},,,)} JMeter will return it where the function is called and additionally print the corresponding message to the log file.
Demo:
You can install __iterationNum() function as a part of Custom JMeter Functions bundle using JMeter Plugins Manager

Jmeter while controller doesn't seem to evaluate variables as numbers

I am writing a jmeter script that keeps loading data until a table reaches a specified size. I have a while loop, in which I have one HTTP Sampler to loads the data, then another HTTP Sampler with an XPath Post-processor to check the table size (they call two different APIs). The reference variable of the XPath Post Processor is currentSize and I have a user defined variable maxSize, but using ${currentSize} < ${maxSize} as the condition for the while loop creates an infinite loop.
Thinking maybe the problem is that the output of XPath is a string, I've tried doing various things in beanshell to coerce it to a number, but I'm a beanshell noob, so I haven't been successful with that either. Can anyone guide me about how to get jmeter to recognize a variable as a number? (Preferably a decimal, but if I have to round to an int, I can live with that.)
Thanks!
I think using __javascript(parseInt()) should suffice for you to check the condition.
e.g.
${__javaScript(parseInt(${time_elapsed_string}) < parseInt(${duration}))}
Assuming that you have following variables:
currentSize
maxSize
continue
where continue is set via User Defined Variables and has the value of true
You can use following Beanshell code to check if current size is equal or greater than maximum size:
import java.math.BigDecimal;
String currentSize = vars.get("currentSize");
String maxSize = vars.get("maxSize");
BigDecimal currentSizeNumber = new BigDecimal(currentSize);
BigDecimal maxSizeNumber = new BigDecimal(maxSize);
if (currentSizeNumber.compareTo(maxSizeNumber) > -1){
vars.put("continue", "false");
}
Make sure that following criteria are met:
Your While Controller has ${continue} as a condition
Beanshell Sampler, Pre / Post Processor or Assertion with the code above is added as a child of the While Controller
See How to use BeanShell guide for more details and kind of Beanshell cookbook.
Everything should work this way.
Hope this helps.

Resources