diff --git a/scala-gatling/.gitignore b/scala-gatling/.gitignore new file mode 100644 index 000000000..fc40e2d95 --- /dev/null +++ b/scala-gatling/.gitignore @@ -0,0 +1,5 @@ +target +.idea +.settings +.classpath +.project diff --git a/scala-gatling/README.md b/scala-gatling/README.md new file mode 100644 index 000000000..2fa9e1f13 --- /dev/null +++ b/scala-gatling/README.md @@ -0,0 +1,10 @@ +### Relevant Articles: +- [Testing With Gatling Using Scala]() + +### Gatling Executions +From this module's folder, we first compile tests: `sbt test:compile` + +Then run the simulation: `sbt 'Gatling/testOnly com.baeldung.gatling.PeakLoadSimulation'` + +**Notes**: in order to spin-up the right API this example uses, we also need to start the server: +`sbt resApi/run` from root folder diff --git a/scala-gatling/build.sbt b/scala-gatling/build.sbt new file mode 100644 index 000000000..1dda5af89 --- /dev/null +++ b/scala-gatling/build.sbt @@ -0,0 +1,11 @@ +enablePlugins(GatlingPlugin) + +scalaVersion := "2.13.15" + +scalacOptions := Seq( + "-encoding", "UTF-8", "-release:8", "-deprecation", + "-feature", "-unchecked", "-language:implicitConversions", "-language:postfixOps") + +val gatlingVersion = "3.13.1" +libraryDependencies += "io.gatling.highcharts" % "gatling-charts-highcharts" % gatlingVersion % "test,it" +libraryDependencies += "io.gatling" % "gatling-test-framework" % gatlingVersion % "test,it" diff --git a/scala-gatling/project/build.properties b/scala-gatling/project/build.properties new file mode 100644 index 000000000..73df629ac --- /dev/null +++ b/scala-gatling/project/build.properties @@ -0,0 +1 @@ +sbt.version=1.10.7 diff --git a/scala-gatling/project/plugins.sbt b/scala-gatling/project/plugins.sbt new file mode 100644 index 000000000..e5a0f0f81 --- /dev/null +++ b/scala-gatling/project/plugins.sbt @@ -0,0 +1 @@ +addSbtPlugin("io.gatling" % "gatling-sbt" % "4.11.1") diff --git a/scala-gatling/src/test/scala/com/baeldung/gatling/ChainRequestsProvider.scala b/scala-gatling/src/test/scala/com/baeldung/gatling/ChainRequestsProvider.scala new file mode 100644 index 000000000..38c6195a7 --- /dev/null +++ b/scala-gatling/src/test/scala/com/baeldung/gatling/ChainRequestsProvider.scala @@ -0,0 +1,31 @@ +package com.baeldung.gatling + +import io.gatling.core.Predef._ +import io.gatling.core.structure.ChainBuilder +import io.gatling.http.Predef._ +import io.gatling.http.request.builder.HttpRequestBuilder + +object ChainRequestsProvider { + + def simpleRequest( + requestName: String, + requestPath: String, + expectedResponseStatus: Int + ): ChainBuilder = { + val request: HttpRequestBuilder = http(requestName) + .get(requestPath) + .check(status.is(expectedResponseStatus)) + .check(bodyString.optional.saveAs("sBodyString")) + + exec(session => session.markAsSucceeded) + .exec(request) + .doIf(_.isFailed) { + exec { session => + println("***Failure on [" + requestPath + "] endpoint:") + print("Gatling Session Data: ") + println(session.attributes.get("sBodyString")) + session + } + } + } +} diff --git a/scala-gatling/src/test/scala/com/baeldung/gatling/PeakLoadSimulation.scala b/scala-gatling/src/test/scala/com/baeldung/gatling/PeakLoadSimulation.scala new file mode 100644 index 000000000..506ba463e --- /dev/null +++ b/scala-gatling/src/test/scala/com/baeldung/gatling/PeakLoadSimulation.scala @@ -0,0 +1,31 @@ +package com.baeldung.gatling + +import io.gatling.core.Predef.{details, _} +import com.baeldung.gatling.ChainRequestsProvider.simpleRequest +import com.baeldung.gatling.ScenariosProvider.getScenario + +class PeakLoadSimulation extends Simulation { + + setUp( + getScenario( + "getExistingEndpoint", + simpleRequest("request_todo_endpoint", "/todo", 200), + 50, + 10, + 60 + ), + getScenario( + "nonExistingEndpoint", + simpleRequest("request_wrong_endpoint", "/not-todo", 200), + 5, + 10, + 60 + ) + ).assertions( + details("request_todo_endpoint").successfulRequests.percent.gt(99.99), + details("request_todo_endpoint").responseTime.percentile4.lt(20), + details("request_todo_endpoint").requestsPerSec.gt(40), + details("request_wrong_endpoint").successfulRequests.percent.lt(1), + details("request_wrong_endpoint").responseTime.percentile4.lt(20) + ) +} diff --git a/scala-gatling/src/test/scala/com/baeldung/gatling/ScenariosProvider.scala b/scala-gatling/src/test/scala/com/baeldung/gatling/ScenariosProvider.scala new file mode 100644 index 000000000..1423f178d --- /dev/null +++ b/scala-gatling/src/test/scala/com/baeldung/gatling/ScenariosProvider.scala @@ -0,0 +1,31 @@ +package com.baeldung.gatling + +import io.gatling.core.Predef._ +import io.gatling.core.structure.{ChainBuilder, PopulationBuilder} +import io.gatling.http.Predef.http + +import scala.language.postfixOps + +object ScenariosProvider { + + private val httpProtocol = + http.baseUrl("http://localhost:9000").disableCaching.disableFollowRedirect + + def getScenario( + scenarioName: String, + request: ChainBuilder, + tps: Double, + rampUpSeconds: Int, + durationSeconds: Int + ): PopulationBuilder = { + scenario(scenarioName) + .exec(request) + .inject( + rampUsersPerSec(0).to(tps).during(rampUpSeconds), + constantUsersPerSec(tps) + .during(durationSeconds - rampUpSeconds - rampUpSeconds), + rampUsersPerSec(tps).to(0).during(rampUpSeconds) + ) + .protocols(httpProtocol) + } +}