Temporarily removing an argument from a JMeter HTTP Request - jmeter

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();
}
}

Related

How to set up the launch order Jmeter

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

shared library method definition with Map

I checked few jenkins shared library examples and I found that in some of them the call method define as below:
def call (Map parameters) { .... }
and in other:
def call (Map parameters = [:]) { .... }
What is the difference between definition of parameters with =[:] and without it ?
Groovy supports a feature feature is called default arguments
The first example requires you to pass in a value for the parameter.
call(['key': 'value'])
The second example can be called that way, but it can also be called without specifying a value and it will use the default:
call()

Mocking RestTemplate call with Mockito

I have the following code that is inside of a method that I am testing. I need to mock this restTemplate call to get predictable result.
GitHubEmail[] gitHubEmails = restTemplate
.getForObject(userEmailsUrl, GitHubEmail[].class, oAuthToken);
In the test method, I do this:
RestTemplate mockRestTemplate = Mockito.mock(RestTemplate.class);
GitHubEmail fakeGitHubEmail = new GitHubEmail("testemail#email.com",
false, false, GitHubEmailVisibility.PRIVATE);
GitHubEmail[] fakeEmails = {fakeGitHubEmail};
Mockito.when(mockRestTemplate.getForObject(
Mockito.eq(userUrl),
Mockito.eq(GitHubEmail[].class),
Mockito.eq(testOAuthToken)))
.thenReturn(fakeEmails);
gitHubService.setRestTemplate(mockRestTemplate);
User user = gitHubService.getUser(testOAuthToken);
Things aren't working as I expect them to... When I examine gitHubEmails variable in my method I am testing, it's null.
Why isn't this working?
The current code as it is right now does not contain any mistakes. However, there are two things we don't see from the given code:
We don't see that testOAuthToken is properly passed to the oAuthToken variable within the githubService.
We don't see that the userUrl is passed to the userEmailsUrl within githubService.
You should make sure that all properties match the one you expect them to be, otherwise the mocking doesn't work. Given that you named one property userUrl and the other one userEmailsUrl, it's likely that the error is there.
Usually, when I encounter these error-prone mocking situations, I use "any matchers" (any(), anyString(), ...) when mocking and then after the call and the assertions, I use Mockito.verify() to check if the parameters match:
Mockito.when(mockRestTemplate.getForObject(
Mockito.anyString(), // Use anyString()
Mockito.eq(GitHubEmail[].class),
Mockito.anyString())) // Use anyString()
.thenReturn(fakeEmails);
// Call + Assertions ...
Mockito.verify(mockRestTemplate).getForObject(
Mockito.eq(userUrl), // Use eq()
Mockito.eq(GitHubEmail[].class),
Mockito.eq(testOAuthToken)); // Use eq()
The reason for this is that the verify() output gives a lot more feedback. Rather than just failing, it will tell why it failed when:
The mocked method was called with different arguments, and which arguments
The mocked object had different methods being invoked

Spring AOP get method parameter value based on parameter name

Is it possible to get the method parameter value based on parameter name in Spring AOP.
MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
Method method = signature.getMethod();
method.getParameters().getName()
// possible to get the paramater names
This approach will get parameter names, not value.
proceedingJoinPoint.getArgs()
will return values not names
Then is it possible to get the value based on a parameter name?
As I searched everywhere does not exist a function that gives parameter value by name and I wrote a simple method that makes this work.
public Object getParameterByName(ProceedingJoinPoint proceedingJoinPoint, String parameterName) {
MethodSignature methodSig = (MethodSignature) proceedingJoinPoint.getSignature();
Object[] args = proceedingJoinPoint.getArgs();
String[] parametersName = methodSig.getParameterNames();
int idx = Arrays.asList(parametersName).indexOf(parameterName);
if(args.length > idx) { // parameter exist
return args[idx];
} // otherwise your parameter does not exist by given name
return null;
}
I searched for the same thing when I had to use AOP for logging function arguments and their values but it seems there is no direct way to get value based on argument name.
What I noticed however us that value returned by method.getParameters().getName() and proceedingJoinPoint.getArgs() was always in sync., i.e., for function
public void foo(String a, String b)
called as
foo("hello", "world");
method.getParameters().getName() returned ["a", "b"] and proceedingJoinPoint.getArgs() returned ["hello", "world"], in order. So you can iterate over the array by index and for each index i, the i'th argument name would correspond to i'th argument value.
I couldn't find a supporting documentation for this behavior but hey, this code has been running on production servers for about an year it never has produced incorrect result. Though I'd be glad if someone can link to a documentation of this behavior. You may even dig into reflectiion's code to verify this behavior.

different values for jmeter ${__UUID} in loop

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;

Resources