How to save variables in gatling session or query results into files

This post is for users who is using gatling gradle plugin io.gatling.gradle and trying to solve the runtime resource path problem with ./bin/gatling.sh after building the bundle.

Background

I have intially setup a project following the gradle plugin, however, after developing the load tests. I realized it’s not super fun to run it with gradle in a remote host. I decided to pack everything in a (bundle structure)[https://gatling.io/docs/gatling/reference/current/general/bundle_structure/] so that I can use command line to run my tests anywhere, this post will not go into how I build the bundle. It works out in the beginning for a simple Simulation, however, as long as I started to use resources, specially I use a Feeder to inject some users’ data, which resources folder my test is using keeps bothers me in the gradle project and in the bundle.

The gradle project has following files:

1
2
3
4
5
6
7
8
9
10
11
project
+ build
++ classes
++ resources
+++ MyFile.csv
+ src
++ gatling
+++ resources
++++ myFile.csv
+++ scala
++++ MySimulation

The structure of the gatling bundle:

1
2
3
4
5
6
7
8
9
10
11
bundle
+ bin
++ gatling.sh
+ conf
++ gatling.conf
+ lib
+ user-files
++ resources
+++ myFile.csv
++ simulations
+++ MySimulation

What is the problem and Where I meet it

In gatling, it’s quite common that we utilize the Session to save or fetch data for a virtul user.

In a recent project, I realized that we might have a few Simulations which might not be ran at the same time, in fact, one Simulation may use the results from another Simulation or we need to log the results from on Simulation.

So I decide to use a PrintWriter to write some session variables into a file which is under the gradle project. I also want to persist it in the git repo so that I can rerun the Simulation which needs the results.

1
2
3
4
5
6
7
.exec(session => {
val writer = new PrintWriter(new FileOutputStream(new File(src/gatling/resources/myFile.csv), true))
writer.write(session("username").as[String] + "," + session("sessionKey").as[String])
writer.write("\n")
writer.close()
session
}

The runtime resource path problem

Running gatling Simulations with gradle task in IDE is super great, however, as I packed things in a bundle, it’s easily known that the above codes won’t work, as there is no src/gatling anymore. There’s a resources folder in the gatling class path if we check the bash gatling.sh

1
GATLING_CLASSPATH="$GATLING_HOME/lib/*:$GATLING_HOME/user-files/resources:$GATLING_HOME/user-files:$GATLING_CONF:"

which means we could use the classloader to help us to find the resources by getClass.getResource(“/myFile.csv”).getPath, it should give me the path to the file.

1
2
3
4
5
6
7
.exec(session => {
val writer = new PrintWriter(new FileOutputStream(new File(getClass.getResource("/myFile.csv").getPath), true))
writer.write(session("username").as[String] + "," + session("sessionKey").as[String])
writer.write("\n")
writer.close()
session
}

The gradle src resource path problem

With the code changes, we can still run the Simulations with gradle, however, as gradle will copy src/resources into the build/resources. The classloader shall be able to find the filepath in the build/resources. Whenever I run the simulations, I will have files generated in the build/resources, which will be deleted when I clean the project, by intention or accidentally.
Oh no, I need this file and I copied it to my src/resources each time I run it, it’s not fun but it’s fine…

Easy solution

Put an environment variable Bundle in the gatling.sh and uses following wrappers to get a file path

1
2
3
4
5
6
7
8
9
10
11
12
13
 // env Bundle=true

def testGeneratedFilePath(filename: String): String = {
var path = ""
val isBundle = System.getenv("Bundle") != null
if (isBundle)
path = s"src/gatling/resources/${filename}"
else
path = getClass.getResource(s"/${filename}").getPath
path
}

val testFileAbsolutePath = new File(testGeneratedFilePath("myFile.csv"));