Aug 23, 2026
Enterprise Service Bus (ESB) Mediation
How it works
The obvious places to look in this chain are the two ends — Source System A Adapter and Destination Adapter A — because they are where real systems touch and where failures announce themselves loudest. That instinct is wrong. The adapters are the narrowest contracts in the flow: each one faces a single known system, and its job is bounded by that system's interface. The genuine complexity sits in the middle three hops, and specifically in the fact that the Protocol Translator, the Content-Based Router, and the Transformation Engine each make decisions about the same message using different views of it. The Protocol Translator changes how the message is carried; the Content-Based Router reads content to decide where it goes; the Transformation Engine rewrites that content on the way out. A message that survives translation intact can still be routed on a field the translation subtly re-typed, and a message routed correctly can still be transformed into something the Destination Adapter accepts without complaint. The ESB Message Bus in front of all of this decouples the source from every downstream decision, which means the source adapter cannot tell you whether any of those decisions went well.
For a QA engineer this reorders the test plan. Endpoint tests confirm connectivity and little else, because a correct handoff at Destination Adapter A only proves the last hop honored its contract, not that the routing decision was the right one or that the transformation preserved meaning. The highest-value coverage is at the seams: what the Protocol Translator hands the Content-Based Router, and what the Router hands the Transformation Engine. Those are the points where an assumption made by one component becomes an input to another that never validated it. Test the routing predicates against post-translation payloads rather than source payloads, since the Router never sees what Source System A actually sent. Assert on transformation output as a semantic result, not as something the Destination Adapter tolerated. And because the ESB Message Bus breaks the synchronous line of sight between source and destination, build observability into those middle hops first — otherwise a defect introduced by the Translator will only ever surface as a complaint about an adapter that did its job correctly.
Caveats — what breaks in practice
The failure mode most likely to blindside a team is the ESB sending an ACK before the message is persisted, because it defeats the one signal everybody trusts as proof of custody. The assumption that makes it surprising is that an acknowledgment is a durability guarantee — that once the bus says "got it," the message survives a crash and will eventually be delivered or, failing that, dead-lettered. It doesn't. On a crash between ACK and write, the message is simply gone, and the producer has already moved on holding a receipt for something that no longer exists. Compare this to the other failure modes: a connection drop mid-message, a timeout on an oversized batch, a poison message halting processing, or a target auth expiry all leave the producer holding an error or a stall — something to see. The ACK-before-persistence case leaves a success.
For testing, the consequence is that no assertion on publish-side return codes can detect it, and neither can dead-letter queue inspection, since the message never reached a state where dead-lettering applies. It has to be tested by killing the broker mid-flight and reconciling counts end to end — produced versus landed at the target — rather than by trusting either side's own view. That same reconciliation is the only thing that also catches the sibling surprises with no error surface: a subscription filter that silently discards a type, a new event type that matches no subscription and is black-holed, and messages dead-lettered without alerting. All four share the property that the system reports health while losing data, which is precisely why they need a test that counts rather than a test that checks status.
How to test this end to end
Picture the Source System A adapter — the order-management mainframe gateway — publishing a single message onto the bus: `ORD-2024-118742`, a `PolicyEndorsementCreated` event carrying `customerName: "MÜLLER-SCHÄFER GmbH"`, `premiumDelta: 412.50`, `effectiveDate: 2024-11-18`, and `sourceSystemId: OMS-A`. The adapter's job at CP1 is narrow: take the event off System A, put it onto the ESB message bus, and hand back an acknowledgement to System A so the mainframe can mark the endorsement as dispatched. Everything downstream — the translator, the rules chain, the content-based router that will decide whether `ORD-2024-118742` fans out to billing, to the document generator, to both, or to neither — depends on this one message actually landing on the bus intact and being visible to a subscription. CP1 is the only place that guarantee gets made.
The ways this breaks are all quiet ones. If the adapter ACKs System A the moment it writes to an in-memory queue rather than after the bus persists, a broker restart loses `ORD-2024-118742` while the mainframe believes it was delivered — no error anywhere, just an endorsement that never bills. If the connection drops mid-publish, you can get a truncated payload or a silent duplicate on retry. If the adapter reads EBCDIC or Latin-1 and publishes without correct encoding, `MÜLLER-SCHÄFER` arrives as `M?LLER-SCH?FER` and corrupts downstream name matching without failing anything. Worst of all, `PolicyEndorsementCreated` may be a newly added event type that no subscription filter matches — the message sits on the bus and is black-holed, never reaching the router at all — or it fails delivery, lands in the dead-letter queue, and nobody is alerted. To test this, publish `ORD-2024-118742` and kill the broker between adapter-ACK and persistence, then confirm System A has *not* marked it dispatched and the message is replayable; sever the connection mid-publish and assert either a complete message or none, never a truncated one, and that a retried `ORD-2024-118742` is deduplicated by message id. Assert byte-for-byte that `MÜLLER-SCHÄFER GmbH` survives the hop. Then, critically, publish `ORD-2024-118742` and assert positively that at least one subscription consumed it — a test that only checks "publish succeeded" will pass on a black-holed event type — and inject a deliberate delivery failure to confirm the dead-letter landing produces an actual alert, not just a queue entry someone has to go looking for.
Once `ORD-2024-118742` is safely on the bus, CP2 picks it up: the protocol translator takes the mainframe-shaped `PolicyEndorsementCreated` event and renders it into the canonical form the router reads, then publishes it onward for the routing decision. Concretely, the translator maps `premiumDelta: 412.50` into a canonical `amount` field, normalizes `effectiveDate: 2024-11-18` into whatever date form the canonical schema demands, carries `customerName: "MÜLLER-SCHÄFER GmbH"` across, and stamps `sourceSystemId: OMS-A` so the router can tell which of the three adapters it came from. The router then reads that translated content and decides `ORD-2024-118742`'s actual destinations — billing, the document generator, both, or neither. That means CP2 is where the message's true path is finally determined; the translator's output is the router's only input, so a field the translator mangles or drops is a routing decision made on bad data.
The failure modes are mostly edge-case shaped. If `premiumDelta` arrives null on a zero-value endorsement, or the event carries an enum value the mapping was never written for, the translator can emit a canonical record with a missing or defaulted `amount` — and the router, keying on content, sends `ORD-2024-118742` to neither destination, silently. If the endorsement arrives as part of a batch, the split can drop or duplicate line items, so `ORD-2024-118742` gets routed twice or not at all; oversized batches can time out mid-translation; and a single poison message ahead of `ORD-2024-118742` can halt processing entirely so it never reaches the router. Even after a clean translation, the router's subscription filters may not match the newly added `PolicyEndorsementCreated` type at all, black-holing it, or delivery to billing can fail and dead-letter without anyone being alerted. Test it by feeding `ORD-2024-118742` through with `premiumDelta` null, then with an unrecognized enum, and asserting the translator either produces a valid canonical record or fails loudly — never a silently defaulted one; assert the translated `MÜLLER-SCHÄFER GmbH` and `2024-11-18` match expected values exactly. Send `ORD-2024-118742` inside a multi-line batch and assert exactly-once presence of its line items downstream, then oversize the batch to confirm timeout behavior is visible. Put a poison message immediately before `ORD-2024-118742` and confirm it still gets processed. Finally, assert positively that the router *chose destinations* for `ORD-2024-118742` — enumerate them, don't just check translation succeeded — and force a delivery failure to billing to confirm the dead-letter produces an alert.
Downstream of the routing decision, `ORD-2024-118742` reaches CP3: the transformation engine takes the canonical record the translator produced — `amount: 412.50`, the normalized `effectiveDate`, `customerName: "MÜLLER-SCHÄFER GmbH"`, `sourceSystemId: OMS-A` — and shapes it into the billing-specific payload that Destination Adapter A actually posts. That means a second mapping pass on the same fields: canonical `amount` becoming whatever the billing target expects (say `chargeAmount: "412.50"` as a string with two decimals), the endorsement subtype driving which billing field set gets populated, and the customer name surviving its umlaut and hyphen through one more serialization hop before Adapter A authenticates against the billing API and delivers. Adapter A is the last thing that touches `ORD-2024-118742` before it leaves the bus, so whatever it emits is what billing believes happened.
The edge cases from CP2 repeat here in a nastier place. A subtype-specific mapping gap — an endorsement flavor the billing payload template never covered — can produce a structurally valid call that posts the wrong field set; a null or unexpected enum surviving translation can be defaulted here instead of rejected; a batch containing `ORD-2024-118742` can split badly at the adapter and post its line items twice, and since this hop is the actual write, a duplicate is a duplicate charge, not just a duplicate log line. Adapter A's session against the billing API can expire mid-run, and if the retry logic doesn't distinguish auth failure from transient failure it will hammer the target into a retry storm; a poison message ahead of `ORD-2024-118742` can stall the adapter queue; and if a second message updates the same billing record concurrently, the two writes can race. Test it by pushing `ORD-2024-118742` with each endorsement subtype and asserting the billing payload's field set matches expected per subtype, not just that a 200 came back; assert `chargeAmount` is exactly `412.50` and `MÜLLER-SCHÄFER GmbH` arrives byte-identical at billing. Send it inside a multi-line batch and assert exactly one billing charge exists for `ORD-2024-118742` afterward; expire Adapter A's session mid-delivery and assert it re-authenticates once rather than retrying in a loop; make the billing API fail persistently and assert retries back off and stop; put a poison message ahead of it and confirm it still posts; and fire two concurrent updates against `ORD-2024-118742`'s billing record and assert the final state is one of the two writes, not a merged or lost one.
CP1 — Capture & Buffer
Source System A Adapter → ESB Message Bus
CP2 — Transform & Publish
Protocol Translator → Content-Based Router
CP3 — Event Routing & Execution
Transformation Engine → Destination Adapter A
Want this level of breakdown for your own system? Match your architecture in a few questions — no confidential upload required.