I need to send specific parameters to a scenario that is being reused multiple times with different payloads depending on the workflows. The following is the code that is to be reused:
var reqName = ""
var payloadName = ""
lazy val sendInfo: ScenarioBuilder = scenario("Send info")
.exec(session => {
reqName = session("localReqName").as[String]
payloadName = session("localPayloadName").as[String]
session}
)
.exec(jms(s"$reqName")
.send
.queue(simQueue)
.textMessage(ElFileBody(s"$payloadName.json"))
)
.exec(session => {
val filePath = s"$payloadName"
val body = new String(Files.readAllBytes(Paths.get(ClassLoader.getSystemResource(filePath).toURI)))
logger.info("timestamp value: " + session("timestamp").as[String])
logger.debug("Template body:\n " + body)
session
})
I know that you can chain scenarios in Scala/Gatling but how can I pass in information like reqName and payloadName down the chain, where reqName is a parameter to indicate the name of the request where the info is being sent and payloadName is the name of the actual JSON payload for the related request:
lazy val randomInfoSend: ScenarioBuilder = scenario("Send random info payloads")
.feed(csv("IDfile.csv").circular)
.randomSwitch(
(randomInfoType1prob) -> exec(
feed(timeFeeder)
.exec(session => {
payloadName = "Info1payload.json"
reqName ="Info1Send"
session.set("localReqName", "Info1Send")
session.set("localPayloadName", "Info1payload.json")
session
})
.exec(sendInfo)
),
(100.0 - randomInfoType1prob) -> exec(
feed(timeFeeder)
.exec(session => {
payloadName = "Info2Payload.json"
reqName ="Info2Send"
session.set("localReqName", "Info2Send")
session.set("localPayloadName", "Info2Payload.json")
session
})
.exec(sendInfo)
)
I attempted the above but the values of that 2 specific parameters were not passed through correctly. (The IDs and timestamps were fed through correctly though) Any suggestions?
Please properly read the Session API documentation. Session is immutable so Session#set returns a new instance.
Related
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'm trying to use gatling and I have a problem.
1- I have one scenario that exec POST request for getting a list of tokens and save all tokens in csv
2- I create another scenario that exec GET request but I need a token for auth each request
My problem is before executing my first scenario my file doesn't exist and I have this following error:
Could not locate feeder file: Resource user-files/resources/token.csv not found
My code :
Scenario 1 :
val auth_app = scenario("App authentication")
.exec(http("App Authentication")
.post("/token")
.header("Content-Type", "application/x-www-form-urlencoded")
.formParamSeq(Seq(("grant_type", "password"), ("client_id", clientID), ("client_secret", clientSecret)))
.check(jsonPath("$.token").saveAs("token")))
.exec(session => {
val token_data = new File(token_file_path)
if(token_data.exists()){
val writer = new PrintWriter(new FileOutputStream(new File(token_file_path), true))
writer.write(session("access_token").as[String].trim)
writer.write("\n")
writer.close()
}
else {
val writer = new PrintWriter(new FileOutputStream(new File(token_file_path), true))
writer.println("AccessToken")
writer.write(session("access_token").as[String].trim)
writer.write("\n")
writer.close()
}
session
})
Scenario 2 :
val load_catalog = scenario("Load catalog")
.exec(http("Load catalog")
.get("/list")
.headers(Map("Content-Type" -> "application/json", "Authorization Bearer" -> "${AccessToken}")))
.feed(csv(token_file_path).random)
My setup :
setUp(
auth_app.inject(atOnceUsers(10)).protocols(httpProtocol),
load_catalog.inject(nothingFor(120 seconds), atOnceUsers(10)).protocols(httpProtocol)
)
Is it possible to have a dynamic feeder with gatling ?
Edit the Web socket header response sent from server to client.
I am creating a websocket server application using playframework. Right now the websocket response from the server is
taken care by Play. Following is the response header,
Request Header:
(UpgradeToWebSocket,),
(Host,localhost:8083),
(Connection,Upgrade),
(Upgrade,websocket),
(Sec-WebSocket-Version,13),
(Accept-Encoding,gzip, deflate, br),
(Accept-Language,en-US,en;q=0.9),
(Sec-WebSocket-Key,ZvfzpVo3EX4DFA4BRcgRIA==)
def chatSystem(): WebSocket = WebSocket.acceptOrResult[String, String] { request =>
Future.successful{
AuthenticationService.doBasicAuthentication(request.headers) match {
case Results.Ok => Right(ActorFlow.actorRef { out => ChatServiceActor.props(out) })
case _ => Left(Unauthorized)
}
}
}
I want to validate Sec-WebSocket-Protocol if it is present in the request header or add the same with value in the server response if it is not present.
I used the following code:
// Defined at http://tools.ietf.org/html/rfc6455#section-4.2.2
val MagicGuid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
def websocketAcceptForKey(key: String): String = {
val sha1 = MessageDigest.getInstance("sha1")
val salted = key + MagicGuid
val hash = sha1.digest(salted.asciiBytes)
val acceptKey: String = Base64.rfc2045().encodeToString(hash, false)
acceptKey
}
Use it like the following:
val wsKey: Optional[HttpHeader] = request.getHeader("Sec-WebSocket-Key")
val wsAccept = if (wsKey.isPresent) Some(RawHeader("Sec-WebSocket-Accept", websocketAcceptForKey(wsKey.get.value()))) else None
I am new to Scala/Spray/AKKA so please excuse this dumb requests.
I have the following Directive and it is being called as the first
logger line ("inside") is showing up in logs.
However, anything inside mapRequest{} is skipped over. The logging line ("headers:") isn't showing up
private def directiveToGetHeaders(input: String) : Directive0 = {
logger.info("inside")
mapRequest { request =>
val headList: List[HttpHeader] = request.headers
logger.info("headers: " + headList.size)
request
}
}
I am not sure what I did wrong. My goal is to pull out all the HTTP headers. Any tip/pointer much appreciated. Thanks
-v
You can use extractRequest directive for getting headers.
private def directiveToGetHeaders(input: String) : Directive0 = {
logger.info("inside")
extractRequest { request =>
val headList: Seq[HttpHeader] = request.headers
logger.info("headers: " + headList.size)
complete(HttpResponse())
}
}