Counting the number of arguments to setUp

Hi,

I have a fairly simple setUp and several different simulations placed in different Scala files. In inject methods for scripts, the number of users and duration are specified as a terminal argument.

The question is whether there is any way to get the number of scenarios that we have passed to setUp in order to divide crmUsers by their number.

I want to do this because I have the same crmUsers for all simulations, but some of them have more scenarios, while others have fewer, so that in the end there would be the same load distribution across different sections

Or somehow through the methods, my ChainBuilder methods are collected in the same file into an object that is then called in the script, their number is the same as the number of scenarios used in setUp

An example of what I want to do:

  crmUsers = crmUsers / 3 - I want to replace this with some functional method, not a hardcode value

  setUp(
    appDiscountsScenario.inject(
      rampPerSec(crmUsers, crmDuration),
      const(crmDuration),
      rampPerSecReverse(crmUsers, crmDuration)
    ),
    appInvoiceScenario.inject(
      rampPerSec(crmUsers, crmDuration),
      const(crmDuration),
      rampPerSecReverse(crmUsers, crmDuration)
    ),
    appServiceAccountsScenario.inject(
      rampPerSec(crmUsers, crmDuration),
      const(crmDuration),
      rampPerSecReverse(crmUsers, crmDuration)
    )
  )

Thanks in advance for your reply

Gatling 3.8.0; Scala

Hi,

Not sure to understand your request here.

In Scala, you cannot reassign a val.
So if you already have your original crmUsers (from properties sys.props or environment variable sys.env) you can create other vals for your user amount by scenario:

  val discountUsers = crmUsers / 3
  val invoiceUsers = crmUsers / 3
  val serviceAccountsUsers = crmUsers / 3

  setUp(
    appDiscountsScenario.inject(
      rampPerSec(discountUsers, crmDuration),
      const(crmDuration),
      rampPerSecReverse(discountUsers, crmDuration)
    ),
    appInvoiceScenario.inject(
      rampPerSec(invoiceUsers, crmDuration),
      const(crmDuration),
      rampPerSecReverse(invoiceUsers, crmDuration)
    ),
    appServiceAccountsScenario.inject(
      rampPerSec(serviceAccountsUsers, crmDuration),
      const(crmDuration),
      rampPerSecReverse(serviceAccountsUsers, crmDuration)
    )
  )

What do you think?
Is this solve your issue?
Note: it’s a scala language feature, not gatling issue.

Hope it helps,

Cheers!

Unfortunately no. I want that there would not be “3” by itself, but in its place there would be some method that gives the number of arguments for “setUp” or objects for the object in which I have ChainBuilder. For example:
crmUsers = crmUsers / App.getClass.getMethods.length
App - object
Or something similar, but setUp arguments instead “App.getClass.getMethods.length”

However, this option is not suitable due to the fact that this method (getMethods) gives all the available methods for this object:

private static java.lang.Object com.allinone.apigateway.AppCustomerAccountSimulation$App$.$deserializeLambda$(java.lang.invoke.SerializedLambda)
public static final java.lang.Object com.allinone.apigateway.AppCustomerAccountSimulation$App$.$anonfun$appServiceAccounts$4$adapted(java.lang.reflect.Method)
public io.gatling.core.structure.ChainBuilder com.allinone.apigateway.AppCustomerAccountSimulation$App$.appInvoices() - **my methods**
public io.gatling.core.structure.ChainBuilder com.allinone.apigateway.AppCustomerAccountSimulation$App$.appDiscounts() - **my methods**
public io.gatling.core.structure.ChainBuilder com.allinone.apigateway.AppCustomerAccountSimulation$App$.appServiceAccounts() - **my methods**
public static final io.gatling.commons.validation.Validation com.allinone.apigateway.AppCustomerAccountSimulation$App$.$anonfun$appServiceAccounts$3(com.allinone.apigateway.AppCustomerAccountSimulation$App$,io.gatling.core.session.S
ession)
public static final io.gatling.commons.validation.Validation com.allinone.apigateway.AppCustomerAccountSimulation$App$.$anonfun$appServiceAccounts$1(io.gatling.core.session.Session)
public static final io.gatling.commons.validation.Validation com.allinone.apigateway.AppCustomerAccountSimulation$App$.$anonfun$appServiceAccounts$2(io.gatling.core.session.Session)
public static final io.gatling.commons.validation.Validation com.allinone.apigateway.AppCustomerAccountSimulation$App$.$anonfun$appDiscounts$1(io.gatling.core.session.Session)
public static final io.gatling.commons.validation.Validation com.allinone.apigateway.AppCustomerAccountSimulation$App$.$anonfun$appDiscounts$2(io.gatling.core.session.Session)
public static final io.gatling.commons.validation.Validation com.allinone.apigateway.AppCustomerAccountSimulation$App$.$anonfun$appInvoices$1(io.gatling.core.session.Session)
public static final void com.allinone.apigateway.AppCustomerAccountSimulation$App$.$anonfun$appServiceAccounts$4(java.lang.reflect.Method)
public static final io.gatling.commons.validation.Validation com.allinone.apigateway.AppCustomerAccountSimulation$App$.$anonfun$appInvoices$2(io.gatling.core.session.Session)

Oh! I didn’t understand what you wanted.

As you use the same injection profile for your scenarios, you may want to apply the same construct for all:

  val scenarios = List(appDiscountsScenario, appInvoiceScenario, appServiceAccountsScenario)

  val crmUsersByScenario = crmUsers / scenarios.size

  val injectionProfiles = scenarios.map(_.inject(
    rampPerSec(crmUsersByScenario, crmDuration),
    const(crmDuration),
    rampPerSecReverse(crmUsersByScenario, crmDuration)
  ))

  setUp(
    injectionProfiles
  ).protocols(httpProtocol)

Is this better?

Cheers!

1 Like

Sorry for re-opening the topic, but there is another related question. I did as they suggested (thank you very much for this), but it became necessary to separate some scripts into a separate launch because they are heavier than the others and so as not to affect other endpoints

I thought to do it through andThen, but I get an error about “overloaded method” if put in setUp or after scenarios.map. But if inside scenarios.map after inject I get an error

Scenario names must be unique but found duplicates: List(name)

  val invoicesInfoScenario =
    scenario(s"*name*")
      .exec(ServiceAccount.serviceAccountInvoices)

  val scenarios =
    List(
      paymentsInfoScenario,
      dashboardInfoScenario,
      processesInfoScenario,
      subscriptionsScenario,
      ordersInfoScenario,
      subscriptionIdInfoScenario,
      paymentsByInvoiceInfoScenario,
      subscriptionsInfoScenario
    )

  // endregion

  val crmUsersByScenario = crmUsers / scenarios.size

  val injectionProfiles = scenarios.map(
    _.inject(
      rampPerSec(crmUsersByScenario, crmDuration),
      const(crmDuration),
      rampPerSecReverse(crmUsersByScenario, crmDuration)
    ).andThen(
      invoicesInfoScenario.inject(
        rampPerSec(crmUsers, crmDuration),
        const(crmDuration),
        rampPerSecReverse(crmUsers, crmDuration)
      ) - duplicate error
    ) - overload error
  )

  setUp(
    injectionProfiles - overload error
  ).protocols(http.baseUrl(apiGatewayHost))
}

Can you please suggest how can I separate the launch of this scenario?

Hello back,

Note: you should have opened an another thread, as the two issues are related but not the same.

There are 2 different issues.

First one, “duplicates”: Indeed, when you add andThen in the map, you’re telling that for each scenario in the list, you append the invoicesInfoScenario and one requirement of Gatling is to have distinct names for scenarios.

Second one, I’m not sure to understand, but I think you try to apply the andThen method on a List of PopulationBuilder, so the type of the result is not really defined, so the compiler doesn’t know which setUp overloads to apply.

What is the requirement?

If invoicesInfoScenario is launched at the same time

You’ll have to build your List of Population builder.

  val scenarios = List(appDiscountsScenario, appInvoiceScenario, appServiceAccountsScenario)
  val crmUsersByScenario = crmUsers / scenarios.size

  val injectionProfiles = scenarios.map(
    _.inject(rampPerSec(crmUsersByScenario, crmDuration)))

  val specificInjectionProfile = invoicesInfoScenario.inject(rampPerSec(crmUsersByScenario, crmDuration))

  val allInjectionProfiles = injectionProfile :+ specificInjectionProfile

  setUp(
    allInjectionProfiles
  ).protocols(httpProtocol)

Note: this is basic List manipulation in Scala. If you aren’t familiar to Scala, do you know you can use the Java or the Kotlin DSL as well?

If invoicesInfoScenario is launched after the other scenarios

You have to make a dummy PopulationBuilder to be able to chain the andThen methods

  val specificInjectionProfile = invoicesInfoScenario.inject(constantUsersPerSec(crmDuration).during(crmDuration))
  
  val starterScenario = scenario("Starter").pause(1)

  setUp(
    starterScenario.inject(constantUsersPerSec(1).during(1))
      .andThen(injectionProfiles)
      .andThen(specificInjectionProfile)
  ).protocols(httpProtocol)

Note: the andThen method is defined on the PopulationBuilder for building sequential scenarios

Does this helps?

Cheers!

1 Like

Yes, the second option helped, thanks, and you are right on the assumption, I just initially tried to do it through List[PopulationBuilder].andThen(invoicesInfoScenario…), but it didn’t work, and therefore I didn’t try the other way around