Use Scala
Open this github project in intelliJ and install everything that we are asked to install.
And the following should be shown in the console:
Up to this point we are sure that installation is completed.
Custom Script
Now follow this architecture
And create our first simiulation script:
package videogamedb import io.gatling.core.Predef._ import io.gatling.http.Predef._ class MyFirstTest extends Simulation { //http config val httpProtocal = http.baseUrl(url="https://videogamedb.uk/api") .acceptHeader(value="application/json") // scenario def val scn = scenario(name="My First Test") .exec( http("Get all games") .get("/videogame") ) // load scenario setUp(scn.inject(atOnceUsers(1))).protocols(httpProtocal) }
Now run our engine again, as usual java framework try to grab all Simulation
class files in a blackbox secretly. Once we type test
, we get:
videogamedb.MyFirstTest is the only simulation, executing it. Select run description (optional) test Simulation videogamedb.MyFirstTest started... ================================================================================ 2023-11-19 19:01:19 0s elapsed ---- Requests ------------------------------------------------------------------ > Global (OK=1 KO=0 ) > Get all games (OK=1 KO=0 ) ---- My First Test ------------------------------------------------------------- [##########################################################################]100% waiting: 0 / active: 0 / done: 1 ================================================================================ Simulation videogamedb.MyFirstTest completed in 0 seconds Parsing log file(s)... Parsing log file(s) done Generating reports... ================================================================================ ---- Global Information -------------------------------------------------------- > request count 1 (OK=1 KO=0 ) > min response time 721 (OK=721 KO=- ) > max response time 721 (OK=721 KO=- ) > mean response time 721 (OK=721 KO=- ) > std deviation 0 (OK=0 KO=- ) > response time 50th percentile 721 (OK=721 KO=- ) > response time 75th percentile 721 (OK=721 KO=- ) > response time 95th percentile 721 (OK=721 KO=- ) > response time 99th percentile 721 (OK=721 KO=- ) > mean requests/sec 1 (OK=1 KO=- ) ---- Response Time Distribution ------------------------------------------------ > t < 800 ms 1 (100%) > 800 ms <= t < 1200 ms 0 ( 0%) > t >= 1200 ms 0 ( 0%) > failed 0 ( 0%) ================================================================================ Reports generated in 0s. Please open the following file: file:///C:/Users/user/Repos/gatling/2023-11-19-gatling-maven-plugin-demo-scala-main/target/gatling/myfirsttest-20231119110117759/index.html Process finished with exit code 0
We also get a full review in an html file:
Scripts Fundamental in Gatling
Pause
package videogamedb.scriptfundamentals import io.gatling.core.Predef._ import io.gatling.http.Predef._ import scala.concurrent.duration.DurationInt class AddPauseTime extends Simulation{ val httpProtocol = http.baseUrl("https://videogamedb.uk/api") .acceptHeader("application/json") val scn = scenario("Video Game DB - 3 calls") .exec(http("Get all video games").get("/videogame")) .pause(5) .exec(http("Get specific game").get("/videogame/1")) .pause(1, 10) // random pause time between 1 and 10 .exec(http("Get all video games - 2nd call").get("/videogame")) .pause(3000.milliseconds) setUp(scn.inject(atOnceUsers(users=1)).protocols(httpProtocol)) }
Check Response Code
package videogamedb.scriptfundamentals import io.gatling.core.Predef._ import io.gatling.http.Predef._ import scala.concurrent.duration.DurationInt class CheckResponseCode extends Simulation{ val httpProtocol = http.baseUrl("https://videogamedb.uk/api") .acceptHeader("application/json") val scn = scenario("Video Game DB - 3 calls") .exec( http("Get all video games") .get("/videogame") .check(status.is(200)) ) .pause(5) .exec(http("Get specific game") .get("/videogame/1") .check(status.in(200 to 210)) ) .pause(1, 10) // random pause time between 1 and 10 .exec(http("Get all video games - 2nd call") .get("/videogame") .check(status.not(404), status.not(500)) ) .pause(3000.milliseconds) setUp(scn.inject(atOnceUsers(users=1)).protocols(httpProtocol)) }
Check Response Body
package videogamedb.scriptfundamentals import io.gatling.core.Predef._ import io.gatling.http.Predef._ import scala.concurrent.duration.DurationInt class CheckResponseBodyAndExtract extends Simulation{ val httpProtocol = http.baseUrl("https://videogamedb.uk/api") .acceptHeader("application/json") val scn = scenario("Check with JSON path").exec( http("Get specific game") .get("/videogame/1") .check(jsonPath("$.name").is("Resident Evil 4")) ).exec() setUp(scn.inject(atOnceUsers(users=1)).protocols(httpProtocol)) }
Save the Result in Variable and Reuse it
package videogamedb.scriptfundamentals import io.gatling.core.Predef._ import io.gatling.http.Predef._ import scala.concurrent.duration.DurationInt class CheckResponseBodyAndExtract extends Simulation{ val httpProtocol = http.baseUrl("https://videogamedb.uk/api") .acceptHeader("application/json") val scn = scenario("Check with JSON path") .exec(http("Get specific game") .get("/videogame/1") .check(jsonPath("$.name").is("Resident Evil 4")) ) .exec(http("Get all video games") .get("/videogame") .check(jsonPath(path="$[1].id").saveAs("gameId")) ) .exec(http("Get specific game") .get("/videogame/#{gameId}") .check(jsonPath("$.name").is("Gran Turismo 3")) ) setUp(scn.inject(atOnceUsers(users=1)).protocols(httpProtocol)) }
Logging for Debugging
package videogamedb.scriptfundamentals import io.gatling.core.Predef._ import io.gatling.http.Predef._ import scala.concurrent.duration.DurationInt class CheckResponseBodyAndExtract extends Simulation{ val httpProtocol = http.baseUrl("https://videogamedb.uk/api") .acceptHeader("application/json") val scn = scenario("Check with JSON path") .exec(http("Get specific game") .get("/videogame/1") .check(jsonPath("$.name").is("Resident Evil 4")) ) .exec(http("Get all video games") .get("/videogame") .check(jsonPath(path="$[1].id").saveAs("gameId")) ) .exec { session => println(session); session} .exec(http("Get specific game") .get("/videogame/#{gameId}") .check(jsonPath("$.name").is("Gran Turismo 3")) .check(bodyString.saveAs("responseBody")) ) .exec { session => println(session("responseBody").as[String]); session} setUp(scn.inject(atOnceUsers(users=1)).protocols(httpProtocol)) }
Code Reuse
package videogamedb.scriptfundamentals import io.gatling.core.Predef._ import io.gatling.http.Predef._ class CodeReuse extends Simulation { val httpProtocol = http.baseUrl("https://videogamedb.uk/api") .acceptHeader("application/json") def getAllVideoGames() = { exec( http("Get all video games") .get("/videogame") .check(status.is(200)) ) } def getSpecificGame() = { exec( http("Get specific game") .get("/videogame/1") .check(status.in(200 to 210)) ) } val scn = scenario("Code reuse") .exec(getAllVideoGames()) .pause(5) .exec(getSpecificGame()) .pause(5) .exec(getAllVideoGames()) setUp(scn.inject(atOnceUsers(users=1)).protocols(httpProtocol)) }
Repeat Requests Several Times (Single User)
package videogamedb.scriptfundamentals import io.gatling.core.Predef._ import io.gatling.http.Predef._ class CodeReuse extends Simulation { val httpProtocol = http.baseUrl("https://videogamedb.uk/api") .acceptHeader("application/json") def getAllVideoGames() = { repeat(3){ exec( http("Get all video games") .get("/videogame") .check(status.is(200)) ) } } def getSpecificGame() = { repeat(5, "counter"){ exec( http(s"Get specific game with id: #{counter}") .get("/videogame/#{counter}") .check(status.in(200 to 210)) ) } } val scn = scenario("Code reuse") .exec(getAllVideoGames()) .pause(5) .exec(getSpecificGame()) .pause(5) .repeat(2){ getAllVideoGames() } setUp(scn.inject(atOnceUsers(users=1)).protocols(httpProtocol)) }
Authenticate and Use that Token for Post Request
The authentication post request returns the following json
{ "token": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImlhdCI6MTcwMDQwMjQ0MCwiZXhwIjoxNzAwNDA2MDQwfQ.MgyULBwMTd_Kj13E7UwrMALNctO6NUTL9qxS_sOk39k" }
We can use jsonPath $.token
to extract this value and use it elsewhere.
package videogamedb.scriptfundamentals import io.gatling.core.Predef._ import io.gatling.http.Predef._ class Authenticate extends Simulation { val httpProtocol = http.baseUrl("https://videogamedb.uk/api") .acceptHeader("application/json") .contentTypeHeader("application/json") def authenticate() = { exec(http("Authenticate") .post("/authenticate") .body(StringBody("{\n \"password\": \"admin\",\n \"username\": \"admin\"\n}")) .check(jsonPath("$.token").saveAs("jwtToken")) ) } def createNewGame() = { exec(http("Create new game") .post("/videogame") .header("Authorization", "Bearer #{jwtToken}") .body(StringBody( "{\n \"category\": \"Platform\",\n \"name\": \"Mario\",\n \"rating\": \"Mature\",\n \"releaseDate\": \"2012-05-04\",\n \"reviewScore\": 85\n}" )) ) } val scn = scenario("Authenticate") .exec(authenticate()) .exec(createNewGame()) setUp(scn.inject(atOnceUsers(users = 1)).protocols(httpProtocol)) }
Feed Data into the Test
CsvFeeder
package videogamedb.feeders import io.gatling.core.Predef._ import io.gatling.http.Predef._ import scala.concurrent.duration.DurationInt class CsvFeeder extends Simulation{ val httpProtocol = http.baseUrl("https://videogamedb.uk/api") .acceptHeader("application/json") val csvFeeder = csv("data/gameCsvFile.csv").circular def getSpecificVideoGame() = { repeat(10){ feed(csvFeeder) .exec(http("Get video game with name - #{gameName}") .get("/videogame/#{gameId}") .check(jsonPath("$.name").is("#{gameName}")) .check(status.is(200)) ) .pause(1) } } val scn = scenario("Csv feeder test") .exec(getSpecificVideoGame()) setUp(scn.inject(atOnceUsers(users=1)).protocols(httpProtocol)) }
Complex Feeder with Json Template, Random Data (String, Integer, Date)
Json Template
Let's create a template here:
Note that for non-string content we should not enclose it by "
's.
// resources/bodies/newGameTemplate.txt { "id": #{gameId} , "category": "#{category}", "name": "#{name}", "rating": "#{rating}", "releaseDate": "#{releaseDate}", "reviewScore": #{reviewScore} }
Script
package videogamedb.feeders import io.gatling.core.Predef._ import io.gatling.http.Predef._ import java.time.LocalDate import java.time.format.DateTimeFormatter import scala.util.Random class ComplexCustomFeeder extends Simulation{ val httpProtocol = http.baseUrl("https://videogamedb.uk/api") .acceptHeader("application/json") .contentTypeHeader("application/json") val idNumbers = (1 to 10).iterator val rnd = new Random() val now = LocalDate.now() val pattern = DateTimeFormatter.ofPattern("yyyy-MM-dd") def randomString(length:Int) ={ rnd.alphanumeric.filter(_.isLetter).take(length).mkString } def randomDate(startDate: LocalDate, random:Random):String = { startDate.minusDays(random.nextInt(30)).format(pattern) } val customFeeder = Iterator.continually(Map( "gameId" -> idNumbers.next(), "name" -> ("Game-" + randomString(5)), "releaseDate" -> randomDate(now, rnd), "reviewScore" -> rnd.nextInt(100), "category" -> ("Category-" + randomString(6)), "rating" -> ("Rating-" + randomString(4)), )) def authenticate() = { exec(http("Authenticate") .post("/authenticate") .body(StringBody("{\n \"password\": \"admin\",\n \"username\": \"admin\"\n}")) .check(jsonPath("$.token").saveAs("jwtToken")) ) } def createNewGame()={ repeat(10){ feed(customFeeder) .exec(http("Create new game - #{name}"). post("/videogame") .header("authorization", "Bearer #{jwtToken}") .body(ElFileBody("bodies/newGameTemplate.json")).asJson .check(bodyString.saveAs("responseBody")) ) .exec{session => println(session("responseBody").as[String]); session} .pause(1) } } val scn = scenario("Csv feeder test") .exec(authenticate()) .exec(createNewGame()) setUp(scn.inject(atOnceUsers(users = 1)).protocols(httpProtocol)) }
Load Test with Scenario: Increase Number of Users Concurrently for a Period
package videogamedb.simulations import io.gatling.core.Predef._ import io.gatling.http.Predef._ class BasicLoadSimulation extends Simulation { val httpProtocol = http.baseUrl("https://videogamedb.uk/api") .acceptHeader("application/json") def getAllVideoGames() = { exec( http("Get all video games") .get("/videogame") ) } def getSpecificGame() = { exec( http("Get specific game") .get("/videogame/2") ) } val scn = scenario("Basic Load Simulation") .exec(getAllVideoGames()) .pause(5) .exec(getSpecificGame()) .pause(5) .exec(getAllVideoGames()) setUp( scn.inject( nothingFor(5), atOnceUsers(5), rampUsers(10).during(10) ).protocols(httpProtocol) ) }