Gatling 2.0.0 - Compilation error when using variables in the injection profile

I have a simulation that is split between 5 concurrent scenarios. The total RPS = 80, so each scenario is sending a fraction of that number at the same time.
When I run the code with hard-coded values for the divided load, it works fine, but when I replace the hard-coded values with a variable, I get a scala compilation error like this>

injection rates must be strictly positive values

What causes this error, and is there a way to work around it?
I would much rather use variables for this kind of thing than have magic numbers in the code. I’ve attached a copy of the stack trace to this message.
BTW The Simulation is being run from Gradle on a Jenkins server.


before (with *magic numbers*):
setUp(
    text.scnTextOnly.inject(rampUsersPerSec(1) to(16) during (rampTime seconds),constantUsersPerSec(16) during(steadyTime seconds)).protocols(httpTargetCluster), 

... 4 more lines like this follow
)

the change I want to make:
val splitLoad = totalLoad / 5.0

scalaError-mustBeStrictlyPositiveValue.txt (1.28 KB)

The error is quite explicit: splitLoad is equal to 0, which doesn’t make sense.
Note that just like in Java, if you don’t use Math.round and the likes to turn a double into an int, but raw cast, it gets truncated (4 / 5.0 => 0).

Good catch Stephane. I left out the preceding line of code.

Actually splitLoad is a value. Sorry, I was trying to be concise.
This is the full gist of it>

So, did you fixed your issue? Was totalLoad less than 5 as I suspected?

Yes. There was an extra calculation that was not working as expected. When I simplified by removing it, the code started working again.

Great!

Just curious – why does the Injection api require Integers for number of users?
Why can’t it use Doubles like most other things in the DSL?

What would you do with a fraction of a user?

I’m using the fractional value to calculate a work load distribution.
Occasionally the calculated value gets rounded down because of Integer arithmetic, and it makes the Simulation fail.

I’ve found a work around, but it’s kind of clunky, and I’m sure there is probably a better way to do it…but in the meanwhile I was just wondering about the design decisions that were made.

I think you missed my point. What would a half of a user DO exactly? What work would you assign it? And how could it, as only a HALF of a user, actually accomplish it? Would it do all of the work you assigned, or only half of it? If half, which half? Or would it do it slower? What does a fraction of a user MEAN in concrete terms?

The fact that you are trying to do workload distribution using your users is probably an indication that you are not doing it the right way. Perhaps what you want is to do your workload distribution using a randomSwitch().

Point taken. It’s like someone who says they are half Italian and you ask “which half” :slight_smile:

My intention with using these fractional values was to design the work load in terms of RPS rather than number of users without using Throttle, but it looks like I will have to rethink that idea.

I like the idea of randomSwitch, but was a little put off by having to use ChainBuilder to do it. I’ve tried creating some chains but the results did not come out like I wanted in the reports.
However perhaps I need to study a few more code examples.

Point taken. It’s like someone who says they are half Italian and you ask “which half” :slight_smile:

Exactly!

My intention with using these fractional values was to design the work load in terms of RPS rather than number of users without using Throttle, but it looks like I will have to rethink that idea.

You can use Throttle to get RPS, but then use randomSwitch to control the mix of transaction types.

I like the idea of randomSwitch, but was a little put off by having to use ChainBuilder to do it. I’ve tried creating some chains but the results did not come out like I wanted in the reports.

What did you want to accomplish?

I am not entirely opposed to the idea of using randomSwitch to accomplish this, but i’m wondering if it would really solve my dilemma.
Would it be possible to set a chain/user group to claim 0% of traffic? That is what I need to be able to do.

My Simulation class currently has an injection profile set up for each endpoint that is provided by the SUT (System Under Test).The setUP method contains an entry for each endpoint that targets RPS values passed in through system vars like a roll call.

What I would like to do is be able to specify which endpoints I want to test by sending them an RPS value passed in from Jenkins as a sys.env variable.

So, if I wanted to run the Simulation using POST requests only, I would want to be able to “turn off” the GET requests in the work load by passing an RPS value of 0 or something close to it. This is where the “less than 1 user” scenario would come into play. For a load consisting of POST requests only, I’d want to be able to switch off the GET requests in a similar manner.
For a mixed work load, the values would be whatever was passed in from these env vars.

Through experimentation, I’ve found the closest I can get to 0 is 0.1. Anything smaller than this triggers the dreaded “number of users must be strictly positive” compilation error. That is why I am asking why it was designed that way.

An example is attached. Thanks for your time :slight_smile:

example.scala (1.93 KB)

Looking at the attachment, I see you are using Gatling to do functional testing of monitoring tools (dashboard). Correct?

If you are going to be doing “every possible configuration under the sun” of your scenario, which is what I imagine you are shooting for, then you are going to need to build something a little more custom.

One option is to build all of the actual transaction code in libraries. Then for every scenario, or combination of transaction flows, use the Random Switch approach, but hand-build the weights. What happens for each “chain” is just pulled in from the library. When they ask for a different mix, you clone your scenario to a new name, and tweak it to get the desired behavior, but the transaction flows are not duplicated. Make sense?

A more complicated solution, which doesn’t necessarily offer much added functionality, is to make it data-driven. So you have a test configuration. But the problem there is, you won’t be able to rely on the Gatling DSL for the logic of converting that configuration into a scenario. It’s added complexity, but not much added value.

So I would consider a pattern like, define an object that represents a particular class of transaction (e.g. a particular application), and a property of that object that contains a specific transaction flow. Define each object (application) in its own .scala file. Then import those files into your scenario, and reference them by applicationName.transactionFlow. You can make as many variations of the mix-and-match as you need to, because the reference to the transaction code is encapsulated into a single identifier.

Play with that, and see if it solves your needs.

Looking at the attachment, I see you are using Gatling to do functional
testing of monitoring tools (dashboard). Correct?

Sort of. This particular script is excerpted from one I wrote to generate

traffic for our Operations team when they were setting up monitoring tools
and dashboards, so it had a lot of different endoints. For my own
performance testing, the endpoints are much more constrained (it's
actually a Microservice). My Simulation class looks very similar to this,
but uses Assertions to make sure basic performance SLAs are being met.

If you are going to be doing "every possible configuration under the sun"
of your scenario, which is what I imagine you are shooting for, then you
are going to need to build something a little more custom.

One option is to build all of the actual transaction code in libraries.
Then for every scenario, or combination of transaction flows, use the
Random Switch approach, but hand-build the weights. What happens for each
"chain" is just pulled in from the library. When they ask for a different
mix, you clone your scenario to a new name, and tweak it to get the desired
behavior, but the transaction flows are not duplicated. Make sense?

Yes, it makes sense. I like the idea of libraries. Most tests are either

all one type of request (like all GETs, all POSTs, etc) or a classic mixed
work load with a fixed percentage of traffic for each endpoint. At this
time we're not trying to model anything more complex.

A more complicated solution, which doesn't necessarily offer much added
functionality, is to make it data-driven. So you have a test
configuration. But the problem there is, you won't be able to rely on the
Gatling DSL for the logic of converting that configuration into a scenario.
It's added complexity, but not much added value.

Agreed

So I would consider a pattern like, define an object that represents a
particular class of transaction (e.g. a particular application), and a
property of that object that contains a specific transaction flow. Define
each object (application) in its own .scala file. Then import those files
into your scenario, and reference them by applicationName.transactionFlow.
You can make as many variations of the mix-and-match as you need to,
because the reference to the transaction code is encapsulated into a single
identifier.

Play with that, and see if it solves your needs.

Great articulation of the pattern.I can see how what we're doing already

kind of flows along these lines. It is just a matter of getting the right
level of abstraction.