Gatling 2 dynamic queryParam on each request - scala

I am trying to run a load test using Gatling 2. I need to generate one of the query parameters dynamically on each request.
My scenario is defined like this:
val scn = scenario("Load Test Scenario")
.exec(
http("Test API")
.post(url)
.body(StringBody("Some XML"))
.queryParam("x", DigestUtils.md5Hex(generateX().getBytes("UTF-8")))
)
def generateX() : String = {
// generate random string and return
}
This only calls generateX once and uses the result in each request. Is there anyway to have the generateX call on every request?

You have to pass a function, not a value. See Gatling documentation about Expression.
Here, you can just discard the session input parameter as you don't use it, so you can simply write:
.queryParam("x", _ => DigestUtils.md5Hex(generateX().getBytes("UTF-8")))

Related

Gatling session - get attribute as Long

I am a new in Scala and got some problems with casting from String to Long. I try to get Gatling session value as Long in request. Before in exec() part, I try to set the userId value
def setUserId(): ChainBuilder = {
exec(session => session
.set("userId", Random.nextLong())
)
}
Next, in request creator I want to use it like that because I need a new userId every call:
object UserRequestCreator {
def sampleUserRequest(currency: String): Request = {
Data data = new Data()
data.setUserId("${userId}".toLong)
data.setCurrency(currency)
}
}
Test scenario:
exec(setUserId())
.exec(http("postUser")
.post(endpointUser).asXml
.headers(headers)
.body(StringBody(toXmlString(sampleUserRequest("EUR"), classOf[Request])))
.check(status.is(200))
but receive error:
java.lang.NumberFormatException: For input string: "${userId}"
How to fix that in Scala?
I also try Long.valueOf, JLong.parseLong("${userId"}, 16), Try(BigDecimal(...)) and more but nothing can help. I think the problem is with $ symbol, but I don't see any different way to get this value from the session. Maybe it is possible to store Long in the Gating session?
From the documentation and based on your current code, one way to do it is like that:
// with a function payload
http("name").post("/")
.body(StringBody(session => s"""{ "foo": "${session("dynamicValueKey").as[String]}" }"""))
Thus, in your case:
StringBody(session => toXmlString(sampleUserRequest(session)("EUR"), classOf[Request])
def sampleUserRequest(session: Session)(currency: String): Request = {
//...
data.setUserId(session("userId").as[Long])
}

Gatling pass feeder as a parameter to object

I have a Gatling script with few objects that I use for my tests. One of the objects is used to authenticate users and users are passed to test using a feeder. The feeder is now defined on top in the beginning of the simulation class like this:
val feeder = csv("users.csv").circular
The feeder provides pairs of usernames and passwords. The object looks like:
object Auth {
val login = {
feed(feeder)
.exec(http("get_auth_token")
.post("/get_auth_token")
.body(StringBody("""{
"username": "${username}",
"password": "${password}"
}""")).asJSON
// this check extracts accessToken from JSON received in response
.check(
status.find.in(200,304,201,202,203,204,205,206,207,208,209),
jsonPath("$.response_body.access.token").saveAs("accessToken"),
jsonPath("$.response_body.refresh.token").saveAs("refreshToken")
)
).exitHereIfFailed
}
val refreshAuthToken = {
exec(http("refresh_auth_token")
.post("/refresh_auth_token")
.header("Authorization", "Bearer ${refreshToken}")
.check(
status.find.in(200,304,201,202,203,204,205,206,207,208,209),
jsonPath("$.response_body.access.token").saveAs("accessToken")
)
).exitHereIfFailed
}
}
Then I have a scenario that looks like:
val myScenario = scenario("My test")
.exec(Auth.login)
// Do some stuff here
.exec(Auth.refreshAuthToken)
// Do more stuff here
Then I have a setup that runs this single scenario.
What I would like to have is additional scenario that will run alongside with the get additional scenario that will run alongside with myScenario. This scenario will also perform Auth.login, but I want it to use a different set of users - so I need to have two separate feeders that will be passed to Auth.login from scenario. Can someone suggest how this can be achieved?

How to read query parameters in akka-http?

I know akka-http libraries marshal and unmarshal to class type while processing request.But now, I need to read request-parameters of GET request. I tried parameter() method and It is returning ParamDefAux type but i need those values as strings types
I check for answer at below questions.
How can I parse out get request parameters in spray-routing?
Query parameters for GET requests using Akka HTTP (formally known as Spray)
but can't do what i need.
Please tell me how can i extract query parameters from request. OR How can I extract required value from ParamDefAux
Request URL
http://host:port/path?key=authType&value=Basic345
Get method definition
val propName = parameter("key")
val propValue = parameter("value")
complete(persistanceMgr.deleteSetting(propName,propValue))
My method declarations
def deleteSetting(name:String,value:String): Future[String] = Future{
code...
}
For a request like http://host:port/path?key=authType&value=Basic345 try
path("path") {
get {
parameters('key.as[String], 'value.as[String]) { (key, value) =>
complete {
someFunction(key,value)
}
}
}
}
Even though being less explicit in the code, you can also extract all the query parameters at once from the context. You can use as follows:
// Previous part of the Akka HTTP routes ...
extract(_.request.uri.query()) { params =>
complete {
someFunction(key,value)
}
}
If you wish extract query parameters as one piece
extract(ctx => ctx.request.uri.queryString(charset = Charset.defaultCharset)) { queryParams =>
//useyourMethod()
}

Gatling httpRequest with dynamic method from collection

I want to build a Gatling scenario from a collection of structured data (StructuredDataCollection).
My problem is, that I'm unable to pass in the "method" (as in HTTP method) from an element from the collection into the http call of the actual test.
Here's a code snippet.
def testScenario(duration: Int) = scenario("SO").during(duration) {
exec {
session => {
val test = StructuredDataCollection.next()
val title = test.title
val method = test.method // Not being used, because it does not work like that :(
val endpoint = test.endpoint
val requiredParameters = test.requiredParameters
val code = test.code
session
.set("title", title)
.set("methodFUG", method).set("endpoint", endpoint)
.set("requiredParameters", requiredParameters)
.set("code", code)
}
}
.exec(
http("${title}")
.httpRequest("get", "${endpoint}") // TODO: method can't be passed in as an expression.
.queryParamMap("${requiredParameters}")
.check(status.is("${code}"))
)
}
As you can see, I've hard-coded "get", but I'll need that to be replaced with the actual value from the method property from the current selected item from the collection.
Unfortunately, Gatling's DSL isn't available in all the places where you'd expect it to be, and it's just reading that as a string.
It took me some time to realize, that
http("${title}").httpRequest("${methodFUG}", "${endpoint}") will actually make a HTTP call with the invalid method "${methodFUG}" and not the value from the collection element, which could be "GET", "POST", "PUT", "DELETE", and so on.
httpRequest signature is (method: String, url: Expression[String]), see documentation.
It cannot take an Expression, only a static String.

Play WS API Making nested requests - WSClient

I want to make two HTTP requests(POST) using play2 WSRequest where some information from the first response is send to the second request. I tried to do this in following manner to make sure second request is only triggers after the first one is completed. But I get Type mismatch: cannot convert from F.Promise to F.Promise error
public Promise<Result> executeAPI(String apiName,JsonNode requestBody){
WSRequest pcLoginRequest = ws.url("http://xxxxx.qa.local:8080/mytest/rest/login");
pcLoginRequest.setContentType("application/json");
pcLoginRequest.setHeader("X-x-Password", "xxxxx")
.setHeader("X-x-Username", "xxxxx")
.setHeader("X-x-Content-Type", "application/json");
Promise<Result> myPromise = pcLoginRequest.post("").map(response -> {
ProApiSession.getInstanceOf().setProToeken(response.asJson().get("token").asText());
WSRequest pcrequest = ws.url("http://xxxxx.qa.local:8080/mytest/rest/api/" + apiName);
pcrequest.setContentType("application/json");
pcrequest.setHeader("X-x-Token",ProApiSession.getInstanceOf().getProToeken() )
.setBody(requestBody)
.setHeader("X-x-Content-Type", "application/json");
Promise<Result> myPromise2 = pcLoginRequest.post(requestBody).map(response2 -> {
return Results.ok(response2.asJson());
});
return myPromise;
});
Can someone please suggest how to do nested request using WSRequest in play. (import play.libs.ws.* )
Java 8 type inference errors are bad at the best of times. Since the result of the lambda you're passing to the first map is Promise<Result>, what you're trying to assign to myPromise is Promise<Promise<Result>>. What you actually want to do is replace the map call with flatMap, which is so named because is "flattens" the nested promise to just be a single promise.