Basic Gatling load script with feeders

Examples on the usage of feeders in Gatling were a bit hard to find on the internet, so maybe someone will find my example helpful in one way or another. I’m no scala guru by any means, so feel free to improve the examples if you feel like it.

This example will run in basic stand-alone Gatling setup (gatling.sh) or through maven using the gatling-maven-plugin (mvn gatling:execute). We’re gonna construct a scala class in file BasicGatlingScenarioWithFeeders.scala. For this to work with gatling.sh the file should be placed in the standard-location ${GATLING_HOME}/user-files/simulations. For Maven, setup a standard maven project and put the file in src/test/scala. Create the directories bodies and data in src/test/scala.

There is another option to run gatling through sbt, but for now that would only complicate things.

Let’s start by importing some Scala and Gatling stuff.

import java.time.LocalDate
import java.time.format.DateTimeFormatter
import java.util
import java.util.Collections
 
import io.gatling.core.Predef._ 
import io.gatling.http.Predef._ 

import scala.collection.JavaConversions._
import scala.concurrent.duration._ 
import scala.util.Random

First, we’ll need some data. Three quotes (“””)  form the raw-string indicator, to include the fourth double-quote (“) in the required String “PLEP” or “TUUT”.

class LoadSimulation extends Simulation {

  val rnd = new Random
  val now = LocalDate.now()
  val pattern = DateTimeFormatter.ofPattern("yyyy-MM-dd")
  val someList = Seq("null", """"PLEP"""", """"TUUT"""")

Some functions to generate dates, times or pick an item from a list.

  def getRandomElement(list: Seq[String], random: Random): String = 
    list(random.nextInt(list.length))

  def getRandomTime(random: Random): String = {
    String.format("%02d:%02d:%02d", 
      random.nextInt(24): Integer, 
      random.nextInt(60): Integer, 
      random.nextInt(60): Integer)
  }

  def getRandomToDate(startDate: LocalDate, random: Random): String = {
    startDate.plusDays(random.nextInt(21)).format(pattern)
  }

And then the feeders using all of the above. When read from, a feeder will provide a session-variable from the mapped entry. The key will be the name of the variable, the value its value. So anytime feed(randomElementFeeder) is called, a variable ${someElement} becomes available in the scenario. The problem is that this all happens quite invisible, read on to find out how to show the retrieved value from the feeder.

  val randomElementFeeder = 
    Iterator.continually(Map("someElement" -> getRandomElement(someList, rnd)))

  val randomDateFeeder = 
    Iterator.continually(Map("someDate" -> getRandomToDate(now, rnd)))

  val randomTimeFeeder = 
    Iterator.continually(Map("someTime" -> getRandomTime(rnd)))

  var counterLoop:Array[Map[String,String]] = 
    (1 to 1000).toArray map ( x => { Map( "counter" -> x.toString) })

This examle will do a REST call so some HTTP config is needed. There are a lot more options (SSL, keepalive). Checkout the Gatling docs.

  val baseHttpProtocol = http
    .acceptHeader("application/json;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"
    )

The main scenario will be executed with injected users further on. The template file NameOfTemplateFile.json is exactly that. The file should be stored in the bodies directory. In the file you can refer to the session-variables as ${variableName}:

{
    "fieldName" : "${someElement}"
}

Below the scenario:

  val scn = scenario("NameOfScenario").repeat(1000) {
    feed(randomDateFeeder)
    .feed(randomTimeFeeder)
    .feed(randomElementFeeder)
    .feed(counterLoop.circular)
    .exec(
        http("NameOfRequestShowsUpInReport")
        .post("/path/to/my/api")
        .header("AdditionalHeader", "1")
        .body(ElFileBody("NameOfTemplateFile.json")).asJSON
    )
    .pause(5 milliseconds)
  }

And putting it all together. (You can put multiple classes in the same file).

class BasicGatlingScenarioWithFeeders extends LoadSimulation {

  val httpProtocol = baseHttpProtocol.baseURL("http://elasticsearch-cluster:9200")

  setUp(scn.inject(atOnceUsers(1))
  .protocols(httpProtocol))
  .maxDuration(20 seconds)
}

If you need to debug the feeder, it is possible to see the output from the feed() calls by adding another debug exec() to the scenario.

  .exec(session => {
    println(session("someElement").as[String])
    session }
  )

To get this script to run with maven, for intstance in a CI/CD situation, you can use the following config in your pom.xml. There are some more options, which you can find in documentation of the gatling-maven-plugin.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

  <modelVersion>4.0.0</modelVersion>

  <groupId>nl.rubix.test</groupId>
  <artifactId>BasicGatlingScenarioWithFeeders</artifactId>
  <version>1.0.0-SNAPSHOT</version>

  <properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <scala.version>2.11.7</scala.version>
    <encoding>UTF-8</encoding>
    <gatling.version>2.2.3</gatling.version>
  </properties>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>io.gatling</groupId>
        <artifactId>gatling-app</artifactId>
        <version>${gatling.version}</version>
      </dependency>
      <dependency>
        <groupId>io.gatling</groupId>
        <artifactId>gatling-recorder</artifactId>
        <version>${gatling.version}</version>
      </dependency>
      <dependency>
        <groupId>io.gatling.highcharts</groupId>
        <artifactId>gatling-charts-highcharts</artifactId>
        <version>${gatling.version}</version>
      </dependency>
      <dependency>
        <groupId>org.scala-lang</groupId>
        <artifactId>scala-library</artifactId>
        <version>${scala.version}</version>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>
    <dependency>
      <groupId>io.gatling.highcharts</groupId>
      <artifactId>gatling-charts-highcharts</artifactId>
    </dependency>
    <dependency>
      <groupId>io.gatling</groupId>
      <artifactId>gatling-app</artifactId>
    </dependency>
    <dependency>
      <groupId>io.gatling</groupId>
      <artifactId>gatling-recorder</artifactId>
    </dependency>
    <dependency>
      <groupId>org.scala-lang</groupId>
      <artifactId>scala-library</artifactId>
    </dependency>
  </dependencies>

  <build>
    <plugins>

      <plugin>
        <groupId>io.gatling</groupId>
        <artifactId>gatling-maven-plugin</artifactId>
        <version>2.2.1</version>
        <configuration>
          <configFolder>${project.basedir}/src/test/resources</configFolder>
          <dataFolder>${project.basedir}/src/test/resources/data</dataFolder>
          <resultsFolder>${project.basedir}/target/gatling/results</resultsFolder>
          <bodiesFolder>${project.basedir}/src/test/resources/bodies</bodiesFolder>
          <simulationsFolder>${project.basedir}/src/test/scala</simulationsFolder>
          <runDescription>SomeDescriptionWhenRunningTests</runDescription>
          <noReports>true</noReports>
          <simulationClass>BasicGatlingScenarioWithFeeders</simulationClass>
          <propagateSystemProperties>true</propagateSystemProperties>
          <failOnError>true</failOnError>
        </configuration>
        <executions>
          <execution>
            <phase>test</phase>
            <goals>
              <goal>execute</goal>
            </goals>
          </execution>
        </executions>
      </plugin>

    </plugins>
  </build>
</project>

And with this, you should have a basic Gatling scenario.

Advertisements

2 thoughts on “Basic Gatling load script with feeders

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s