Wanting to extract some request variables, hash, insert into header

Using Gatling 2.0.0-M3a

I have to set a header value to an encryption hash based on the uri, method, datetime, any body.

I can get this all to work if I do it all manually, i.e. call the hashing function with the values I am going to use.

However if there a way from my Get/PostHttpRequestBuilder to do a header(“hash”,somefunc), with somefunc
getting the above uri, method, body and passing it to the hashing function?

i.e. I don’t want to have to have to repeat myself, but easily set the hash value based on what is already in the request

Thanks.

Nope

I suspected as much.

What if AbstractHttpRequestBuilder had a getAttributes:HttpAttributes method?

Its a case class, immutable. Just would be useful to do some post-processing on a builder as described above.

Thanks.

Dno.

What for? AbstractHttpRequestBuilder.httpAttributes is public.

Really?

val getOrderDetails=http(“GetOrderDetails”)
.get(url)

println (getOrderDetails.httpAttributes)

won’t compile.

Ah, you’re right.

Anyway, you can manually create a RequestBuilder, the constructors are public.

I’m not sure how that helps me.

I build up a request, the url uses an orderid from a feed, so will be different with each request, and I have to send a hash header value based on that dynamic url, else the receiving url won’t accept my request.

Dino.

Linked to this, might be a solution, just wondering.

I feed in some values thus:

val orderIds = ((1 to 1000) map (x=>Map(“oid”->x)) toArray).circular


.feed(orderIds)

So I have a 1000 repeating “oid” values.

Now, its easy to simply insert that value into a header like this:

.header(“oid”,"${oid}")

However, is there a good way I could call some custom function based on that ${oid} ?

e.g.

.header(“oid”,“myfunc(${oid})”)

Thanks.

Ah, OK!

You have to understand how Gatling works with EL and Expressions.

Most DSL methods take Expression[T] parameters. Expression is a type alias for (Session) => Validation[T], meaning a function that takes a Session input and return a Validation (something that can either be a Success containing the value or a Failure containing the error message).

Then, how is it you can pass Strings to methods taking Expression[String] parameters?
There’s a implicit conversion that happens if you pass a String to a method expecting an Expression[String]! It parses the String and resolve whatever ${} EL it might contains.

So, the point is, as the documentation states, that you can explicitly pass an Expression[String].
If you do so, you can’t use EL there, as the implicit conversion doesn’t happen.
So if you want to use Session attributes, you have to do it programatically.

.header(“oid”, session => session(“oid”).validate[String].map(myfunc))

where myfunc if a def that takes a String and returns a String.

Get it?

Thanks, that made is very clear.

Should be able to do some good things with that functionality now. I understand that in using 2.x I’m rather on the bleeding edge.

You might want to add the above to the 2.,x wiki page for others.

Dino.

Ok, progress:

def url:Expression[String]={

(“oid”).validate[String].map("/myurl//"+)
}

later on:

.get(url)

However I also have another Expression[String] function that uses that url

def expectedHmac:Expression[String]={
session=>

hmacgen.generateHmac(
url(session).toString. // how do I get the Validation to turn to a string? It comes back as Success(/theurl). I want the url
“GET”, x_date,
“”).getHmac()
}

How do I turn the Validation into a string?

     def url:Expression[String]={
      _("oid").validate[String].map("/myurl//"+_)
    }

If I may, that's a matter of style, but I personally find the first _
unreadable. Matter of taste maybe.

later on:

.get(url)

However I also have another Expression[String] function that uses that url

def expectedHmac:Expression[String]={
      session=>

        hmacgen.generateHmac(
url(session).toString. // how do I get the Validation to turn to a string?
It comes back as Success(/theurl). I want the url
"GET", x_date,
"").getHmac()
    }

That's the other way around: you first get a Validation of your url, then
map its content:

def expectedHmac:Expression[String]= { session => url(session).map(url =>
hmacgen.generateHmac(url, "GET", x_date).getHmac) }

Ok, thought as much, that just struck me as a bit odd, having to do a map just to get the value.

Would be nice to have a method to get the content. A get/getOrElse in the Option style?

If I have to get several values from a bag of session attributes then it gets a bit abstruse.

BTW, first url could be even shorter

def url:Expression[String]=(“oid”).map("/myurl/"+)

Ha!

Anyway, got my stuff working this way:

def urlString:(Session=>String)={
“/myurl/orderid_”+_(“oid”).as[Integer]
}

def url:Expression[String]=urlString(_)

def expectedHmac:Expression[String]={
session=>

hmacgen.generateHmac(
urlString(session),
“GET”, x_date,
“”).getHmac()
}

then

.get(url)

.header(“Authorization”,expectedHmac)

Thanks so much for all your help.

Dino.

Ok, thought as much, that just struck me as a bit odd, having to do a map
just to get the value.

That's because you still think imperative style and not functional. With
map, You didn't just "get the value", you converted a Validation of the url
into a Validation of hmac without having to think about the Validation
being a Success or a Failure and got the potential error message
automatically conveyed for you.

Would be nice to have a method to get the content. A get/getOrElse in the
Option style?

get is a big No way! It's just a dangerous stuff that might produce a NPE,
being there for imperative developers.
getOrElse is a no too, as you'd lose the potential error message if the
Validation is a Failure. You can pattern match on Success and Failure if
you want.

You have to realize that Validation potentially contains more information
than just the success object.

If I have to get several values from a bag of session attributes then it
gets a bit abstruse.

Nope, that's actually very neat:
for {
  a <- session("a").validation[A]
  b <- session("b").validation[B]
  c <- session("c").validation[C]
} yield doSomething(a, b, c)

BTW, first url could be even shorter

def url:Expression[String]=_("oid").map("/myurl/"+_)

Shorter doesn't mean more readable, coding is no character typing race :wink:

Ha!

Anyway, got my stuff working this way:

    def urlString:(Session=>String)={
      "/myurl/orderid_"+_("oid").as[Integer]
    }

def url:Expression[String]=urlString(_)

     def expectedHmac:Expression[String]={
      session=>

        hmacgen.generateHmac(
urlString(session),
"GET", x_date,
"").getHmac()
    }

then

.get(url)
.header("Authorization",expectedHmac)

Well, as[Integer] might throw exceptions (for example, if oid is missing
for whatever reason), which would harm performance.

You're used to imperative style, and starting this way is fine, but I
advice at some point you try to wrap your mind around functional style and
use validate instead of as.

Ok, more idiomatic:

def url:Expression[String]={
sess=>
sess(“oid”).validate[Int].map("/myurl/orderid_"+_)
}

def expectedHmac:Expression[String]={
sess=>
url(sess).map(hmacgen.generateHmac(_,“GET”, x_date,"").getHmac())
}

Much better IMHO :slight_smile:
Just make them val instead of def so you don’t create a new function instance every time and you’ll be good.

Doh!

Dino.