Gatling session - get attribute as Long - scala

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])
}

Related

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 Framework 2.4 how to use return statement in Action controller

is there a way to return a value inside Action controller.
I have a method in my User model which returns the number of friends of a given user.
def nrOfFriends(current_user: Long): Int = {
DB.withConnection{ implicit connection =>
var nr: Int = SQL("select count(*) from friend where user_id_1=" + current_user + " or user_id_2=" + current_user).as(scalar[Int].single)
nr
}
}
In my controller, I just want to return the value from the model
def freunde() = IsAuthenticated { username => _ =>
User.findByUsername(username).map { user =>
var nr: Int = Friend.nrOfFriends(user.id.get)
Ok(""+nr)
}.getOrElse(Forbidden)
}
But in the way that is written, it will print "empty string " concatenated with the number
If I replace Ok(""+nr) with Ok(nr) I receive the following error:
"Cannot write an instance of Int to HTTP response. Try to define a Writeable[Int]"
I need for my action to return a value so that I can pass the value from the action to header.views.html inside the navbar something like that
#Freund.freunde Friends
if you want your response to just be the value of nr you can simply call nr.toString:
def freunde() = IsAuthenticated { username => _ =>
User.findByUsername(username).map { user =>
var nr: Int = Friend.nrOfFriends(user.id.get)
Ok(nr.toString)
}.getOrElse(Forbidden)
}
The error you're getting makes reference to the fact that Int doesn't have an implicit Writeable[Int] in scope. So play doesn't know how display an Int in an http response.
You can add make Int writeable by putting this in scope:
implicit val intWriteable = play.api.http.Writeable[Int](_.toString.getBytes, None)
Then you would be able to just say:
Ok(nr)
without error.
However, it sounds like you just want the result of nrOfFriends inside an unrelated template. If that's the case, you should be using an Action at all. Instead just call your model function inside the template where you need the data.
#User.nrOfFriends(user.id) Friends
Of course you would need to pass in the user to the template as well.
You didn't post a full sample of all the code involved in what you are trying to accomplish so I think this is the best I can do for now. Perhaps try posting the base template that your <a> is in.
An important point is that Actions are for production an HTTP response, and not just plain data internally to the application.
An action of a controller handles a request and generates a result to be sent to the client. In other words, an action returns a play.api.mvc.Result value, representing the HTTP response to send to the web client. In your example Ok constructs a 200 OK response. The body of the response must be one of the predefined types, including text/plain, json, and html. The number of a friends is an integer and is NOT an acceptable type of the body. Therefore, a simple way to address this problem is to convert it into a text/plain using .toString().
On the other hand, you can define a writer for Int that lets Play know how to convert an integer into a json format.
For more details, please take a look at this https://www.playframework.com/documentation/2.2.x/ScalaActions.

Gatling 2 dynamic queryParam on each request

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")))

Play 2.2 for Scala: is it possible to modify the session of an incoming request?

I'm trying to use action composition to add a fake user to Session.
def GuestAction(f: Request[AnyContent] => Result): Action[AnyContent] = {
Action { request =>
var myUser = searchUser(request.session)
if ( myUser == null ) {
myUser = newUser()
}
f(request).withSession("user" -> myUser)
}
}
In my controller there is
def action1 = GuestAction { implicit request =>
// My code
Ok()
}
def action2 = GuestAction { implicit request =>
val user = request.session.get("user").get
// My code
Ok()
}
When I open Chrome and browse to the route pointing to "action1" and then to the route pointing to "action2", everything works fine: I got a new user and it is attached to the session.
On the contrary, when I open Chrome and I browse to the route pointing to "action2" first, I got an error because my "request.session" is empty, and that's obvious: using .withSession() the session is attached to the Result, not to the incoming request.
So, in order to make this work, I need to attach the session key/value pairs to the incoming request - like it is possible in FakeRequest.withSession(), but there's no such method in Request.
What would you suggest in order to fix this issue?
You're very nearly there - but to get the maximum value from your Action composition, you should be able to make your "client" Actions totally unaware of the session - they really only care about the User object after all. You want to be able to write:
def action2 = GuestAction { implicit user => implicit request =>
// Do something with 'user', whether it's a guest or real
println(s"My user is $user")
Ok()
}
action2 doesn't care how the User was obtained, but it can rely on one being available. To make this happen, GuestAction needs to be something like this:
def GuestAction(f: (User) => Request[AnyContent] => Result): Action[AnyContent] = {
Action { request =>
var myUser = searchUser(request.session)
if ( myUser == null ) {
myUser = newUser()
}
f(myUser)(request)
}
}
The only remaining piece of the puzzle is putting a user into the session - which you can still do with a conventional response.withSession() as part of a successful login process.