Usage of gatling feeders

N LAMY picture N LAMY · Dec 9, 2014 · Viewed 17.2k times · Source

I'm trying to use two gatling feeders for producing http post request data :

First file contains some fields. One of them is a counter. With this value I'd like to add to my post body as far as lines from second feeder.

For example :

fileA.csv
---------
fileAId,counter
value,3

fileB.csv
---------
fileBId
stack
overflow

I want to construct this string : "value stack overflow stack".

I created a scenario :

object Actions {
    val search = forever() {
        group("Test") {
            exec(feed(FeederUtils.fileAFeeder))
            .exec(  
                http("Test")                                            
                    .post(uri)                          
                    .body(StringBody("""${fileAId} """ +     FeederUtils.generateItems(${counter}.toInt)))
                )
                .pause(20 seconds)
            }
        }
}   

And an object FeederUtils :

object FeederUtils {
    val fileAFeeder= csv("fileA.csv").circular

    var fileBFeeder = csv("fileB.csv").circular

    def generateItems(itemsNumber: Int) : String = {
        var i = 0;
        var returnedString = "";
        for(i <- 0 to itemsNumber) {
            exec(feed(fileBFeeder))
            returnedString = returnedString + """${fileBId} """
        }

        return returnedString ;
    }
}

I have two problems : function call doesn't compile (not found: value $) and feeder variables doesn't exist in generateItems.

I'm new to Gatling & Scala so I think this is evident but I don't understand how exec and feed functions work.

Thanks !

EDIT : Functionnal code is below :

object FeederUtils {
    val fileAFeeder= csv("fileA.csv").circular

    var fileBVector = csv("fileB.csv").records

    var fileBIterator = 0;

    def generateItems(itemsNumber: Int) : String = {
        var i = 0;
        var returnedString = "";
        for(i <- 0 to itemsNumber) {
            var currentItem = fileBVector(fileBIterator)

            //Circular read
            if (fileBIterator < fileBVector.size) { 
              fileBIterator+=1
            } else {
              fileBIterator=0
            }

            returnedString = returnedString + currentItem("fileBId")
        }

        return returnedString ;
   }
}

object Actions {
    val search = forever() {
        group("Test") {
            exec(feed(FeederUtils.fileAFeeder))
            .exec({session => session.set("generatedString",feederUtils.generateItems(session("counter").as[String].toInt))})
            .exec(  
                http("Test")                                            
                    .post(uri)                          
                    .body(StringBody("""${fileAId} ${generatedString}"""))
                )
                .pause(20 seconds)
            }
        }
} 

The concept below is : feed function stores data into session attributes, which can be readed from gatling EL expressions or manually with Session API. I had to combine both.

Links :

Session API

EL Expressions

Session manipulation with exec

Answer

Stephane Landelle picture Stephane Landelle · Dec 9, 2014

You can't use a feeder for your second file. At best, you can pull multiple records at once, but names will be translated (fileBId1, fileBId2...).

Load the second file content with Gatling csv parser, so you'll be able to access the records (records field) and store it into a global val.

Feed from the first file.

Then write an exec(function) where you:

  • fetch the counter from the session
  • generate a random offset (ThreadLocalRandom) if you want something like the random strategy, or an AtomicInteger that you would increment if you want something like the circular strategy.
  • fetch records from the second file (use a modulo on the records vector size to get proper indices)
  • compute your final String

Don't try to use Gatling EL in custom code. See doc.