In my BSF preprocessor (language javascript), I am generating post data such as
var totalCustomer = 2;
var data = { "customers": [] };
for(i=1; i<=totalCustomer; i++){
// in all iteration getting same value for ${__UUID}
var customer = {
"id": "${__UUID}"
}
data.customers.push(customer);
}
vars.putObject("data",JSON.stringify(data));
I guess it is compiled once and looked up for the value in subsequent iterations.
Is there any way I can generate different guid using ${__UUID} for each iteration?
Replace ${__UUID} with UUID.randomUUID().toString(). Don't inline JMeter variables and functions into script, it's not very good practice and may lead to unexpected behavior (as in your case). Particular for your scenario it's better to call UUID class methods directly.
Don't use BSF test elements, they're not very efficient from performance side of things. Consider using JSR223 test elements and Groovy language. See Beanshell vs JSR223 vs Java JMeter Scripting: The Performance-Off You've Been Waiting For! for explanation, benchmarks, groovy engine installation details and scripting best practices.
Write JSR223 PreProcessor using java language to generate UUID
vars.put("myUUID",UUID.randomUUID().toString());
then access it in your javascript JSR223 PreProcessor.
var customer = {
"id": "${myUUID}"
}
You can use the "Parameters" field to pass ${__UUID}.
Then in your code, use:
bsh.args[0]
Example:
This is when you're using the PreProcessor in a While Controller or Loop Controller.
But if you are speaking about a Beanshell code that contains a loop then just do:
UUID.randomUUID().toString()
Of course ensure you import class:
import java.util.UUID;
Related
I need to re-do the setup with every thread(number). Now I have 2 times first the setup thread, and then 2 times the main thread. In setting apply 2 threads in SetUp and Main
The problem is that I end up getting requests with the same JSESSION ID
I want to see like this->
First thread:
CSRF-TOKEN
LOGIN
Test(first csrf login)
Second thread:
CSRF-TOKEN
LOGIN
Test(second csrf-token)
I know that this can be done in one thread, but there can be many such requests. And so we need a single setup, so as not to duplicate
UPDATED:
changed my code like you said and now it doesn't work.
I use in postprocessor this code:
import org.apache.jmeter.protocol.http.control.CookieManager;
import org.apache.jmeter.protocol.http.control.Cookie;
import org.apache.jmeter.testelement.property.PropertyIterator;
import org.apache.jmeter.testelement.property.JMeterProperty;
CookieManager manager = ctx.getCurrentSampler().getCookieManager();
PropertyIterator iter = manager.getCookies().iterator();
while (iter.hasNext()) {
JMeterProperty prop = iter.next();
Cookie cookie = prop.getObjectValue();
if (cookie.getName().equals("JSESSIONID")) {
vars.putObject("JSESSIONID", cookie);
break;
}
}
while (iter.hasNext()) {
JMeterProperty prop = iter.next();
Cookie cookie = prop.getObjectValue();
if (cookie.getName().equals("XSRF-TOKEN")) {
vars.putObject("XSRF-TOKEN", cookie);
break;
}
}
This Preprocessor main thread:
CookieManager manager = sampler.getCookieManager();
manager.add(vars.getObject("JSESSIONID"));
manager.add(vars.getObject("XSRF-TOKEN"));
But now it doesn't work
I used to use:
props.put("JSESSIONID", cookie);
The correctness of your test design is a big question mark, normally you don't need to pass any data between thread groups.
However if you've been told to do so by your not very competent team lead looking at my crystal ball I can see the following possible problems:
If you're using something like props.put("property-name", vars.get("csrf-token")) you're overwriting the previous value with the next value on each occurrence/iteration because properties are global for the whole JVM process. Consider using ctx.getThreadNum() as the property prefix/postfix
If you're using something like props.put("property-name", "${csrf-token}") the first occurrence of variable is being cached and used on subsequent iterations. Consider using vars.get("csrf-token") instead
More information on these ctx, vars and props guys: Top 8 JMeter Java Classes You Should Be Using with Groovy
In jmeter I have nested loops: an outer ForEach loop, with an inner LoopController. Inside the inner LoopController, I have a user defined variable being incremented with each inner loop. To increment that variable, I am using the config element "Counter".
Once the inner LoopController completes because it has hit its max loop count, it of course exits to the outer ForEach loop. In that outer ForEach loop, I want to re-initialize that user defined variable (int) to an initial (non-zero) value before entering the inner LoopController again. Pretty basic stuff.
I'm using user defined variables. As an example:
initialValue=3
currentValue=${initialValue} - initialize both variables to be the same
In essence, the logic is:
ForEach loop
currentValue=${initialValue}
LoopController loop
Increment currentValue using jmeter's Counter
Done
The problem is the currentValue variable keeps incrementing and is not being re-initialized back in the ForEach loop.
I've tried a number of different methods. Currently, to re-initialize the currentValue variable within the ForEach loop, I'm using a Beanshell PreProcessor as follows (from an example I found in stackoverflow):
String x = vars.get("initialValue");
int y = Integer.parseInt(x);
String z = y;
vars.put("currentValue", z);
I've also tried using the User Defined Variable config element inside the ForEach loop to set the currentValue to initialValue with each loop:
currentValue=${initialValue}
...but that doesn't work either.
I must be overlooking and/or over-complicating this, but jmeter seems to be treating the user defined variables in a not-so-obvious manner.
It is not very possible to reset the counter value using JMeter Variables because the value it's being managed by the Counter internally so if you really need to reset the counter value you will have to use Reflection API for accessing and setting the value of the given property.
Add JSR223 Sampler as a child of the ForEach Controller
Put the following code into "Script" area:
SampleResult.setIgnore()
def engine = engine = ctx.getEngine()
def testPlan = engine.test
def counterSearch = new org.apache.jorphan.collections.SearchByClass<>(org.apache.jmeter.modifiers.CounterConfig.class)
testPlan.traverse(counterSearch)
counter = counterSearch.getSearchResults().first()
counter.globalCounter = vars.get('initialValue') as long
Now your counter value should be reset on each ForEach Controller's iteration
Check out Apache Groovy - Why and How You Should Use It article to learn more about Groovy scripting in JMeter.
Just remember if you bypass a JMeter limitation using reflection somewhere somehow a kitten dies so most probably there is a better way of implementing your use case, by the way are you aware of intSum() function?
I couldn't get to use bsh.shared namespace to share an array between thread groups, please guide me on this
Following is the structure of my jmx file:
ThreadGroup1
Sampler1
Beanshell-PostProcessor1
ThreadGroup2
Sampler2
Beanshell-PreProcessor2
Inside BeanshellPostProcessor1,
if (bsh.shared.names == void){
bsh.shared.names = new java.util.ArrayList();
}
String[] arr = vars.get("fruits").split(',');
for(int i =0;i < arr.length; i++){
if (arr[i].contains("APPLE")){
bsh.shared.names.add[arr[i]]
}
}
When I try to access bsh.shared.names inside Beanshell-PreProcessor2, it doesn't return the value.
There are multiple problems with your code, to wit:
You need to replace split(',') with split(",") because String.split() function takes String as the parameter and you're providing a char
You need to replace bsh.shared.names.add[arr[i]] with bsh.shared.names.add(arr[i]); as this is the correct way of calling ArrayList.add() function
Full code just in case:
if (bsh.shared.names == void){
bsh.shared.names = new java.util.ArrayList();
}
String[] arr = vars.get("fruits").split(",");
for (int i = 0; i < arr.length; i++) {
if (arr[i].contains("APPLE")) {
bsh.shared.names.add(arr[i]);
}
}
Also be aware that starting from JMeter 3.1 it is recommended to use JSR223 Test Elements and Groovy language because Groovy performance is much higher.
There is no bsh.shared namespace in Groovy however you should be able to use props shorthand instead, it will do the same trick for you.
I'm still figuring out how to use p5.js. In regular java you have to declare each variable using its data type, ex. int foo = 0.
In p5, I know you can just use var foo but you can also declare variables using this.foo. If someone could clarify when is the proper time to use var and when i can use this, that would be very helpful.
For example, if I want to declare a variable inside a method, should i use var foo = thing or could I declare it using this.foo = thing? What should I use when declaring global variables or when referring to objects passed into methods?
Thanks!
First of all, p5 is not a language, it is a Javascript library, you are coding in Javascript, not p5.
Coming to your question, if you want to use some function as a data type, similar to a class in java, and want all the "instances" of that to have their own different variables, you use this. If they are just variables you use in someway but don't need to be specific for each instance, or if the function is not a constructor function and is not to be used as a data type, you will just use var then.
Again, there is no class stuff in javascript, you will have to write what is called a constructor function in order to "simulate" a java class, but be aware that a constructor function should not return anything. Here is an example of car class in java:
class car {
int speed = ___;
String model = ___;
static int numOfWheels = ___;
}
This is what it will look like in javascript (a constructor function):
function car() {
this.speed = ____;
this.model = ____;
var numOfWheels = ___;
}
If you declare a variable without this, it can be roughly compared to a static variable in a java class in the sense that it will be constant among all the instances.
So basically, at least in most cases, you will use this.varName usually inside constructor functions, i.e., functions that you will use to construct objects.
What should I use when declaring global variables or when referring to objects passed into methods?
Global variables will almost always be var something = something. When referring to objects passed into functions, just use the dot notation to refer to its properties like passedObject.someProperty
I would recommend you to learn Javascript before jumping into p5 directly, here are some resources that I found useful when I started learning Javascript-
w3 School
JavaScript Info Website
TheNewBoston
My scenario is that I am sending HTTP requests within a loop, in which the arguments values are based on JMeter variables. When first entering the loop I might have variables which are not set at this point, so they are null, hence I’d like to remove the argument from the HTTP request. I can successfully do so with the code below. However, at a later loop-iteration, this variable could now have a value and I would like to include the argument which I have previously removed. So my question is, how can I temporarily remove the argument from my HTTP request?
I have a JMeter Test Plan extract according to:
While Controller
Some logic
HTTP Request
JSR223 PreProcessor (groovy)
My HTTP Request has the following arguments:
Name Value
inputA ${A}
inputB ${B}
My PreProcessor script looks like:
for (Iterator iterator = sampler.getArguments().iterator();
prop = iterator.next();
String value = prop.getStringValue();
if (value.contains('\${')) {
iterator.remove();
}
}
The fastest, the easiest and imho the correct solution would be using __evalVar() JMeter Function like:
So in case if ${A} variable is not defined - inputA parameter will be sent with an empty value and such parameters are ignored by the well-behaved applications. See series of How to Use JMeter Functions guides to get started with JMeter Functions
I recall answering something similar here, it assumed checking if the variables is null using Beanshell
If for some reason points 1 and 2 are not applicable, here is correct code to completely remove the parameter:
import org.apache.jmeter.config.Arguments;
Arguments args = sampler.getArguments();
Iterator it = args.iterator();
while (it.hasNext()) {
def argument = it.next();
if (argument.getStringValue().contains('${')) {
args.removeArgument(argument.getName());
}
}
A solution to this problem could be to make a clone of the sampler Arguments object and set it to the sampler.
import org.apache.jmeter.config.Arguments;
Arguments arguments = sampler.getArguments().clone();
sampler.setArguments(arguments);
for (Iterator iterator = sampler.getArguments().iterator();
prop = iterator.next();
String value = prop.getStringValue();
if (value.contains('\${')) {
iterator.remove();
}
}