Using "repeat" in an "advanced" (Simulation Modularization) scenario

Hi,

Hopefully I’m just missing something simple here.

I’m trying to build a re-usable gatling test runner for our environment. The idea is that I will save out several “Simulations” from the Gatling Recorder, and store them in a directory. I’ll then have one “master” simulation, which will read a config file containing a list of references to some of the other simulations that I’ve saved out, instantiate them and build up a list, and then call “setUp” with the dynamically assembled list of simulations.

So far this is mostly working. The one problem I’m having is that I’d like to use the “repeat” loop, and allow that to be dynamically configured as well. However, it seems like “repeat” is only available from within an individual Simulation class, meaning that I’d have to modify each of the generated Simulation code files to accomplish this.

Is there a better way?

Thanks!
Chris

Easy: import bootstrap._

Cheers,

Stéphane

Thanks for the reply, and for tolerating my lack of familiarity with some of the intricacies of Scala’s type system and generics.

I still can’t quite solve what I’m trying to do, though. Here’s some example code:

class AdvancedSimulation extends Simulation {

val scn1 = new SomeOtherSimGeneratedViaRecorder()
.scn
//.repeat(10)
.users(n.numInstances)
.ramp(n.rampUpDuration)
.protocolConfig(httpConf)

setUp(scn1)
}

Thanks for the reply, and for tolerating my lack of familiarity with some
of the intricacies of Scala's type system and generics.

I still can't quite solve what I'm trying to do, though. Here's some
example code:

class AdvancedSimulation extends Simulation {

...

      val scn1 = new SomeOtherSimGeneratedViaRecorder()
          .scn
          //.repeat(10)
          .users(n.numInstances)
          .ramp(n.rampUpDuration)
          .protocolConfig(httpConf)

  setUp(scn1)
}

In the above code I can insert a ".repeat(10)" immediately after ".scn",
but then the type of the object that is returned by that does not suport
calling ".users" on it. It looks like it's returning a function that
expects to be called with a ChainBuilder

You're not using repeat properly.
repeat takes 2 parameter lists: the first one is the number of iterations,
the second one the chain to repeat (this is called currying).

--but I don't want to override the ChainBuilder that's already defined in
the Simulation class that the Recorder generated. It's kind of like I want
the Recorder to assign that automatically-generated ChainBuilder to its own
val that I can then access by name, rather than accessing the
ScenarioBuilder (scn).

Yep, exactly. I guess you're trying not to have to manually refactor what
you get from the Recorder?

Right; my goal was to try to leave the Recorder-generated simulations completely untouched, and then modify them programatically from my AdvancedSimulation code. For things like “.users”, “.ramp”, this appears to work fine, but I’m not seeing an easy way to do the “repeat” part w/o editing the generated code.

For now I can work around it by editing the generated code. I was just trying to determine if there was some way to do it programatically that I was missing. Seems like maybe there isn’t a way to do that right now.

If I get some more time to hack on some pull requests in the future, I might try to figure out a way to allow that if it’s something you would consider merging. I have a few other ideas about things that would be useful in making those auto-generated Simulations easier to manipulate programatically as well :slight_smile:

But for now I can definitely get by by just editing them by hand. Thanks for putting together such an awesome piece of software!

My bad. I checked the code, and there is a way actually: you have to access the content of the scenario and chop off the last element (start) and build a new Chain.

I’ll make things easier in a next version.

class AdvancedSimulation extends Simulation {

import io.gatling.core.structure.ChainBuilder

val scn1 = scenario(“Repeated”)
.repeat(10) {
new ChainBuilder(new SomeOtherSimGeneratedViaRecorder().scn.actionBuilders.dropRight(1))

}
.users(n.numInstances)
.ramp(n.rampUpDuration)
.protocolConfig(httpConf)

setUp(scn1)
}

Nice! Thanks.

Please let me know if that works properly so that I add a built in in the DSL for the next release.

Hmmm… it looks like the ChainBuilder constructor also requires a second parameter: “next: ActorRef”.

Arf, not in 2.0
Just put a null there (I know, that’s ugly, that’s why it was refactored in 2.0 :wink: )

Tried this today, and with the null in there it compiles OK. But when I run it, it doesn’t actually submit any requests… so at the end, it dies with:

java.lang.UnsupportedOperationException: There were no requests sent during the simulation, reports won’t be generated

I tried removing the “dropRight(1)”, thinking maybe that last action in the chain is what makes it go… but got the same results.

I’ll just stick with the hand-edits of the recorder Sims for now, but would definitely take advantage of a more dynamic way to do this in the future.

Weird: I just tested on both 1.5.1-SNAPSHOT and 2.0.0-SNAPSHOT and it works fine.

https://github.com/excilys/gatling/issues/1145

Hmmm… I was trying it against 1.5.0, not sure if that makes a difference.

So with your new commit, the syntax would be this, correct?:

val scn1 = scenario(“Repeated”)
.repeat(10) {
new SomeOtherSimGeneratedViaRecorder().scn
}
.users(n.numInstances)
.ramp(n.rampUpDuration)
.protocolConfig(httpConf)

Not exactly, you need to wrap with exec.

Here’s my test:

class Hello extends Simulation {

val scn = scenario(“Hello”).exec(http(“Home”).get("/"))

val httpConf = httpConfig
.baseURL(“http://localhost:9000”)
.acceptHeader(“text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8”)
.doNotTrackHeader(“1”)
.acceptLanguageHeader(“en-US,en;q=0.5”)
.acceptEncodingHeader(“gzip, deflate”)
.userAgentHeader(“Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0”)
.shareConnections

setUp(scn.users(1).protocolConfig(httpConf))
}

class World extends Simulation {

val hello = new Hello()

val scn = scenario(“World”).repeat(5) {
exec(hello.scn)
}

setUp(scn.users(1).protocolConfig(hello.httpConf))
}

Interesting. Seems like that exec would be necessary even if I was doing the “new ChainBuilder” approach then, right? I didn’t have an exec there before so maybe that’s why it didn’t work for me.

Nope, just tested with new ChainBuilder(hello.scn.actionBuilders.dropRight(1), null) and it worked fine for me.

Well, I’m stumped then. Maybe I’ll try again from scratch tomorrow. Thanks for the help!

At long last, I got a chance to try this again… and it works! Not sure what I’d done wrong before. Thanks for the help, Stéphane.

Great! And you’re welcome :slight_smile: