Procedure for creating a new Protocol

Hello,

I’m a new user of Gatling using version 1.5.3 of the Maven plugin. I have a client library written in Java that I use to send HTTP requests (it’s a client to handle the authentication handshake the service under test requires). I need to use my client library to send requests and as such I believe that requires me to create my own Protocol.

I was reading the documentation on how to create your own Protocol (https://github.com/excilys/gatling/wiki/Protocol-support) and making the appropriate changes but I’m not sure how to get my change to be used when I run Gatling via the maven plugin. Is there a plugin directory for Gatling? Where should the new Protocol be deployed? Do I register the new Protocol if that’s necessary? Is it expecting the new Protocol to be a part up of my performance/load test project?

If I’m going about this incorrectly please correct me (and update the documentation so other users don’t get confounded).

Thank you,
Charles Agnello

It has to be in the classpath, meaning that:

  • your client library jar has to be a dependency of the maven project
  • your protocol code has to be either package into a jar and added as a dependency, or the sources simply stored along your simulations (Gatling will compile them on the fly).
    Have you checked out James Gregory’s tutorial?

Beware that APIs are changing a lot in Gatling 2, but I can help you migrate once your done.

Thanks for the reply.

For point 1, yes I do have my client library included as a dependency in the performance test project, sorry I didn’t make that clear. I was just unclear about where the new Protocol code should live and you answered that with point 2 so I’ll just include the new scala file(s) in the simulation directory.

Is creating a new Protocol easier in 2.0.0M3? I am using 1.5.3 because I don’t want to have to deal with breaking changes in the API, but I could be convinced to switch.

I saw James Gregory’s tutorial and I’m using it to make sure I have all the right pieces. We’ll see if I can build a custom Protocol.

Thanks again,
Charles Agnello

Note that you don’t necessarily have to build a full blown “protocol”.
I don’t know about your protocol. Is it blocking or non blocking?

Note that as a starter you could just use exec(function) with your code inside this function, and just use DataWriter to report to Gatling stats engine.

The client I’m using is non-blocking.

I tried creating a function and calling it in the exec when I do that I get the following error:

overloaded method value exec with alternatives:
(scenario: com.excilys.ebi.gatling.core.structure.ScenarioBuilder)com.excilys.ebi.gatling.core.structure.ChainBuilder
(chains: Iterable[com.excilys.ebi.gatling.core.structure.ChainBuilder])com.excilys.ebi.gatling.core.structure.ChainBuilder
(chains: Iterator[com.excilys.ebi.gatling.core.structure.ChainBuilder])com.excilys.ebi.gatling.core.structure.ChainBuilder
(chains: com.excilys.ebi.gatling.core.structure.ChainBuilder*)com.excilys.ebi.gatling.core.structure.ChainBuilder
(actionBuilder: com.excilys.ebi.gatling.core.action.builder.ActionBuilder)com.excilys.ebi.gatling.core.structure.ChainBuilder
(sessionFunction: com.excilys.ebi.gatling.core.session.Session => com.excilys.ebi.gatling.core.session.Session)com.excilys.ebi.gatling.core.structure.ChainBuilder
cannot be applied to (Unit)

Looks like I need the function to “return” one of these objects but I don’t quite understand how to do that. All I want the “exec” Action to do is run my Java code.

Here’s what I tried:

var myClient = new MyClient()
def callJavaCode() { myClient.getInfo(id) }

val scn = scenario(“Performance Test Get Info request”).repeat(repeats) {
exec(callJavaCode())

}
setUp(scn.users(users).ramp(ramp))

Charles Agnello

OK, so you actually really have to go with Gatling APIs.

First, you need to implement an ActionBuilder. That’s what is passed to exec().
Then, your ActionBuilder has to build Actions. Those Actions will execute requests with your client. You’ll then deal with the responses within the callbacks, report results to the DataWriter and finally propagate the update Sessions to the next Action.

https://github.com/excilys/gatling/blob/master/gatling-core/src/main/scala/io/gatling/core/action/builder/ActionBuilder.scala

https://github.com/excilys/gatling/blob/master/gatling-core/src/main/scala/io/gatling/core/action/Actions.scala

https://github.com/excilys/gatling/blob/master/gatling-core/src/main/scala/io/gatling/core/result/writer/DataWriter.scala

Am I being clear?

Stéphane

Yes that makes sense. Does that apply to 1.5.3 as well (I see you linked to 2.0.x files)? If not I’ll just start using 2.0.x. I’ll try it and get back to you, but it could be a few days. Work just de-prioritized this project.

Thanks again,
Charles Agnello

Here is an example of a protocol I implemented to execute Specs2 tests under load. This is on Gatling 2.0.0

/**

  • Gatling Protocol support for running Specs2 tests under load.
  • @param spec The Specs2 test to run.
  • @param next Actor that handles session messages between run iterations of the test.
  • @see https://github.com/excilys/gatling/wiki/Protocol-support#the-action
    */
    case class Specs2RunAction(spec: Expression[SpecificationStructure], next: ActorRef)
    extends Interruptable with Failable {
    def executeOrFail(session: Session) = {
    def schedule(specToRun: SpecificationStructure) = {
    system.dispatcher.execute(new Runnable {
    def run(): Unit = {
    val startTime = nowMillis
    runWithoutReporting(specToRun)
    next ! session.increaseDrift(nowMillis - startTime)
    }
    })
    }

spec(session).map(schedule)
}
}

/**

  • Gatling Protocol support for running Specs2 tests under load. The ActorBuilder is used at engine start-up to build Action
  • instances.
  • @param spec The Specs2 test to run.
  • @see https://github.com/excilys/gatling/wiki/Protocol-support#the-actionbuilder
    */
    case class Specs2RunActionBuilder(spec: Expression[SpecificationStructure])
    extends ActionBuilder {
    def build(next: ActorRef, protocols: Protocols): ActorRef = {
    system.actorOf(Props(Specs2RunAction(spec, next)))
    }
    }

The runWithoutReporting(…) method is my optimized implementation of a Specs2 runner that does not do any result reporting or aggregation (painfully slow)
To report stats, the following method is called inside my Specs2 test:

def gatlingLogger(request: RequestSummary, response: ResponseSummary, result: Result): Unit = {
val currentThread = Thread.currentThread
val requestName = sanitize(request.requestLine)

val requestResult =
if (result.isSuccess) OK
else KO

DataWriter.tell(RequestMessage(
“{scenario name}”,
currentThread.getId.toString,
List(),
requestName,
request.clientBeginRequest.getTime,
request.clientDoneRequest.getTime,
response.clientBeginResponse.getTime,
response.clientDoneResponse.getTime,
requestResult,
Some(result.message),
List()
))
}

I dont use Maven so I cant advice how to package your protocol jar together with Gatling. I use SBT and package Gatling and all dependencies using sbt-pack: https://github.com/xerial/sbt-pack

I have been meaning to open source this solution, but only recently moved up to Gatling 2, and I am waiting for the M4 release. I am waiting on the M4 release.

Hey, that’s very cool! Can’t wait so see it open sourced!