From 8e02695a108ffd789be8985a47d54df31308bcc4 Mon Sep 17 00:00:00 2001 From: LQ63 Date: Tue, 5 May 2026 19:45:24 +0200 Subject: [PATCH] feat(Gatlin): Rework of test behaviour Added realistic user behaviour --- .../scala/scenarios/ChessUserScenario.scala | 61 +++++++++++++++++++ .../simulations/EnduranceTestSimulation.scala | 18 +++--- .../simulations/LoadTestSimulation.scala | 19 +++--- .../simulations/SmokeTestSimulation.scala | 10 ++- .../simulations/SpikeTestSimulation.scala | 24 +++++--- .../simulations/StressTestSimulation.scala | 26 ++++---- 6 files changed, 121 insertions(+), 37 deletions(-) create mode 100644 src/gatling/scala/scenarios/ChessUserScenario.scala diff --git a/src/gatling/scala/scenarios/ChessUserScenario.scala b/src/gatling/scala/scenarios/ChessUserScenario.scala new file mode 100644 index 0000000..c39fb24 --- /dev/null +++ b/src/gatling/scala/scenarios/ChessUserScenario.scala @@ -0,0 +1,61 @@ +package scenarios + +import io.gatling.core.Predef._ +import io.gatling.core.structure.ScenarioBuilder +import io.gatling.http.Predef._ + +import scala.concurrent.duration._ + +object ChessUserScenario { + + private def makeMove(uci: String) = + http(s"Move $uci") + .post(session => s"/api/board/game/${session("gameId").as[String]}/move/$uci") + .header("Authorization", "${jwt}") + .check(status.in(200, 201)) + + val play: ScenarioBuilder = scenario("Chess User Journey") + .exec(session => session.set("username", s"user_${System.currentTimeMillis()}_${session.userId}_${java.util.UUID.randomUUID().toString.take(8)}")) + .exec( + http("Register") + .post("/api/account") + .body(StringBody(session => + s"""{"username":"${session("username").as[String]}","email":"${session("username").as[String]}@test.com","password":"Password123!"}""" + )) + .check(status.is(200)) + ) + .exec( + http("Login") + .post("/api/account/login") + .body(StringBody(session => + s"""{"username":"${session("username").as[String]}","password":"Password123!"}""" + )) + .check(status.is(200)) + .check(jsonPath("$.token").saveAs("jwt")) + ) + .exec( + http("Import Game") + .post("/api/board/game/import/fen") + .header("Authorization", "${jwt}") + .body(StringBody(session => { + val username = session("username").as[String] + s"""{ + | "fen": "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", + | "white": {"id": "$username", "displayName": "$username"}, + | "black": {"id": "opponent_${session.userId}", "displayName": "Opponent"}, + | "timeControl": {"limitSeconds": 300, "incrementSeconds": 3} + |}""".stripMargin + })) + .check(status.in(200, 201)) + .check(jsonPath("$.gameId").saveAs("gameId")) + ) + .exec(makeMove("e2e4")) + .exec(makeMove("e7e5")) + .exec(makeMove("g1f3")) + .exec( + http("Resign") + .post(session => s"/api/board/game/${session("gameId").as[String]}/resign") + .header("Authorization", "${jwt}") + .check(status.in(200, 201, 204)) + ) +} diff --git a/src/gatling/scala/simulations/EnduranceTestSimulation.scala b/src/gatling/scala/simulations/EnduranceTestSimulation.scala index e3a4868..eaf0ef9 100644 --- a/src/gatling/scala/simulations/EnduranceTestSimulation.scala +++ b/src/gatling/scala/simulations/EnduranceTestSimulation.scala @@ -1,8 +1,9 @@ package simulations import base.BaseSimulation -import endpoints.BoardEndpoints +import scenarios.ChessUserScenario import io.gatling.core.Predef._ +import io.gatling.http.Predef._ import scala.concurrent.duration._ @@ -11,12 +12,15 @@ class EnduranceTestSimulation extends BaseSimulation { private val concurrentUsers = sys.props.getOrElse("concurrentUsers", "3").toInt private val duration = sys.props.getOrElse("duration", "300").toInt + override protected val httpProtocol = http + .baseUrl(baseUrl) + .header("Accept", "application/json") + .header("Content-Type", "application/json") + setUp( - BoardEndpoints.all.map { endpoint => - scenarioFromEndpoint(endpoint) - .inject( - constantConcurrentUsers(concurrentUsers).during(duration.seconds) - ) - }: _* + ChessUserScenario.play + .inject( + constantConcurrentUsers(concurrentUsers).during(duration.seconds) + ) ).protocols(httpProtocol) } diff --git a/src/gatling/scala/simulations/LoadTestSimulation.scala b/src/gatling/scala/simulations/LoadTestSimulation.scala index 3222b05..7c89859 100644 --- a/src/gatling/scala/simulations/LoadTestSimulation.scala +++ b/src/gatling/scala/simulations/LoadTestSimulation.scala @@ -1,20 +1,25 @@ package simulations import base.BaseSimulation -import endpoints.BoardEndpoints +import scenarios.ChessUserScenario import io.gatling.core.Predef._ +import io.gatling.http.Predef._ import scala.concurrent.duration._ class LoadTestSimulation extends BaseSimulation { - private val maxUsers = sys.props.getOrElse("maxUsers", "5").toInt - private val rampDuration = sys.props.getOrElse("rampDuration", "60").toInt + private val maxUsers = sys.props.getOrElse("maxUsers", "5").toInt + private val rampDuration = sys.props.getOrElse("rampDuration", "60").toInt + + // Each virtual user authenticates individually, so no global Bearer token + override protected val httpProtocol = http + .baseUrl(baseUrl) + .header("Accept", "application/json") + .header("Content-Type", "application/json") setUp( - BoardEndpoints.all.map { endpoint => - scenarioFromEndpoint(endpoint) - .inject(rampUsers(maxUsers).during(rampDuration.seconds)) - }: _* + ChessUserScenario.play + .inject(rampUsers(maxUsers).during(rampDuration.seconds)) ).protocols(httpProtocol) } diff --git a/src/gatling/scala/simulations/SmokeTestSimulation.scala b/src/gatling/scala/simulations/SmokeTestSimulation.scala index 730bb7b..d540551 100644 --- a/src/gatling/scala/simulations/SmokeTestSimulation.scala +++ b/src/gatling/scala/simulations/SmokeTestSimulation.scala @@ -1,13 +1,19 @@ package simulations import base.BaseSimulation -import endpoints.BoardEndpoints +import scenarios.ChessUserScenario import io.gatling.core.Predef._ +import io.gatling.http.Predef._ class SmokeTestSimulation extends BaseSimulation { + override protected val httpProtocol = http + .baseUrl(baseUrl) + .header("Accept", "application/json") + .header("Content-Type", "application/json") + setUp( - scenarioFromEndpoint(BoardEndpoints.createGame) + ChessUserScenario.play .inject(atOnceUsers(1)) ).protocols(httpProtocol) } diff --git a/src/gatling/scala/simulations/SpikeTestSimulation.scala b/src/gatling/scala/simulations/SpikeTestSimulation.scala index 0795c51..56b0aed 100644 --- a/src/gatling/scala/simulations/SpikeTestSimulation.scala +++ b/src/gatling/scala/simulations/SpikeTestSimulation.scala @@ -1,8 +1,9 @@ package simulations import base.BaseSimulation -import endpoints.BoardEndpoints +import scenarios.ChessUserScenario import io.gatling.core.Predef._ +import io.gatling.http.Predef._ import scala.concurrent.duration._ @@ -12,15 +13,18 @@ class SpikeTestSimulation extends BaseSimulation { private val baselineDuration = sys.props.getOrElse("baselineDuration", "20").toInt private val spikeUsers = sys.props.getOrElse("spikeUsers", "15").toInt + override protected val httpProtocol = http + .baseUrl(baseUrl) + .header("Accept", "application/json") + .header("Content-Type", "application/json") + setUp( - BoardEndpoints.all.map { endpoint => - scenarioFromEndpoint(endpoint) - .inject( - constantUsersPerSec(baselineUsers).during(baselineDuration.seconds), - atOnceUsers(spikeUsers), - nothingFor(5.seconds), - constantUsersPerSec(baselineUsers).during(baselineDuration.seconds) - ) - }: _* + ChessUserScenario.play + .inject( + constantUsersPerSec(baselineUsers).during(baselineDuration.seconds), + atOnceUsers(spikeUsers), + nothingFor(5.seconds), + constantUsersPerSec(baselineUsers).during(baselineDuration.seconds) + ) ).protocols(httpProtocol) } diff --git a/src/gatling/scala/simulations/StressTestSimulation.scala b/src/gatling/scala/simulations/StressTestSimulation.scala index 9f10adb..c0032ab 100644 --- a/src/gatling/scala/simulations/StressTestSimulation.scala +++ b/src/gatling/scala/simulations/StressTestSimulation.scala @@ -1,8 +1,9 @@ package simulations import base.BaseSimulation -import endpoints.BoardEndpoints +import scenarios.ChessUserScenario import io.gatling.core.Predef._ +import io.gatling.http.Predef._ import scala.concurrent.duration._ @@ -14,16 +15,19 @@ class StressTestSimulation extends BaseSimulation { private val stepDuration = sys.props.getOrElse("stepDuration", "30").toInt private val rampDuration = sys.props.getOrElse("rampDuration", "10").toInt + override protected val httpProtocol = http + .baseUrl(baseUrl) + .header("Accept", "application/json") + .header("Content-Type", "application/json") + setUp( - BoardEndpoints.all.map { endpoint => - scenarioFromEndpoint(endpoint) - .inject( - incrementConcurrentUsers(usersIncrement) - .times(steps) - .eachLevelLasting(stepDuration.seconds) - .separatedByRampsLasting(rampDuration.seconds) - .startingFrom(startUsers) - ) - }: _* + ChessUserScenario.play + .inject( + incrementConcurrentUsers(usersIncrement) + .times(steps) + .eachLevelLasting(stepDuration.seconds) + .separatedByRampsLasting(rampDuration.seconds) + .startingFrom(startUsers) + ) ).protocols(httpProtocol) }