How to start gatling scenario with feeder - gatling

I have simple scenario that tests single endpoint. I have problems with DSL. Can't figure out how to start scenario with feeder. I have to make useless call first in order to make it compile.
class GetDataSimulation extends Simulation {
val httpProtocol = http
.baseUrl("http://localhost:8080") // Here is the root for all relative URLs
.header("Content-Type", "application/json")
.header("Accept", "application/json")
object GetData {
val feeder = csv("data.csv").shuffle.circular
val getData = exec(
http("Home")
.get("/")
) // first call .get("/") is useless. I've added it only to make it compile
.pause(1.millisecond)
.feed(feeder) // start feeder, want to start scenario from here.
.exec(
http("GetData") // interpolate params using CSV feeder.
.get("/api/v1/data?firstParam=${firstParam}&secondParam=${secondParam}")
)
.pause(1)
}
setUp(
constantUsers.inject(constantUsersPerSec(3).during(60.seconds))
).protocols(httpProtocol)
}
how can I get rid of
exec(
http("Home")
.get("/")
) // first call .get("/") is useless. I've added it only to make it compile

feed is available as a top level function, similar to exec itself:
val getData = feed(feeder)
.exec(
http("GetData") // interpolate params using CSV feeder.
.get("/api/v1/data?firstParam=${firstParam}&secondParam=${secondParam}")
)
.pause(1)
You can see it in the Feeders documentation.

Related

scala - Gatling - I can't seem to use Session Variables stored from a request in a subsequent Request

The code:
package simulations
import io.gatling.core.Predef._
import io.gatling.http.Predef._
class StarWarsBasicExample extends Simulation
{
// 1 Http Conf
val httpConf = http.baseUrl("https://swapi.dev/api/films/")
// 2 Scenario Definition
val scn = scenario("Star Wars API")
.exec(http("Get Number")
.get("4")
.check(jsonPath("$.episode_id")
.saveAs("episodeId"))
)
.exec(session => {
val movie = session("episodeId").as[String]
session.set("episode",movie)
}).pause(4)
.exec(http("$episode")
.get("$episode"))
// 3 Load Scenario
setUp(
scn.inject(atOnceUsers(1)))
.protocols(httpConf)
}
Trying to grab a variable from the first Get request, and inject that variable into a second request, but unable to do so despite using the documentation. There might be something I'm not understanding.
When I use breakpoints, and navigate through the process, it appears the session execution happens AFTER both of the other requests have been completed (by which time is too late). Can't seem to make that session execution happen between the two requests.
Already answered on Gatling's community mailing list.
"$episode" is not correct Gatling Expression Language syntax. "${episode}" is correct.

How to feed an answer back into a request in Gatling

I'm working in Scala with Gatling.
I need to follow a redirection found in a HTML page, sent as a response for my first request (so the automatic redirection following of Gatling doesn't do the trick).
Right now my solution looks a bit like this:
private def scn: ScenarioBuilder = {
scenario("KLS test tool")
.repeat(nb_req) {
feed(feeder)
.exec {
http("request").
httpRequest("GET", "${url}")
.check(bodyString.saveAs("body"))
}
.exec {
session => {
val responseBody = session.attributes("body").toString
val redirect = findRedirectUrlIn(responseBody)
redirect match {
case Some(url) =>
java.lang.System.setProperty("redirect_url", url)
case None =>java.lang.System.setProperty("redirect_url", "")
}
}
}
.exec {
val redirect = java.lang.System.getProperty("redirect_url")
val url = "/redirect?url=" + redirect
http("redirect").
httpRequest("GET", url)
}
}
}
However, the second exec (which is supposed to scan the HTML page to find the URL to redirect to) is being run after the third exec (which is supposed to actually visit the URL), so the getProperty gives me "null"
How could I force Gatling to run the execs in the right order?
I have similar task, but did in another way... What if disable redirects?
Just add disableFollowRedirect to your HttpProtocolBuilder:
val protocol = http
.baseUrl(...)
.disableFollowRedirect
Then I made request which redirected and save to redirect_url
val getUrl: HttpRequestBuilder = http("getShortUrl")
.get("${shortUrl}")
.check(
status.is(302),
header("Location").saveAs("redirect_url")
)
What you're doing is wrong.
First, System properties are non thread safe and global. You need a user scope, which is the Session.
Then, in your 3rd exec, your code is executed when the Simulation is instantiated as it's not in a function like the 2nd one.
.exec { session =>
val redirect = findRedirectUrlIn(session("body").as[String])
session.set("redirect_url", redirect.getOrElse(""))
}
.exec(http("redirect").get("${redirect_url}"))

Issue sending FormData to Rails API with strong parameters

I want to create a character, with a name and an avatar. Here is my code :
CharacterApi.js, in which I make my network call
function addCharacter(name, avatar) {
const data = new FormData();
data.append(‘name’, name);
data.append(‘avatar’, avatar);
return authenticatedFetch({
path: '/teams/characters’,
method: 'post',
data
});
}
characters_controller.rb
def create
#character = #character.new(character_params)
if #character.save
render :show
else
render json: #character.errors, status: :unprocessable_entity
end
end
[. . .]
private
def character_params
params.fetch(:character, {}).permit(:name, :avatar)
end
Which, when I make my create request, gives me a 422: unprocessable entity error. However, debugs showed me that the right parameters are actually sent, and doing the following makes everything working fine again :
def create
#character = #characters.new
#character.name = params[:name]
#character.avatar = params[:avatar]
[. . .]
end
Even though this second method works, it is not very practical to me, since I’d like to add a few more params in the future.
If I send the params as simple JSON, I can’t get any file (always gives me a null value), but the first method works, this time :
With this I can’t send images or any files, but the initial rails syntax works again
function addCharacter(name, avatar) {
return authenticatedFetch({
path: '/teams/characters’,
method: 'post',
data: {name, avatar}
});
}
Is there a reason why the short syntax #character.new(character_params) isn’t working when I send FormData?
I use carrier wave to handle files in rails API. Thanks in advance for any help!
You are using Strong Parameters the wrong way.
It must be:
def character_params
params.require(:character).permit(:name, :avatar)
end

End Gatling simulation when scenario fails BUT generate a report

I have code which currently will not run my scenario if it fails;
//Defined outside of the scenario scope
var simulationHealthy = true
//defined within the scenario
.exec((session: io.gatling.core.session.Session) => {
if (session.status == KO) {
simulationHealthy = false
}
session
})
However my simulation keeps running until the duration set for the simulation is over, though the scenario will not keep executing.
What I would like to do is to have a scenario fail under conditions I define (similar to assertions) and for the entire simulation to fail at that point as well, and also generate a report.
Thanks
Edit: I am running these tests within the IntelliJ IDE. Ending the simulation programmatically is required.
You might run the test itself without report and produce the report with a second call for just the report generation from the simulation.log
Run Simulation w/o report (-nr flag), i.e.
gatling.sh -nr -s YourSimulationClass
Generate Report (-ro flag):
gatling.sh -ro yoursimulation
(your simultation is the path underneath the results folder, which can be specified with -rf, which contains the simulation.log file)
In IntelliJ you can define another LaunchConfiguration to be executed before. So you define an action for executing Gatling Test (with -nr flag) and another configuration for report generation (with -ro flag), that executes the Gatling Test run action before.
Alternatively you could use the gatling-maven-plugin and define two executions (run, report) with the same flags.
Edit
According to this group thread you could execute your steps conditionally or mute them. The condition could be the presence of an error, but anything else as well. If the condition depends on global state i.e. a global variable, it would mute all users (unlike exitHereIfFailed)
For example:
val continue = new AtomicBoolean(true)
val scn = scenario("MyTest")
.exec(
doIf(session => continue.get) {
exec(http("request_0").get("/home").check(status.is(200)))
.exec((session: io.gatling.core.session.Session) => {
if (session.status == KO) {
continue.set(false)
}
session
})
})
As said, this only stops sending requests to the SUT. Seems there is no other option at the moment (apart from System.exit(0))
You can use exitHereIfFailed in ScenarioBuilder returned by exec().
.exec(http("login")
.post("/serviceapp/api/auth/login")
...
.check(status.is(200))))
.exitHereIfFailed
.pause(1)
.exec(http("getProfileDetails")
.get("/serviceapp/api/user/get_profile")
.headers(authHeader("${token}"))
.check(status.is(200)))
Thanks to #GeraldMücke 's suggestion of using system.exit I've come up with a work around. Still no where close to ideal but it does the job.
The problems are
Still have to manually generate the report from the log that is created when gatling is run
The user has to constantly manage how long the scenario lasts for both items as I don't know a way to have a scenario last the length of a simulation
This is obviously a "proof of concept" it has nothing in the code to define failure over thresholds etc like the asserts and checks available in Gatling itself
Here's the code. I've nested simulations within the setUp function because it fits the criteria of the work I am doing currently, allowing me to run multiple simulations within the main simulation.
FailOverSimulation and ScenarioFailOver are the classes that need to be added to the list; obviously this only adds value when you are running something that loops within the setUp.
import java.util.concurrent.atomic.AtomicBoolean
import io.gatling.commons.stats.KO
import io.gatling.core.Predef._
import io.gatling.core.scenario.Simulation
import io.gatling.http.Predef._
import scala.concurrent.duration._
object ScenarioTest {
val get = scenario("Test Scenario")
.exec(http("Test Scenario")
.get("https://.co.uk/")
)
.exec((session: io.gatling.core.session.Session) => {
if(session.status == KO) {
ScenarioFailOver.exitFlag.set(true)
}
session
})
}
object TestSimulation {
val fullScenario = List(
ScenarioTest.get.inject(constantUsersPerSec(1).during(10.seconds))
)
}
object ScenarioFailOver {
var exitFlag = new AtomicBoolean(false)
val get = scenario("Fail Over")
.doIf(session => exitFlag.get()) {
exec(s => {
java.lang.System.exit(0)
s
})
}
}
object FailOverSimulation {
val fullScenario = List(
ScenarioFailOver.get.inject(constantUsersPerSec(1).during(10.seconds))
)
}
class SimulateTestEnding extends Simulation {
setUp(
FailOverSimulation.fullScenario
::: TestSimulation.fullScenario
).protocols(
)
}

Gatling switch protocols during scenario

I'm trying to create a Gatling scenario which requires switching the protocol to a different host during the test. The user journey is
https://example.com/page1
https://example.com/page2
https://accounts.example.com/signin
https://example.com/page3
so as part of a single scenario, I need to ether switch the protocol defined in the scenario set up, or switch the baseUrl defined on the protocol but I can't figure out how to do that.
A basic scenario might look like
package protocolexample
import io.gatling.core.Predef._
import io.gatling.http.Predef._
class Example extends Simulation {
val exampleHttp = http.baseURL("https://example.com/")
val exampleAccountsHttp = http.baseURL("https://accounts.example.com/")
val scn = scenario("Signin")
.exec(
http("Page 1").get("/page1")
)
.exec(
http("Page 2").get("/page2")
)
.exec(
// This needs to be done against accounts.example.com
http("Signin").get("/signin")
)
.exec(
// Back to example.com
http("Page 3").get("/page3")
)
setUp(
scn.inject(
atOnceUsers(3)
).protocols(exampleHttp)
)
}
I just need to figure out how to ether switch the host or protocol for the 3rd step. I know I can create multiple scenarios but this needs to be a single user flow across multiple hosts.
I've tried directly using the other protocol
exec(
// This needs to be done against accounts.example.com
exampleAccountsHttp("Signin").get("/signin")
)
which results in
protocolexample/example.scala:19: type mismatch;
found : String("Signin")
required: io.gatling.core.session.Session
exampleAccountsHttp("Signin").get("/signin")
and also changing the base URL on the request
exec(
// This needs to be done against accounts.example.com
http("Signin").baseUrl("https://accounts.example.com/").get("/signin")
)
which results in
protocolexample/example.scala:19: value baseUrl is not a member of io.gatling.http.request.builder.Http
You can use an absolute URI (inclusive protocol) as a parameter for Http.get, Http.post and so on.
class Example extends Simulation {
val exampleHttp = http.baseURL("https://example.com/")
val scn = scenario("Signin")
.exec(http("Page 1").get("/page1"))
.exec(http("Page 2").get("/page2"))
.exec(http("Signin").get("https://accounts.example.com/signin"))
.exec(http("Page 3").get("/page3"))
setUp(scn.inject(atOnceUsers(3))
.protocols(exampleHttp))
}
see: https://gatling.io/docs/current/cheat-sheet/#http-protocol-urls-baseUrl
baseURL: Sets the base URL of all relative URLs of the scenario on which the configuration is applied.
I am currently working in gatling.
SOLUTION:
=> WHAT WE USE IF WE HAVE ONE HTTPBASE:
var httpConf1= http.baseUrl("https://s1.com")
=>FOR MULTIPLE HTTPBASE:
var httpConf1=http.**baseUrls**("https://s1.com","https://s2.com","https://s3.com")
You can use baseUrls function which takes a list of httpBase urls.
ANOTHER METHOD:
Reading from csv file all httpbase and storing it in list buffer in scala language and then converting it into list while passing it in http.baseUrls
var listOfTenants:ListBuffer[String] = new ListBuffer[String] //buffer
var httpConf1=http.**baseUrls**(listOfTenants.toList) //converting buffer to list.
Hope it helps!.
Thank you.😊

Resources