Doing performance testing of API using Gatling.
Scenario:
Login (authToken will be generated in header)
For GET, POST, PUT request, need to pass that generated authToken in header
Here's my code snippet:
package apitest
import scala.concurrent.duration.*
import io.gatling.core.Predef.*
import io.gatling.http.Predef.*
import io.gatling.jdbc.Predef.*
import scala.language.postfixOps
class TestEnv4trial extends Simulation {
var e1: String = "https://testenv1-dev.net"
var e2: String = "https://testenv2-dev.net"
var BaseUrl: String = e1
var pwd: String = "pass123"
// Users
var admin: String = "admin123"
val httpProtocol = http
.baseUrl(BaseUrl)
.inferHtmlResources()
val login_headers = Map(
"Accept" -> """*/*""",
"Connection" -> "keep-alive",
"Content-Type" -> "application/x-www-form-urlencoded;charset=UTF-8"
)
val scn1 = scenario("Admin Login")
.exec(http("Login Admin")
.post({BaseUrl} + "/api/user/login")
.formParam("username", admin123)
.formParam("password", pass123)
.check(jsonPath("$.authToken").saveAs("tokenId")))
.exec { session => println(session("tokenId").as[String]); session } //authToken getting printed
val common_headers = Map(
"Accept" -> """*/*""",
"Accept-Encoding" -> "gzip, deflate, br",
"Accept-Language" -> "en-GB,en;q=0.9,en-US;q=0.8",
"Authorization" -> "Bearer " + $tokenId, //With hardcoded authToken works. Need to pass generated authToken in prev scenario here.
"Connection" -> "keep-alive",
)
val scn2 = scenario("All Employees")
.exec(http("All Employees")
.post("/api/employee/lists/")
.headers(common_headers)
.body(RawFileBody("test/TestEnv4trial/employees_request.json")).asJson)
setUp(
scn1.inject(atOnceUsers(1)).protocols(httpProtocol),
scn2.inject(atOnceUsers(1)).protocols(httpProtocol))
}
When I hardcode authToken generated in scn1 in common_headers, scn2 works.
But when I use tokenId, its not able to identify tokenId.
How do I pass saved key tokenId in common_headers?
Thanks.
"Authorization" -> "Bearer " + $tokenId
This doesn't compile.
Currently, you're using Session attributes, meaning tokenId is scoped for the single user executing scn1.
There's no way for a user executing scn2 to be able to reach it as is.
Related
I am using Gatling for performance testing, so I want know that how we extract token id from the login request here is code
val scn = scenario("Navigation")
.exec(http("request_6")
.post("/WEBAUTO03/aurora/login/security_check")
.headers(headers_6)
.formParam("j_username", "TONY")
.formParam("j_password", "1234")
.formParam("doLogin", "")
Above request provide token and I need apply the token in following request
val headers_9 = Map(
"Content-type" -> "text/plain",
"Origin" -> "https://resource.com",
"X-XSRF-TOKEN" -> ""4c81ed9c-e509-4830-b724-62e489c918e2"") -----here i need to replace token
.exec(http("request_9")
.post("/WEBAUTO03/aurora/JSON-RPC")
.headers(headers_9)
.body(RawFileBody("webview/navigation/0009_request.txt")))
anyone have any idea
Without seeing the response from the "above request" we cannot suggest the exact steps, approximate would be something like:
http("request_6")
.post("/WEBAUTO03/aurora/login/security_check")
.check(css("input[name='csrf_token']", "value").saveAs("Correlation1"))
val headers_9 = Map(
"Content-type" -> "text/plain",
"Origin" -> "https://resource.com",
"X-CSRF-Token" -> "${Correlation1}")
More information:
Gatling HTTP Checks
How to Run a Simple Load Test with Gatling
im new to Gatling and have been trying to setup a test where my users login, get an access token, then perform some simple get requests using that token. Having 1-2 users works fine, however once i start ramping up the users i start getting spammed with this error:
[ERROR] i.g.h.a.HttpRequestAction - 'httpRequest-2' failed to execute: No attribute named 'access_token' is defined
Im thinking it could have something to do with the way I am saving and using the access token ?
class GatlingTest extends Simulation {
val httpProtocol = http
.baseUrl("https://myurl.com/api/v1")
.inferHtmlResources(BlackList(""".*\.js""", """.*\.css""", """.*\.gif""", """.*\.jpeg""", """.*\.jpg""", """.*\.ico""", """.*\.woff""", """.*\.woff2""", """.*\.(t|o)tf""", """.*\.png""", """.*detectportal\.firefox\.com.*"""), WhiteList())
.acceptLanguageHeader("en-GB,en;q=0.5")
.upgradeInsecureRequestsHeader("1")
object GetUserData {
val userData = exec(http("Get_User_Data")
.get("/user")
.header("Authorization", "Bearer ${access_token}"))
.pause(1)
}
object GetUserInfo {
val userInfo = exec(http("Get_User_Info")
.get("/userInfo")
.header("Authorization", "Bearer ${access_token}")
.header("Accept", "application/json"))
.pause(1)
}
object Login {
val sentHeaders = Map("api_key" -> "nnxzv336wt2374h6zw5x24qd", "Content-Type" -> "application/x-www-form-urlencoded", "Accept" -> "application/json")
val login = exec(http("Login_User")
.post("/login")
.basicAuth("username", "password")
.headers(sentHeaders)
.body(StringBody("grant_type=password&username=username#username.local&password=12345"))
.check(jsonPath("$.access_token").saveAs("access_token"))
)
}
val user = scenario("User").exec(Login.login).exec(GetUserData.userData, GetUserInfo.userInfo)
setUp(
user.inject(
rampUsers(5).during(2.seconds),
).protocols(httpProtocol)
)
}
I have added Authorization Bearer to the get requests, like i mentioned it does work, but as soon as 3+ users are involved i get the error.
It means the login request failed and hence, the user wasn't able to capture the access_token there.
I am working on performance test, for that I have below Gatling script -
val getUserById: ChainBuilder = feed(userEmailFeeder).exec(http("User By Id")
.get("url")
.headers(getHeaders)
.check(status is 200)
)
private val getHeaders = Map.apply(
"Content-Type" -> "application/json",
"Accept" -> "application/json",
"token" -> {tokenValue}
)
object BearerToken {
//Generating token here
}
In userEmailFeeder I have user emails and passwords. I have to generate a token for every email present in feeder and add to header in getHeader.
Can someone guide me how I can pass same email & associated password to BearerToken for which getUserById is referring from feeder so it will genearte token and add into header?
You can create method which will get your email and password from session, generate token and then write this values to session.
val generateTokenByEmailAndPassword: Expression[Session] = (session: Session) => {
val email = session("email").as[String]
val password = session("password").as[String]
// your logic for generate token
val token = email + password
session.set("tokenValue", token)
}
And then add to scenarion
...
.feed(userEmailFeeder)
.exec(generateTokenByEmailAndPassword)
.exec(http("User By Id")
...
A little remark - for get session value need add $
Wrong: {tokenValue}
Right way: ${tokenValue}
I have to write some tests with Gatling / Scala. In my concrete case I have to login to a website with username and password (additionally there is also keycloak security). There is a CSV file with a lot of user/password lines and my goal is to login with every single user/password out of this CSV file.
The problem is I do not know how to do that. I am able to login with username/password and the security token of the keycloak with just one user. That's fine so far, but not enough. Here is what I have done so far.
The first class:
class LasttestBestand extends Simulation {
val context = Context.ladeContext("de", "integ")
val userCredentials = TestdatenImport.ladeTestDaten("de")
val httpProtocol = http
.baseUrl(s"${context.protocol}://${context.host}")
.inferHtmlResources(
BlackList(""".*\.css""", """.*\.js""", """.*\.ico""", """.*\.woff"""),
WhiteList()
)
.acceptHeader("application/json, text/plain, */*")
.acceptEncodingHeader("gzip, deflate")
.acceptLanguageHeader("de,en-US;q=0.7,en;q=0.3")
.disableFollowRedirect
.userAgentHeader(
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:63.0) Gecko/20100101 Firefox/63.0"
)
val scn = scenario("Lasttest Bestand")
.feed(userCredentials.csvFeeder)
.exec(Login.holeAccessToken("${Benutzername}", "${Passwort}", context))
.exec(Suche.ladeKundensucheResourcen(context))
setUp(
scn.inject(
atOnceUsers(1)
)
).protocols(httpProtocol)
}
The feeder class:
class TestdatenImport(val csvFeeder: BatchableFeederBuilder[String]) {}
object TestdatenImport {
def ladeTestDaten(land: String) = {
val csvFeeder = csv(s"data/eca-bb3-${land}-testdaten.csv").circular
new TestdatenImport(
csvFeeder
)
}
}
The Login:
object Login {
def holeAccessToken(
benutzer: String,
passwort: String,
context: Context
): ChainBuilder = {
val keycloakUri = s"${context.protocol}://${context.keycloakHost}"
val redirectUri =
s"${context.protocol}%3A%2F%2F${context.host}%2Fapp%2F%3Fredirect_fragment%3D%252Fsuche"
exec(
http("Login Page")
.get(
s"$keycloakUri/auth/realms/${context.realm}/protocol/openid-connect/auth"
)
.queryParam("client_id", "bestand-js")
.queryParam("redirect_uri", redirectUri)
.queryParam("state", UUID.randomUUID().toString())
.queryParam("nonce", UUID.randomUUID().toString())
.queryParam("response_mode", "fragment")
.queryParam("response_type", "code")
.queryParam("scope", "openid")
.header(
"Accept",
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
)
.header("Upgrade-Insecure-Requests", "1")
.check(status.is(200))
.check(
css("#kc-form-login")
.ofType[Node]
.transform(variable => {
variable.getAttribute("action")
})
.saveAs("loginUrl")
)
).exec(
http("Login")
.post("${loginUrl}")
.formParam("username", benutzer)
.formParam("password", passwort)
.header(
"Accept",
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
)
.header("Upgrade-Insecure-Requests", "1")
.check(status.is(302))
.check(
header("Location")
.transform(url => {
url.substring(url.indexOf("code=") + 5, url.length())
})
.saveAs("code")
)
.check(header("Location").saveAs("nextPage"))
)
.exec(
http("Fetch Token")
.post(
s"$keycloakUri/auth/realms/${context.realm}/protocol/openid-connect/token"
)
.header("Accept", "*/*")
.header("Origin", s"${context.protocol}://${context.host}")
.formParam("code", "${code}")
.formParam("grant_type", "authorization_code")
.formParam("client_id", "bestand-js")
.formParam("redirect_uri", redirectUri)
.check(status.is(200))
.check(
jsonPath("$..access_token")
.saveAs("accessToken")
)
)
}
}
As you can see I added a feeder to the scenario, but I do not know how to "repeat" the login the number of times there are user/password lines in the CSV file. What do I do wrong?
Inject as many users as you have entries in your CSV file, eg:
scn.inject(
rampUsers(numberOfEntries) during(10 minutes)
)
I have this code for gatling where i wish to pass auth_token to soap request body.
Soap request body is written in a txt file and that txt file is called in ElFilebody
All i need is to send access_token which is generated in saveAs("access_token") to be sent to ElFileBody("Soap_request_CancelEvent.txt")
Content of Soap_request_CancelEvent.txt is below
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns="http://www.example.com/Service/2013-03">
<soapenv:Header/>
<soapenv:Body>
<ns:CancelEvent>
<!--Optional:-->
<ns:request>
<ns:AuthToken>${access_token}</ns:AuthToken>
<ns:SanctionNumber>?</ns:SanctionNumber>
</ns:request>
</ns:CancelEvent>
</soapenv:Body>
</soapenv:Envelope>
Error in Gatling console is
Session(Test Cancel Event Soap Request,23,Map(caee65d1-d380-48e9-8566-
9d8efb16b5fa -> 0, 6014555f-5487-44bc-9384-864dece96fe0 ->
5),1557435685640,-125,KO,List(ExitOnCompleteLoopBlock(6014555f-5487-44bc-
9384-864dece96fe0), ExitOnCompleteLoopBlock(caee65d1-d380-48e9-8566-
6b5fa)),io.gatling.core.protocol.ProtocolComponentsRegistry$$Lambda$37
2/1791589252#2be8b240)
14:01:30.520 [ERROR] i.g.h.a.s.HttpRequestAction - 'httpRequest-17' failed
to execute: No attribute named 'access_token' is defined
Code is below
package simulations
import scala.io.Source
class ERBSJson extends BaseSimulation {
val httpProtocol = http
.baseURL("http://services.online.local:4059/Business/")
val uri03 = "https://api.platform.com"
)
val header_cancel = Map(
"POST" -> "http://services.online.local:4059/Business/ HTTP/1.1",
"Accept-Encoding" -> "gzip,deflate",
"Content-Type" -> "text/xml;charset=UTF-8",
"SOAPAction" -> "http://www.example.org/Service/2013-
03/IEventReporterEndpoint/CancelEvent",
"Content-Length" -> "429",
"Host" -> "r20services.onlinegaming.local:4059",
"Connection" -> "Keep-Alive",
"User-Agent" -> "Apache-HttpClient/4.1.1 (java 1.5)"
)
val headers_10 = Map("Content-Type" -> "application/json","Authorization"
-> "${token_type} + ${access_token}" )
val source: String = Source.fromFile("C:/Gatling2/resources/data/input-
ERBS.json").getLines.mkString
def userCount: Int = JsonPath.parse(source).read("$.[0].user")
def testDuration: Int = JsonPath.parse(source).read("$.[0].testDuration")
def rampDuration: Int = JsonPath.parse(source).read("$.[0].rampDuration")
before {
println(s"Running test with ${userCount} users")
println(s"Ramping users over ${rampDuration} seconds")
println(s"Total Test duration: ${testDuration} seconds")
}
def CancelEvent()={
repeat(990000000){
exec(flushHttpCache)
exec(flushHttpCache)
.exec(http("Cancel Event")
.post("EventReporterV2")
.headers(header_cancel)
.body(ElFileBody("Soap_request_CancelEvent.txt"))
.check(status.in(200,201)))//checkforaspecificstatus
.exec{session=>println(session);session}//parameterfortheorgIdgoeshere
.pause(1)
}
}
val scenario1 = scenario("Test Cancel Event Soap Request ")
.exec(http("Event-Reservations-Web-Image-Login")
.get("https://api.origin.cloud/dev/event-reservations-
/loading.dfbfd678.svg")
.headers(headers_1)
.resources(http("Http Header Token Authentication Url")
.options(uri03 + "/auth/oauth/token")
.headers(headers_7),
http("Token Generation Url For Post")
.post(uri03 + "/auth/oauth/token")
.headers(headers_8)
.formParam("grant_type", "password")
.formParam("username", "zyz#abc.com")
.formParam("password", "fJC2RuVmHB")
.basicAuth("ikrwugh3883gh","NbnEEqmDLSfno315o87ghFGYr3jybtzbi76sr")
.check(jsonPath("$.access_token").exists.saveAs("access_token"))
.check(jsonPath("$.token_type").exists.saveAs("token_type"))
))
.forever() { // add in the forever() method - users now loop forever
exec(CancelEvent())
}
setUp(
scenario1.inject(
nothingFor(5 seconds),
rampUsers(userCount) over ( rampDuration ))
.protocols(httpProtocol))
.maxDuration(testDuration)
}
can you try with removing the '.exists' command? It's not necessary if you're saving anyway