feat: NCS-73 Refine Gatlin tests to reflect ordinary user behaviour #7

Merged
Janis merged 1 commits from feat/NCS-73 into main 2026-05-05 19:51:13 +02:00
6 changed files with 121 additions and 37 deletions
Showing only changes of commit 8e02695a10 - Show all commits
@@ -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))
)
}
@@ -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)
}
@@ -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)
}
@@ -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)
}
@@ -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)
}
@@ -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)
}