Wiremock templating fixedDelayMilliseconds

10.5k Views Asked by At

I am trying to generated a response in wiremock, after a delay, where that delay is derived from the incoming request. e.g the family-name of the user in the request is "delay_10000" then delay by 10000 milliseconds, or delay_20000 then delay by 20000.....

{
  "request": {
    "method": "POST",
    "headers": {
      "SOAPAction": {
        "matches": "http://redacted"
      }
    },
    "bodyPatterns": [
      {
        "matchesXPath": {
          "expression": "//*[local-name()=\"family-name\"]/text()",
          "matches": "^delay_([0-9]+)$"
        }
      }
    ]
  },
  "response": {
    "status": 200,
    "bodyFileName": "verify.xml",
    "fixedDelayMilliseconds": "{{soapXPath request.body 'number(substring-after(//*[local-name()=\"family-name\"]/text(), \"delay_\"))'}}"
  }
}

Can anyone confirm whether which fields are able to be templated. The doco suggests "response headers and bodies", and elsewhere bodyFileName (which i have working) but it says nothing about whether or not other response fields can be templated.

Presently i'm seeing

 
2020-09-22 02:43:24.441 Verbose logging enabled
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Exception in thread "main" com.github.tomakehurst.wiremock.standalone.MappingFileException: Error loading file /home/wiremock/./mappings/equifax_generic_verify_identity_delay.json:
Cannot deserialize value of type `java.lang.Integer` from String "{{soapXPath request.body 'number(substring-after(//*[local-name()="family-name"]/text(), "timeout_"))'}}": not a valid Integer value
    at com.github.tomakehurst.wiremock.standalone.JsonFileMappingsSource.loadMappingsInto(JsonFileMappingsSource.java:121)
    at com.github.tomakehurst.wiremock.core.WireMockApp.loadMappingsUsing(WireMockApp.java:204)
    at com.github.tomakehurst.wiremock.core.WireMockApp.loadDefaultMappings(WireMockApp.java:200)
    at com.github.tomakehurst.wiremock.core.WireMockApp.<init>(WireMockApp.java:103)
    at com.github.tomakehurst.wiremock.WireMockServer.<init>(WireMockServer.java:73)
    at com.github.tomakehurst.wiremock.standalone.WireMockServerRunner.run(WireMockServerRunner.java:65)
    at com.github.tomakehurst.wiremock.standalone.WireMockServerRunner.main(WireMockServerRunner.java:134)
stream closed           

Firstly I can see where that is being caught, but not clearly where it's thrown https://github.com/tomakehurst/wiremock/blob/master/src/main/java/com/github/tomakehurst/wiremock/standalone/JsonFileMappingsSource.java#L121

Secondly, it's unclear to me whether i'm just driving wiremock wrong, and this is NOT possible via a response transformer, but is possible via an extension and a "Response definition transformation" (http://wiremock.org/docs/extending-wiremock/)

I can work around this with a set of fixed delays - but it would be nicer if it were dynamic

Help appreciated !

2

There are 2 best solutions below

0
On BEST ANSWER

I had a similar issue and I created a response definition extension which takes it from the header when provided.


class InjectDelayFromHeader : ResponseDefinitionTransformer() {
  override fun getName() = "InjectDelayFromHeader"

  override fun transform(
    request: Request,
    response: ResponseDefinition,
    files: FileSource, 
    parameters: Parameters
  ): ResponseDefinition {
    val delay = request.getHeader("X-WIREMOCK-DELAY")
    if (delay.isNullOrBlank()) {
      return response
    }
    return ResponseDefinitionBuilder.like(response).withFixedDelay(Integer.valueOf(delay)).build()
  }
}
0
On

So my initial assumption is that this isn't possible, since any use of the templates will resolve to a string, but fixedDelayMilliseconds wants a number, so WireMock will throw errors :(

I think you could extend WireMock with a custom transformer that would parse the delay in the response body and add it as a number in the response. For more information, check out the Extending WireMock documentation. Edit: I see now that you already arrived at this assumption. I think you're right :D -- this is most easily possible through a transformer.