skip to content

Injected Latency

Making a stand-in answer slowly on purpose: a fixed pause, a random distribution, a delay applied to every response, and a body dripped out slowly enough to trip a read timeout.

on this pageshow

explore

questions

4

In WireMock, how do withFixedDelay(), withUniformRandomDelay() and withLogNormalRandomDelay() differ?

level: middleimportance: should knowfreq 64%

answer

  1. three ways to make a stub slow
  2. one number, two bounds, or a curve
  3. uniform draws flat between lower and upper
  4. log-normal takes a median and a sigma
  5. bigger sigma means a longer slow tail

basics

~20 s

WireMock's withFixedDelay holds every matching reply for the same number of milliseconds. WireMock's withUniformRandomDelay samples each pause evenly between a lower and upper bound. WireMock's withLogNormalRandomDelay samples around a median, where a bigger sigma lengthens the slow tail.

solid answer

~40 s

All three are WireMock response-side delays declared on the same `ResponseDefinitionBuilder`, and all three hold the whole reply — status line, headers and body — back before a single byte is written. WireMock's `withFixedDelay(Integer)` takes one millisecond figure and applies it identically on every call, which is what you want when a test asserts a boundary. WireMock's `withUniformRandomDelay(int lower, int upper)` draws a fresh sample from a flat distribution between the two bounds each time the stub answers. WireMock's `withLogNormalRandomDelay(double median, double sigma)` draws from a log-normal curve, where `median` is the 50th percentile in milliseconds and a larger `sigma` lengthens the right-hand tail of slow responses. In MockServer the same idea is reached through `withDelay(`, which takes a `Delay` from factories such as `Delay.milliseconds(`, `Delay.uniform(`, `Delay.logNormal(` and `Delay.gaussian(`.

code

java · 20 lines
java
import static com.github.tomakehurst.wiremock.client.WireMock.*;

stubFor(get(urlPathEqualTo("/fitting/patients/AB-4471/audiogram"))
    .willReturn(aResponse()
        .withStatus(200)
        .withHeader("Content-Type", "application/json")
        .withBody("{\"patientId\":\"AB-4471\",\"earSide\":\"left\"}")
        .withFixedDelay(3000)));

stubFor(get(urlPathEqualTo("/fitting/devices/HX-9002/telemetry"))
    .willReturn(aResponse()
        .withStatus(200)
        .withBodyFile("telemetry.json")
        .withUniformRandomDelay(200, 1200)));

stubFor(post(urlPathEqualTo("/fitting/sessions"))
    .willReturn(aResponse()
        .withStatus(202)
        .withBody("{\"fittingStatus\":\"PENDING\"}")
        .withLogNormalRandomDelay(400, 1)));

go deeper

for a junior

Know that a WireMock stub can be made slow on purpose, and that the delay is attached to the response builder inside willReturn, not to the request matcher. Be able to name WireMock's withFixedDelay.

for a middle

Be ready to explain all three WireMock methods and their parameters: one figure for fixed, a lower and an upper bound for uniform, a median and a sigma for log-normal. Say what a single sample looks like in each case.

for a senior

Show that you know a WireMock delay is spent as a sleep on the request thread unless the server runs with --async-response-enabled, and that only bounds, never exact times, are safely assertable against a random delay.

for a principal

Own the question of which shape a suite standardises on. Argue when a long-tailed WireMock log-normal delay earns its flakiness budget, and when a fixed delay or a truncated ceiling is the more honest instrument.

A stub server answers from a canned definition, so it replies as fast as the process can write bytes — often in single-digit milliseconds. That is faster than any real dependency will ever be, and it quietly hides every branch a client has for waiting: progress indicators, cancellation, deadlines, back-pressure. WireMock's delay methods exist to put the slowness back on purpose, and there are three sampling shapes to choose between. ## Where a WireMock delay is declared Every delay discussed here belongs to WireMock's `ResponseDefinitionBuilder` — the object `aResponse()` returns and `willReturn(` consumes. It is a property of the **reply**, not of the matcher: a WireMock delay changes *when* a stub answers, never *which* stub is selected. Because it is part of the response definition it serialises into the stub mapping alongside the status and body, so a delay written with WireMock's `withFixedDelay(` appears in the committed mapping file as `fixedDelayMilliseconds`, and the two random forms appear as a `delayDistribution` object. ## The three methods, side by side | Product | Method | Parameters | What one call gets | |---|---|---|---| | WireMock | `withFixedDelay(Integer)` | one figure, milliseconds | the same pause every time | | WireMock | `withUniformRandomDelay(int, int)` | lower and upper bound | an even draw between the bounds | | WireMock | `withLogNormalRandomDelay(double, double)` | median and sigma | a skewed draw with a long tail | - WireMock's `withFixedDelay(3000)` is the deterministic instrument: every request that stub answers waits the same three seconds, which is exactly what a test asserting a boundary needs. - WireMock's `withUniformRandomDelay(200, 1200)` samples afresh on every call from a flat distribution, so any value between the bounds is equally likely and nothing outside them ever happens. - WireMock's `withLogNormalRandomDelay(400, 1)` samples from a log-normal curve whose `median` argument is the 50th percentile in milliseconds, while `sigma` is the standard deviation of the underlying normal distribution. - A larger `sigma` in WireMock's `withLogNormalRandomDelay(` produces a longer right-hand tail — most calls land near the median and a few land far above it, which is the shape real service latency actually has. - WireMock's three-argument `withLogNormalRandomDelay(double median, double sigma, Double maxValue)` truncates that tail by resampling anything above `maxValue`, so a long-tailed stub cannot occasionally stall a whole suite. WireMock rejects a `maxValue` below the median outright. - Both random forms are convenience wrappers: WireMock's `withRandomDelay(DelayDistribution)` is the underlying method, and the uniform and log-normal helpers simply construct the distribution for you. ## What all three have in common WireMock applies a response delay *before* it writes anything at all. Under WireMock's `withFixedDelay(3000)` the client does not receive an early status line and then stall; it sees nothing whatsoever on the socket for three seconds, and then the entire reply — status, headers and body — arrives together. That is deliberately different from WireMock's `withChunkedDribbleDelay(`, which is slow *while transferring* rather than slow *before answering*, and it is why that method is a separate property rather than a fourth distribution. The wait itself is not free. By default WireMock spends it as a sleep on the thread handling the request, so a stub server holding many delayed responses at once can exhaust its container threads long before the delay figures themselves look large. Starting WireMock with `--async-response-enabled` (or building the server with `wireMockConfig().asynchronousResponseEnabled(true)`) moves the waiting onto a scheduled executor instead, which is what makes generous delays affordable under concurrency. ## Choosing one for a hearing-aid fitting stub set 1. Reach for WireMock's `withFixedDelay(` when the test asserts something about a specific duration — that the fitting screen still shows its progress indicator, or that the client gives up precisely where you expect it to. 2. Reach for WireMock's `withUniformRandomDelay(` when you want ordinary jitter with a hard ceiling, for instance a `GET /fitting/devices/{deviceSerial}/telemetry` stub that should never answer instantly but should never be pathological either. 3. Reach for WireMock's `withLogNormalRandomDelay(` when the point is that most calls are quick and a few are not — the shape that finds the code path nobody exercised — usually with the third `maxValue` argument set so the tail stays bounded. ## Mistakes worth naming - Treating WireMock's `withUniformRandomDelay(` and `withLogNormalRandomDelay(` as interchangeable. Uniform has hard bounds and no tail; log-normal has a median and an unbounded tail unless you truncate it. - Reading `sigma` in WireMock's `withLogNormalRandomDelay(` as a maximum. It is a spread parameter; the maximum is the optional third argument. - Asserting an exact elapsed time against a WireMock stub that uses a random delay. The sample changes on every call, so only bounds are safely assertable. - Assuming a WireMock delay slows the *request*. It does not: the request is fully received and matched first, and only the reply is held back. - Forgetting that a WireMock delay is serialised into the mapping, which means it travels with the file to every other instance that loads it.

  • What does the optional third argument to WireMock's withLogNormalRandomDelay do?
    It is `maxValue`, a ceiling in milliseconds. WireMock resamples any draw above it, which truncates the long right-hand tail of the log-normal distribution. Without it a stub can occasionally produce a delay far larger than the median and stall a suite; with it the shape stays skewed but bounded. WireMock rejects a `maxValue` lower than the median.
  • How would you assert against a WireMock stub that uses withUniformRandomDelay?
    On bounds, never on an exact figure. The sample changes on every call, so assert that the observed duration falls between the lower and upper arguments, or assert the client behaviour the delay is meant to provoke — a progress indicator that stayed on screen, a deadline that fired. An exact-time assertion against a random WireMock delay is a flake waiting to happen.

saying these in an interview costs you the question

  • Says WireMock's uniform and log-normal delays are interchangeable
  • Reads sigma in WireMock's log-normal delay as a maximum
  • Thinks a WireMock delay slows the request, not just the reply
  • Asserts an exact elapsed time against a random WireMock delay
  • Believes a WireMock delay changes which stub matches
open as a page

In WireMock, what does withChunkedDribbleDelay() do to a reply that withFixedDelay() does not?

level: seniorimportance: should knowfreq 56%

basics

~20 s

WireMock's withFixedDelay writes nothing until the pause elapses, then sends the whole reply at once. WireMock's withChunkedDribbleDelay sends the status line and headers immediately and spreads only the body across the stated duration, in the requested number of slices.

open as a page

In Mountebank, which behavior makes a stubbed response slow, and how is it declared?

level: middleimportance: nice to knowfreq 47%

basics

~20 s

Mountebank's wait behavior makes a response slow. It is one of Mountebank's five behaviors and is declared as an entry in the behaviors array on a response, taking a number of milliseconds. Repeat is not a behavior.

open as a page

In WireMock, when should injected delay live in setGlobalFixedDelay() rather than on each stub?

level: principalimportance: nice to knowfreq 44%

basics

~20 s

WireMock's setGlobalFixedDelay writes the delay into the server's settings store. It applies to every stubbed reply and appears in no mapping file. WireMock's per-stub withFixedDelay serialises into the mapping and replaces the global figure rather than adding to it.

open as a page