Forum Discussion
Regards,
Steve
This issue's been biting me on SOAP UI NG (in ReadyAPI 1.4.1) too. I've been trying to implement our version of HMAC authentication on REST requests. Our method takes the UID, the request method, the full request URI (including the path and query parts - context.requestURI), and the secret key and generates a map, including a hash and a timestamp for the request headers. The groovy script to generate the map can't be run for each header or else the hash and the timestamp may go out of sync between calls - it has to be run once then the values assigned to both headers. Now, on a SOAP UI REST request, the places to deploy a groovy script are limited (and I need to use the WsdlTestRunContext for the complete URI) and I've been trying to run it in the headers themselves, storing the timestamp value as a test case property, returning the hash as the script result, and then picking up the timestamp from the custom property.
The problem is that the order of the headers keeps changing, so if I calculate the hash and store the timestamp value as a test case property, I can't guarantee that the timestamp header will follow the hash header, and the timestamp will have been populated from a previous run's timestamp, resulting in authentication failure.
It's been driving me up the wall. I've spent 3 days trying to find away around the problem (with no success). I'm baffled as to why it's been designed this way - what possible use case could be satisfied by rearranging request headers (apparently at random) between one test run and another? And why can't the analyst set an order to the request headers themselves?
- gok10 years agoNew Contributor
I managed to figure it out - the epihany came when I fully internalised the fact that any HTTP request is just a bunch of text, and headers are just key/value text pairs delimited by a colon and a space and separated by newlines.
Create the first header you want (e.g. header1) and then create the remaining headers you want in a given order with a sprintf call in the new header's Value column, like so:
${=sprintf('%s\nheader2: %s\nheader3: %s\nheader4: %s', [${#TestCase#header1val}, ${#TestCase#header2val}, ${#TestCase#header3val}, ${#TestCase#header4}])}
Of course, you have to subvert the UI to do something this straightforward, which makes me think the UI hasn't been designed well at all.
- nmrao10 years agoCommunity Hero
Please look at the Map and List features of Java, and where order is not maintained. You will be able find the details on the net.
And in this case headers is Map, so you notice the same, and that is nothing to do with SoapUI, but Java. Another important thing is that, the application / server reads Map / List in the same manner, i.e., it could be even processed different manner than what is actually received.
If one understand the behaviour of certain object, then will be able to better handle such objects with ease.
Here is simple example : the (script) assertion on request and response headers. Also assumes that response contains only the headers passed in the request. Treating input header values as expected and header values received in the response as actual values.
Also note that if you have different values, you may alter the script as needed.
def headerKeys = messageExchange.requestHeaders.keySet() def result = true def message = new StringBuffer("Not matching headers information\n") headerKeys.each { def expectedValue = messageExchange.requestHeaders.get(it) def actualValue = messageExchange.responseHeaders.get(it) if (actualValue != expectedValue) { result = false message.append("Header : ${it}\nActual value: ${actualValue}\nExpected value: ${expectedValue}\n") } } if (!result) { throw new Error(message.toString()) }
Hope this helps.