How to use return of one gatling request into another request - Scala - scala

In the following code, I am getting a token in the first Gatling request, saving it in a variable named auth. However, when I try to use it in the second request, it is sending empty string in place of auth variable. So for some reason, the auth string is not being updated till the time it is being used in the second request. Can anyone suggest any workaround so that I can use the value returned in one request into another request?
Code:
val headers_10 = Map("Content-Type" -> "application/x-www-form-urlencoded")
var a= "qwerty91#gmail.com"
var auth = ""
val scn = scenario("Scenario Name") // A scenario is a chain of requests and pauses
.exec(http("request_1") // Here's an example of a POST request
.post("/token")
.headers(headers_10)
.formParam("email", a)
.formParam("password", "password")
.transformResponse { case response if response.isReceived =>
new ResponseWrapper(response) {
val a = response.body.string
auth = "Basic " + Base64.getEncoder.encodeToString((a.substring(10,a.length - 2) + ":" + "junk").getBytes(StandardCharsets.UTF_8))
}
})
.pause(2)
.exec(http("request_2")
.get("/user")
.header("Authorization",auth)
.transformResponse { case response if response.isReceived =>
new ResponseWrapper(response) {
val a = response.body.string
}
})

You should store the value you need in the session. Something like this will work, although you'll have to tweak the regex and maybe some other details:
val headers_10 = Map("Content-Type" -> "application/x-www-form-urlencoded")
var a= "qwerty91#gmail.com"
var auth = ""
val scn = scenario("Scenario Name") // A scenario is a chain of requests and pauses
.exec(http("request_1") // Here's an example of a POST request
.post("/token")
.headers(headers_10)
.formParam("email", a)
.formParam("password", "password")
.check(regex("token: (\\d+)").find.saveAs("auth")))
.pause(2)
.exec(http("request_2")
.get("/user")
.header("Authorization", "${auth}"))
Here's the documentation on "checks", which you can use to capture values from a response:
http://gatling.io/docs/2.2.2/http/http_check.html
Here is the documentation on the gatling EL, which is the easiest way to use session variables (this is the "${auth}" syntax in the last line above):
http://gatling.io/docs/2.2.2/session/expression_el.html

Related

Kraken private API with F# returns EGeneral: invalid arguments

I am trying to access the Kraken private API using F#. The code to access the public API runs perfectly fine, but when i try to access the private API i am always getting the error "EGeneral:Invalid arguments".
#r "FSharp.Data.dll"
open FSharp.Data
open System
open System.Text
open System.Security.Cryptography
let baseUri = "https://api.kraken.com"
let key = MY_KRAKEN_API_KEY
let secret = MY_KRAKEN_API_SECRET
let path = "/0/private/Balance"
let nonce = DateTime.UtcNow.Ticks
let bodyText = "nonce=" + nonce.ToString()
let hmac (key : byte []) (data : byte[]) =
use hmac = new HMACSHA512(key)
hmac.ComputeHash(data)
let sha256 (data : string) =
use sha = SHA256Managed.Create()
sha.ComputeHash(Encoding.UTF8.GetBytes(data))
let createSignature (nonce : int64) body (path : string) secret =
let shaSum = nonce.ToString() + body |> sha256
let data = Array.append (Encoding.UTF8.GetBytes path) shaSum
let key = Convert.FromBase64String secret
hmac key data |> Convert.ToBase64String
let signature = createSignature nonce bodyText path secret
let response = Http.RequestString (
url = baseUri + path,
httpMethod = "POST",
headers = ([("API-Key", key); ("API-Sign", signature)] |> Seq.ofList),
body = TextRequest bodyText
)
Does anybody see what i am doing wrong?
EDIT:
The Kraken.com API documentation is awailable here: https://www.kraken.com/help/api
I suppose the header signature is incorrect. The docu requires the following two values to be submitted in the header:
API-Key = API key API-Sign = Message signature using HMAC-SHA512 of
(URI path + SHA256(nonce + POST data)) and base64 decoded secret API
key
EDIT 2:
The remaining parameters need to be transmitted with a POST method. In my case this is only the "nonce" value in the body part of the HTTP request.
I had the same error while I was writing a C# library for Kraken and I found a solution of this problem:
This error does not appears if the API key or the sign are wrong or missing. The problem is that you do not add a mediatype to your request. I do not know how it works in F# but look at this example:
using (var client = new HttpClient())
{
string address = String.Format("{0}/{1}/public/{2}", _url, _version, method);
// Does not work with this:
// var content = new StringContent(postData, Encoding.UTF8);
var content = new StringContent(postData, Encoding.UTF8, "application/x-www-form-urlencoded");
var response = await client.PostAsync(address, content);
return await response.Content.ReadAsStringAsync();
}
The "application/x-www-form-urlencoded" is the critical path. If you do not send a request with that, you get the "EGeneral: invalid arguments"-error. With it, everything works fine. At least in my case.

Return from function in body and not only in last line in REST API Scala and play

I develop Rest API with scala and play framework.
In my product controller, I do validation of parameters received.
In case they fail from some reason, I would like to response with BadRequest in the middle of the function and not in the last line as scala works..
In the code below - Code continues running to the Ok line.. which is wrong, I want to return !
def getProduct(lang: String, t: String, ids: String) = Action {
val productIdsList = ids.split(",").toList
if (productIdsList.length.equals(1) && productIdsList(0).equals("")) //Validate input params are product Ids and not empty !
{
var errorResponse:ErrorResponse[String] = ErrorResponse(ErrorCode.GeneralError, "No products IDs", 500)
BadRequest(Json.toJson(errorResponse))//maybe return BadRequest(Json.toJson(errorResponse) ??
}
val results = productService.getProducts(GetProductsRequest(lang,t,productIdsList));
Ok(Json.toJson(results))
// TODO: handle error
}
If implemented as:
return BadRequest(...)
It reply with error:
"method getProduct has return statement; needs result type"
I Understand this is bad practice, so what is the best practice for quitting the function without finishing it (and not throwing exceptions..)
Just put an else branch, so there's nowhere to continue:
def getProduct(lang: String, t: String, ids: String) = Action {
val productIdsList = ids.split(",").toList
if (productIdsList.length.equals(1) && productIdsList(0).equals("")){ //Validate input params are product Ids and not empty !
var errorResponse:ErrorResponse[String] = ErrorResponse(ErrorCode.GeneralError, "No products IDs", 500)
BadRequest(Json.toJson(errorResponse))//maybe return BadRequest(Json.toJson(errorResponse) ??
}else{
val results = productService.getProducts(GetProductsRequest(lang,t,productIdsList));
Ok(Json.toJson(results))
// TODO: handle error
}
}

Playframework WS API response processing

I use The Play WS API from PlayFramework to communicate with external API.
I need to process the received data, but don't know how. I get a response, and I want to pass it to other function like an JSON Object. How I can achieve that?
Code I use you can see below.
Thanks!
def getTasks = Action {
Async {
val promise = WS.url(getAppProperty("helpdesk.host")).withHeaders(
"Accept" -> "application/json",
"Authorization" -> "Basic bi5sdWJ5YW5vdjoyMDEzMDcwNDE0NDc=" ).get()
for {
response <- promise
} yield Ok((response.json \\ "Tasks"))
}
}
I get a response, and I want to pass it to other function like an JSON Object.
I'm not sure I understand your question, but I'm guessing you want to transform the json you receive from the WS call prior to returning to the client, and that this transformation could take several lines of code. If this is correct, then you just need to add curly brackets around your yield statement so you can do more work on the response:
def getTasks = Action {
Async {
val promise = WS.url(getAppProperty("helpdesk.host")).withHeaders(
"Accept" -> "application/json",
"Authorization" -> "Basic bi5sdWJ5YW5vdjoyMDEzMDcwNDE0NDc=" ).get()
for {
response <- promise
} yield {
// here you can have as many lines of code as you want,
// only the result of the last line is yielded
val transformed = someTransformation(response.json)
Ok(transformed)
}
}
}
I took a look at the doc, and you could try:
Async {
WS.url(getAppProperty("helpdesk.host")).withHeaders(
"Accept" -> "application/json",
"Authorization" -> "Basic bi5sdWJ5YW5vdjoyMDEzMDcwNDE0NDc=" ).get().map{
response => Ok(response.json \\ "Tasks")
}
}

Trying to define Scalatra webservice with JSON parameters

I am trying to define a webservice, using Scalatra, where the parameters are passed in in the body, preferably as JSON, not having everything on the url, as I have it now.
So, I would like this test to pass, but the commented out code is what passes currently. The non-commented code isn't JSON, but I also am not certain how I would pass JSON for testing, as put requires an Iterable in the second parameter.
class WebAppSpec extends MutableScalatraSpec {
addServlet(classOf[WebApp], "/*")
"PUT /phaseupdate" should {
"return status 200" in {
//put("/phaseupdate/test1/address1/starting/10") {
put("/phaseupdate", Map("filename" -> "test1", "entryaddress" -> "address1","name" -> "starting","percentcomplete" -> "10")) {
status must_== 200
}
}
}
My current definition, which is wrong, is:
put("/phaseupdate/:filename/:entryaddress/:name/:percentcomplete") {
val filename = params("filename")
val entryaddress = params("entryaddress")
val name = params("name")
val percentcomplete = params("percentcomplete")
So how do I define my put service to just call it with PUT /phaseupdate and have the parameters in the body?
I am trying to limit what is going into the webserver access log, basically.
The solution is to do this:
put("/phaseupdate") {
val filename = if (params("filename").indexOf('.') > -1) params("filename").substring(0, params("filename").indexOf('.')) else params("filename")
val entryaddress = params("entryaddress")
val name = params("name")
val percentcomplete = params("percentcomplete")
Basically, params() can read in what was passed.
The specs2 test is, and if this is followed by the get it returns the correct information.
"PUT /phaseupdate" should {
"return status 200" in {
put("/phaseupdate", Map("filename" -> "test1", "entryaddress" -> "address1", "name" -> "starting", "percentcomplete" -> "10")) {
status must_== 200
}
}
}

Databinder dispatch: Get uncompressed content of a 403 response

I am using databinder dispatch for making HTTP requests which works nicely, as long as the web server returns a 404.
If the request fails, the web server returns a 403 status code and provides a detailed error message in the response body as XML.
How to read the xml body (regardless of the 403), e.g. how can I make dispatch ignore all 403 errors?
My code looks like this:
class HttpApiService(val apiAccount:ApiAccount) extends ApiService {
val http = new Http
override def baseUrl() = "http://ws.audioscrobbler.com/2.0"
def service(call:Call) : Response = {
val http = new Http
var req = url(baseUrl())
var params = call.getParameterMap(apiAccount)
var response: NodeSeq = Text("")
var request: Request = constructRequest(call, req, params)
// Here a StatusCode exception is thrown.
// Cannot use StatusCode case matching because of GZIP compression
http(request <> {response = _})
//returns the parsed xml response as NodeSeq
Response(response)
}
private def constructRequest(call: Call, req: Request, params: Map[String, String]): Request = {
val request: Request = call match {
case authCall: AuthenticatedCall =>
if (authCall.isWriteRequest) req <<< params else req <<? params
case _ => req <<? params
}
//Enable gzip compression
request.gzip
}
}
I believe something like this works:
val response: Either[String, xml.Elem] =
try {
Right(http(request <> { r => r }))
} catch {
case dispatch.StatusCode(403, contents) =>
Left(contents)
}
The error will be in Left. The success will be in Right. The error is a String that should contain the XML response you desire.
If you need more, I believe you can look at HttpExecutor.x, which should give you full control. It's been a while since I've used dispatch, though.
Also, I'd suggest using more val's and less var's.