External-system provider simulators
Standalone doubles for the business systems an application reads data out of, so a data pipeline or a provider operation can be exercised against a real socket without a real business system.
- What it is
- Tool — something you run.
- What it does
- Protocol-faithful doubles for the external systems an application reads from — a business suite's remote-procedure envelope, two versions of a standard query protocol, and a route-driven generic REST face.
- Where it stops
- No scenario in the end-to-end registry drives it, and nothing outside the package references it.
provider-simulators stands in for the external target systems an application reads from. Four
faces are implemented: a business-suite remote-procedure endpoint, an OData version-four endpoint, a
version-two endpoint in the flavour a large enterprise suite actually publishes, and a route-driven
generic HTTP double for provider operations. Each is a standalone server started from one
orchestrator, with no framework imports.
The problem it solves
Reading data out of somebody else’s system is mostly a question of dialect. The envelope differs, the paging property differs, the query language differs, and a wrong answer looks like an empty result rather than an error. Testing that against the real system means holding an account, a network path and a data set, none of which belongs in a test lane; testing it against a stub written from the same assumptions as the reader proves only that the assumptions are self-consistent.
The version-two case is the clearest illustration. The engine’s OData reader expects a value array and a next link, which is version four. A widely used enterprise business-partner service publishes version two, whose envelope wraps everything in a different property, names its results differently and carries a different next link and count. A version-four reader pointed at it finds no array and fails on the first page. Only a double that is faithful to the published version-two format shows that, which is why the two are separate doubles rather than one with a flag.
What it does
Protocol-faithful doubles for the external systems an application reads from — a business suite’s remote-procedure envelope, two versions of a standard query protocol, and a route-driven generic REST face.
Each face is faithful to a PUBLISHED protocol rather than to the framework, and none of them imports anything from it. That is the load-bearing property: a double derived from the reader would agree with the reader by construction, so a framework defect could never surface.
The business-suite face implements the envelope, the authenticate call including its rejection answer, and the read family with the domain query language, its prefix-notation combinators and its operator set. The newer query face parses the filter grammar subset a query compiler realistically emits, by recursive descent, and answers the metadata document as well as the count. The older face implements the other envelope, the other paging and the other count.
The generic double is deliberately a different shape. A provider operation has no dialect — only a method, a path template, parameters and a body encoding — so this face is route-driven: a test declares routes the way a vendor’s API reads on paper, and the double records what actually ARRIVED, including query parameters, headers and the raw body with its content type. That record is the assertion surface, and it is what turns “the parameter went to the query rather than the body” into a checkable fact rather than an inference from a successful status.
Two faces carry a knob that forces one throttled answer after a chosen number of calls, so transport-retry machinery has a live counterpart rather than a mocked one.
Limits
No scenario in the end-to-end registry drives it, and nothing outside the package references it. Each face carries its own unit tests and has been exercised directly, and the claim that an application’s data pipeline works end to end against one of them has not been made by a lane.
The doubles are faithful to a scoped subset of each protocol, chosen as what a query compiler realistically emits. Constructs outside that subset are not implemented, and the source says so at each face.
They carry no business logic and no persistence. A fixture is supplied at start-up and read back; nothing writes.