skip to content

How would you govern one WireMock proxyAllTo( canary mapping against the live meter API across many suites?

level: principalimportance: should knowfreq 44%

answer

  1. one mapping, left on purpose
  2. underneath everything the set already covers
  3. a live outbound call inside a test run
  4. priority above DEFAULT_PRIORITY, so recorded stubs win
  5. metadata tag, so removal is one call

basics

~20 s

Keep one proxy mapping pointed at the live meter API, sitting below every recorded stub so it only fires on an uncovered call. Run it on a scheduled job rather than every suite, and make it removable by metadata.

solid answer

~50 s

A canary is one WireMock mapping deliberately left proxying to the real district heating meter API after every other proxy leg has been stripped from the refreshed set. Give it WireMock's `proxyAllTo("https://meters.stadtwaerme.example")` and `atPriority(` with a number above `DEFAULT_PRIORITY`, which is `5`, so every recorded stub matches first and the canary only ever answers a call the set does not cover. The governance is the hard part, not the mapping. Decide where it runs — one scheduled job, never every pull request — because it puts a live network call, a credential and real upstream load inside a test run. Restrict egress to that one host, tag the mapping with `metadata` so WireMock's `POST /__admin/mappings/remove-by-metadata` can pull it out in a single call, and name an owner for whatever it reports. In Mountebank the same idea is a proxy stub left in the imposter rather than stripped by `--removeProxies`.

go deeper

for a junior

Know what the construct is: one WireMock mapping that proxies to the real service, left in a set where everything else answers from a recording. Know that it is meant to sit below the recorded stubs.

for a middle

Explain the precedence mechanics that make it safe — WireMock matches the lower priority number first and DEFAULT_PRIORITY is 5 — and why a canary above that number only ever answers calls the set does not cover.

for a senior

Show the operational side: where it runs, what egress it needs, how a firing is surfaced rather than swallowed, and how you remove it cleanly from a set that other environments also use.

for a principal

Own the tradeoff. Argue whether the signal justifies a live outbound dependency inside test infrastructure at all, who reads it, what stops it widening into a catch-all, and under what condition it is retired.

## What a canary proxy mapping is After a refresh, the normal end state is a closed world: every mapping in the set answers from a recorded response, and no proxy leg survives. A **canary** is a deliberate exception — exactly one WireMock mapping, `proxyAllTo("https://meters.stadtwaerme.example")`, left in the set on purpose. Because it sits at a lower precedence than the recorded stubs, it never answers a call the set already covers. It answers only the calls the set does not cover, and in doing so it reaches the real district heating meter API. The mechanism is small. The governance is not, because that one mapping quietly converts a hermetic test set into something with a live outbound dependency. ## What it buys, and what it costs - **Buys:** an uncovered call produces a real response instead of a match failure, so the run tells you what the client now asks for and what the upstream actually answers. - **Buys:** it is one mapping, in the same set, in the same repository — nothing extra to deploy or maintain. - **Costs:** a network call inside a test run, with the flakiness, latency and DNS dependence that implies. - **Costs:** a credential in a place that previously needed none, because the real meter API will want authentication. - **Costs:** load on a service whose owners never agreed to it, multiplied by however many suites run. - **Costs:** the temptation to widen it. A canary that starts answering ordinary traffic has become a catch-all, and a catch-all makes everything pass. ## The decisions a lead actually owns 1. **Where it runs.** One scheduled job on one instance — not every developer's machine, and not every pull request. The value of the signal does not scale with how often you collect it; the cost does. 2. **Its precedence.** In WireMock, `DEFAULT_PRIORITY` is `5` and a lower number is matched first, so a canary at `atPriority(` with a higher number sits underneath the whole recorded set by construction. Getting this backwards turns the canary into the first thing every request hits. 3. **Its blast radius.** Restrict egress from that instance to the one upstream host. A proxy mapping is an outbound path, and an unrestricted one is an outbound path to anywhere the URL happens to point. 4. **Its removability.** Tag the mapping with `metadata` when you add it, so WireMock's `POST /__admin/mappings/remove-by-metadata` strips exactly it and nothing else. A canary you cannot cleanly remove is a canary that will still be there when someone runs the set in an environment with no route to the upstream. 5. **Its owner.** Someone must read what it produces, and the finding must land somewhere with a name on it. An unowned signal decays into a job that is red for a fortnight and then muted. ## Keeping it from becoming a catch-all The failure is gradual and always looks reasonable at each step. The canary catches an uncovered call, somebody notices the suite is more robust with it enabled, it gets turned on in more places, and eventually a request that should have failed loudly against a missing stub is quietly answered by the real service. At that point the set no longer tells you what it covers, and the suite passes for reasons nobody chose. Guards that hold up in practice: - Keep it to **one** mapping, and treat a second as a design smell rather than an extension. - Keep it out of the default configuration: the canary belongs to a named job, added at start-up and removed at the end. - Make its firing **visible**. A canary that answers a request has found something; that should be an outcome the job reports, not a silent success. - Never let it serve the paths the recorded set already covers. If it does, the precedence is wrong. ## Where this sits next to the refresh itself A refresh and a canary answer different questions with the same underlying transport. The refresh regenerates the whole set and hands you a diff to review deliberately. The canary is standing surveillance on one narrow thing — the calls your set does not answer — and it is cheap precisely because it does almost nothing most of the time. So the sensible arrangement is usually both, at different cadences: a scheduled refresh whose output a person reads, and a canary that only speaks when the client asks for something the set has never seen. If you can only have one, have the refresh: it is the one that produces reviewable evidence, and it does not leave a live outbound path in a test set that a hundred other runs will inherit. Finally, write down the exit. Under what circumstance does the canary come out — the API is being retired, egress policy tightens, the job stops being read? Deciding that at the point you add it is much cheaper than deciding it during an incident where a test set turns out to have been calling a production service for a year.

  • The canary fires on a path the client has always called. What does that tell you?
    Not that the upstream changed — that your recorded set never covered that path, or that the replay which produced it never exercised it. The first action is to look at whether the committed set has a mapping for that request at all. A canary firing is a coverage signal before it is anything else.
  • Why not simply let unmatched requests fail loudly instead of running a canary?
    Failing loudly is the right default for ordinary suites, and most runs should keep it. The canary exists on one scheduled job precisely because a failure tells you only that nothing matched, while a proxied call also tells you what the real meter API answers — which is the part you need in order to decide what to record next.

saying these in an interview costs you the question

  • Puts the canary at a priority that shadows the recorded stubs
  • Enables it in every suite instead of one scheduled job
  • Lets it widen into a catch-all so nothing ever fails
  • Ignores that it adds egress, a credential and upstream load
  • Leaves no way to remove the mapping cleanly
  • Reads a firing canary as proof the upstream changed