Closed AntonioSun closed 2 years ago
Also,
// using single quotes (for Java plain String)
plan (name: 'Test name')
// using single quotes is recommended in most situation (should be used when you want use JMeter variable substitution in the script)
plan (name: '${var_variable}')
// using double quotes (for GString, interpolation available during test build but not execution by JMeter engine)
plan (name: "${var_param}")
I want to let my jmeter file to use groovy expression directly in it, so I put this in:
argument(name: 'application', value: '${__groovy(("${__TestPlanName}").replace('.jmx'\,''),)}')
However, that will cause --jmx-out
to choke:
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
/home/groovy/myscript.groovy: 6: Unexpected input: '{' @ line 6, column 7.
start {
^
1 error
Only when I replace it with the following, the --jmx-out
will run fine.
argument(name: 'application', value: 'THE_APPLICATION')
PS. Here is how the line should be showing up in the .jmx
file:
<elementProp name="application" elementType="Argument">
<stringProp name="Argument.name">application</stringProp>
<stringProp name="Argument.value">${__groovy(("${__TestPlanName}").replace('.jmx'\,''),)}</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
PPS.
:). Ok So you should use groovy triple quotes.
argument(name: 'application', value: '''${groovy(("${TestPlanName}").replace('.jmx',''),)}''')
I think it should work in this way. You might check other types of groovy quotes in https://groovy-lang.org/syntax.html#all-strings
Yep, it works perfectly.
TBH, I did read through the groovy quotes you posted before in https://groovy-lang.org/syntax.html#all-strings, and I only thought that triple single quotes are for span multiple lines, :)
Thanks for helping!
Hi @smicyk, I have to reopen this as it is not getting want I want.
Here is how the line should be showing up in the
.jmx
file:<elementProp name="application" elementType="Argument"> <stringProp name="Argument.name">application</stringProp> <stringProp name="Argument.value">${__groovy(("${__TestPlanName}").replace('.jmx'\,''),)}</stringProp> <stringProp name="Argument.metadata">=</stringProp> </elementProp>
And within the JMeter, it reads:
${__groovy(("${__TestPlanName}").replace('.jmx'\,''),)}
This is the only way it works. and these are what I've tried within groovy-jmeter script:
'''${__groovy(("${__TestPlanName}").replace('.jmx',''),)}'''
", then what reported at the influxdb side is the literal string, ${__groovy(("${__TestPlanName}").replace('.jmx',''),)}
'''${__groovy(("${__TestPlanName}").replace('.jmx'\,''),)}'''
", will cause groovy-jmeter to choke: 6: Unexpected input: '{' ... start {
'''${__groovy(("${__TestPlanName}").replace('.jmx'\\,''),)}'''
", will get nothing reported at the influxdb side, as if the test does not exist.Please find a solution, as it is becoming a show-stopper for me to recommend it to our colleagues, since this is our standard way of doing reporting into the influxdb. thanks!
Hi,
the version which works for me
argument(name: 'application', value: '${__groovy("${__TestPlanName}".replace(".jmx"\\,""))}')
It produces:
<stringProp name="Argument.value">${__groovy("${__TestPlanName}".replace(".jmx"\,""))}</stringProp>
Check it out and let me know.
Thanks!
Hmm.. I tried it and it works with the generated .jmx file. however, directly running the .groovy
file didn't work. Did directly running the .groovy
file work for you?
I think there is a problem with __TestPlanName. It can't be used in groovy script when running because it is based on the .jmx file name. I need to investigate this problem.
Reusing the old thread so that related info are at the same place.
I'm defining my Think Time in the arguments
as:
argument(name: 'c_tt_range', value: '${__P(c_tt_range, 6000)}') // Maximum random number of ms to delay
argument(name: 'c_tt_delay', value: '${__P(c_tt_delay, 2000)}') // Ms to delay in addition to random time
then use them to define the uniform_timer
as:
uniform_timer (name: 'Think Time', delay: '${c_tt_delay}', range: '${c_tt_range}')
However, if I don't use the single quote in the uniform_timer
as:
uniform_timer (name: 'Think Time', delay: ${c_tt_delay}, range: ${c_tt_range})
It'll error out with:
WARNING: Could not find match for name '$' Caught: net.simonix.dsl.jmeter.model.ValidationException: The keyword '$' is not valid. Did you misspell any of valid keywords [execute_if, argument, before,...
if I use the single quote, then I'll get:
Caught: java.lang.NumberFormatException: For input string: "${c_tt_delay}"
Tried the following as well which didn't work:
uniform_timer (name: 'Think Time', delay: \${c_tt_delay}, range: \${c_tt_range})
How can I make it work?
please, I'm blocked on this. thx.
Unfortunately, this is JMeter shortcomming. The uniform_timer doesn't allow to pass expressions as delay and range values. It must be parsable number value.
The alternative is to use command line variables if you want to change them dynamically for each run.
Hmm... I did some more experiments with it, and found that this might not be JMeter's shortcoming.
Here is my arguments:
argument(name: 'c_lt_users', value: '${__P(c_lt_users, {{ coalesce (ENV "GJS_LT_USERS") 10}})}') // loadtest users
argument(name: 'c_lt_ramp', value: '${__P(c_lt_ramp, {{ coalesce (ENV "GJS_LT_RAMP") 5}})}') // loadtest ramp up in seconds
And here is how I'm trying to use it:
//group(users: ${c_lt_users}, rampUp: ${c_lt_ramp}) {
group(users: 1, rampUp: 1) {
If using the commented one, I'll be getting the exact same problem as reported above -- Could not find match for name '$' Caught
.
However, after the conversion, if I change it back in JMeter directly, it saves the file just fine:
@@ -76,3 +76,3 @@
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
- <stringProp name="ThreadGroup.num_threads">1</stringProp>
+ <stringProp name="ThreadGroup.num_threads">${c_lt_users}</stringProp>
<stringProp name="ThreadGroup.ramp_time">1</stringProp>
So, jmeter allows using ${c_lt_users}
as-is, it is groovy-jmeter the converter that is preventing me doing it.
Please double-check. thx
Yep, confirmed -- adding The uniform_timer in JMeter directly allow to pass expressions as delay and range values:
@@ -76,3 +76,3 @@
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
- <stringProp name="ThreadGroup.num_threads">1</stringProp>
+ <stringProp name="ThreadGroup.num_threads">${c_lt_users}</stringProp>
<stringProp name="ThreadGroup.ramp_time">1</stringProp>
@@ -202,2 +202,7 @@
</hashTree>
+ <UniformRandomTimer guiclass="UniformRandomTimerGui" testclass="UniformRandomTimer" testname="Uniform Random Timer" enabled="true">
+ <stringProp name="ConstantTimer.delay">${c_tt_delay}</stringProp>
+ <stringProp name="RandomTimer.range">${c_tt_range}</stringProp>
+ </UniformRandomTimer>
+ <hashTree/>
<TransactionController guiclass="TransactionControllerGui" testclass="TransactionController" testname="TR0_SendMqMessage.php" enabled="true">
OK. So some explanation about using variables.
You can use groovy variables in the script e.g.:
def rampUpValue = 100
plan {
group users: 1, rampUp: rampUpValue, {
// other stuff
}
}
So you can use variables define in the script and use them where you want in the script but they are used during building the script not during execution.
plan {
variables {
variable name: 'rampUpValue', value, '100'
}
group users: 1, rampUp: '${rampUpValue}', {
// other stuff
}
}
So the rampUpValue is not jmeter variable and is used during script execution not building. Note the single quotes.
So your example
group(users: ${c_lt_users}, rampUp: ${c_lt_ramp}) {
Groovy doesn't know what is $ because it is not part of the language. But if you do:
group(users: '${c_lt_users}', rampUp: '${c_lt_ramp}') {
It shoudl work since you define c_lt_users as test plan variable, so jmeter would be able to evaluate it during script execution.
The example with jmx file which you send are fine if you didn't run them in JMeter GUI, the groovy script can be serialize to jmx with what every you put there but when your run it it will fail. The expressions are evaluated during runtime not during building jmx.
Thanks for the explanation.
The question is closely related to #81, so I'll follow up there.
Reopen it as it seems I'm getting the same result for groovy-jmeter-0.18.0.
Here is the full groovy script for you to try with, @smicyk:
@GrabConfig(systemClassLoader=true)
@Grab('net.simonix.scripts:groovy-jmeter')
@groovy.transform.BaseScript net.simonix.dsl.jmeter.TestScript script
start {
plan {
variables {
variable(name: 'c_lt_users', value: '${__P(c_lt_users, 10)}', description: 'loadtest users')
variable(name: 'c_lt_ramp', value: '${__P(c_lt_ramp, 5)}', description: 'loadtest ramp up in seconds')
}
defaults(protocol: 'https', domain: 'www.example.com', port: 443)
group(users: ${c_lt_users}, rampUp: ${c_lt_ramp}) {
http 'GET https://www.example.com'
// to define own sample name you must use long version
http name: 'Custom Name 1', protocol: 'http', domain: 'localhost', path: '/', method: 'GET'
http (name: 'Custom Name 2', path: '/', method: 'GET')
}
}
}
Hi, it should be:
@GrabConfig(systemClassLoader=true)
@Grab('net.simonix.scripts:groovy-jmeter')
@groovy.transform.BaseScript net.simonix.dsl.jmeter.TestScript script
start {
plan {
variables {
variable(name: 'c_lt_users', value: '${__P(c_lt_users, 10)}', description: 'loadtest users')
variable(name: 'c_lt_ramp', value: '${__P(c_lt_ramp, 5)}', description: 'loadtest ramp up in seconds')
}
defaults(protocol: 'https', domain: 'www.example.com', port: 443)
group(users: '${c_lt_users}', rampUp: '${c_lt_ramp}') {
http 'GET https://www.example.com'
// to define own sample name you must use long version
http name: 'Custom Name 1', protocol: 'http', domain: 'localhost', path: '/', method: 'GET'
http (name: 'Custom Name 2', path: '/', method: 'GET')
}
}
}
Then you need to run it with (local):
groovy script.groovy -Jc_lt_users=20 -Jc_lt_ramp=10
or if running in distributed env:
groovy script.groovy -c -r worker1:1099 -r worker2:1099 -Gc_lt_users=20 -Gc_lt_ramp=10
You can actually look at examples distributed or parameters
Ah, using single quote!
Yes, indeed, now point # 3 works too -- having the source groovy-jmeter script works with JMeter without modification, even when converting it into JMeter.
Thanks!
Ah ok, so you should look at https://github.com/smicyk/groovy-jmeter#groovy-as-dsl.
So basically you have two types of variables substitutions, the one for groovy variables and one for jmeter variables. Since jmeter and has same syntax to substitute it can be confusing. In general the rule is if you want groovy substitution you should use double quotes, in any other case you should use single quotes.
In your case when you have:
you define var_host variable based on groovy variable jmt_host and this substitution is only available during test plan build phase.
then
you use __var_host__ variable define before during test plan execution.
Note, that groovy substitution you don't have use string interplation to get variable and just use the variable name. It depends what you want to actually create as a variable.
Originally posted by @smicyk in https://github.com/smicyk/groovy-jmeter/issues/53#issuecomment-1023982378