jmeter-java-dsl icon indicating copy to clipboard operation
jmeter-java-dsl copied to clipboard

Question - Does this dsl provide feature to add UserParameters preprocessor ?

Open abygeorgea opened this issue 3 years ago • 5 comments

I would like to know whether this DSL will support adding user parameter preprocessors? If yes, can you please point me to the documentation/ sample where it is used

Use case : REST API ( under performance test) supports 5 different query parameters which can be used individually or as a combination. I need to use different values for these query parameters in every thread. I normally use User parameter preprocessor and set around 10 different thread values for each of these query parameter. During test run, Jmeter will select a value from these defined values.

Is there a way to achieve this while using DSL? If yes, I would like to see a sample

Thanks

abygeorgea avatar Jun 14 '22 06:06 abygeorgea

Hello, thank you for asking this, is a very interesting question.

In the past, when the teams I work with have had similar needs have used the CSV datasource, but that requires synchronization between input CSV and threads configuration to get same behavior you would get with User Parameters pre processor. There might be some edge cases where you can't achieve same functionality but for general cases you can.

You might also implement similar behavior using jsr223 pre processor, but that would require some coding.

We may implement something in the DSL to support this case, let us think about it and come with some proposal. If you have a proposal as well to work from it, you are welcome.

rabelenda avatar Jun 14 '22 21:06 rabelenda

Hello,

we have thought further about this need, and found out that we need to further understand your use case to provide a good solution for it, since just implementing support for user parameters might not be the best fit for your use case in the DSL and we may come up with suboptimal solution.

Have you considered using csvDataSet? Do you actually need each thread to have a specific value that endures during iterations of the same thread, or is it fine for each iteration to exercise a different set or parameters? Do you need control over when the variables evaluation is executed (do you use jmeter functions in User Parameters values)? Or is it just a fixed set of variables values?

If you use csvDataSet you can achieve different behaviors for your use case.

For example, if you just want uniform distribution of a set of parameters between iterations:

param1,param2
param1val1, param2val1
param1val2, param2val2

If you want weighted selection, just duplicate entries proportionally to the weights. Eg: to have first pair twice the times second pair:

param1,param2
param1val1, param2val1
param1val1, param2val1
param1val2, param2val2

If you want the parameter values to be combined in a cartesian product you can use some tool like pict or implement some java logic to generate the csv beforehand like this.

Do you feel generating a CSV would be in some way inconvenient over how you use jmeter user parameters nowadays?

We are eager to understand better your use case and try to come up with a good solution to help you.

Regards

rabelenda avatar Jun 21 '22 18:06 rabelenda

Hello

csvDataSet works in my use case. Thanks for pointing that out.

I was just looking at an option to run a few different threads with various parameters and compare the response time. I don't need to have specific values for each thread. I just need to make sure different parameters are used for each iteration. csvDataSet works fine for that.

My use case is not a full-fledged performance test. This is part of a functional test automation project, in which I use Cucumber & rest assured for test automation.

The cucumber steps will look something like below


When an API is called in 3 parallel threads for 120 seconds with below parameter
  | param1         | param2        | param3      |
  | P1value1       | P2value1      | P3value1    |
  | P1value2       | P2value2      | P3value2    |
  | P1value3       | P2value3      | P3value3    |
  | P1value4       | P2value4      | P3value4    |
  | P1value5       | P2value5      | P3value5    |
  | P1value6       | P2value6      | P3value6    |
  | P1value7       | P2value7      | P3value7    |
  | P1value8       | P2value8      | P3value8    |
  And 99 percentile Response time is less than 2 seconds

Cucumber provides an option to convert the parameters List<Map<String, String>>. Hence I was thinking of using the User parameter option and setting them with input parameters and values. Key from Map will be name and value will be values.

As per your suggestion, I used csvDataSet and it is working fine. I saved the cucumber input parameter into a CSV file and used that file as input for csvDataSet.

While creating the DslHttpSampler, I add the parameters below.


TestPlan(
        vars()
          .set("protocol",protocol)
          .set("hostUrl", hostUrl)
          .set("url",url),
       csvDataSet(filePath),
       threadGroup()
          .rampToAndHold(numberOfThreads, Duration.ofSeconds(5), Duration.ofSeconds(timeInSeconds))
          .rampTo(0, Duration.ofSeconds(2))
          .children(
              httpHeaders()
                   .header("Accept", "application/json"),
               getHttpSampler(url,protocol,hostUrl,queryparams)
      );


 private DslHttpSampler getHttpSampler(String url, String protocol, String hostUrl, List<Map<String, String>> queryparams) {
      var sample=  httpSampler("GetRequest", url)
                .protocol(protocol)
                .host(hostUrl);
        queryparams.get(0).forEach((key,value) -> {
             sample.param(String.format("%s",key),String.format("${%s}",key));
        });
      return sample;
    }

abygeorgea avatar Jun 22 '22 03:06 abygeorgea

Very interesting, thank you for sharing all the details!

Some comments/questions about your code, that may help or not, mainly are out of curiosity :):

  • Why are you setting protocol, hostUrl and url jmeter variables (vars invocation)? Do you use them in other parts of the test plan that are not included in the code you provided?
  • If you want to avoid literal strings in header you might use org.apache.http.HttpHeaders.ACCEPT & org.apache.http.entity.ContentType.APPLICATION_JSON.toString()
  • Does url variable contain only the path part of the url? if it contains the full url, there would be no need for specifying also host and port in the sampler. If the three of them are parts of the full url, you might even also concatenate them make code shorter: httpSampler("GetRequest", protocol + hostUrl + url)
  • Why are you passing a list of sets of query params and only using the first set (queryparams.get(0))? Maybe is a structure that you inherit from some previous code?
  • Any reason for passing a Map of query parameters when you are only using the keys? Maybe is a structure that you inherit from some previous code?
  • Seems that you may replace String.format("%s", key) with just key when you set sample.param

I hope the comments/questions help, best regards, and thank you again for asking this and providing detailed info.

rabelenda avatar Jun 22 '22 12:06 rabelenda

Ok, I guess I understand the reason for questions in points 4 & 5: I guess that list of maps is what you use to generate the CSV before creating the test plan and you only want to get the variable names from it.

rabelenda avatar Jun 22 '22 12:06 rabelenda