Search code examples
javawiremockhandlebars.javawiremock-standalone

Wiremock templating fixedDelayMilliseconds


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 !


Solution

  • 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()
      }
    }