Skip to content

feat(repo): add the mock gateway server for client tests - #3

Merged
MobileMage merged 14 commits into
mainfrom
feat/mock-server
Oct 3, 2026
Merged

MobileMage merged 14 commits into
mainfrom
feat/mock-server

Conversation

@MobileMage

@MobileMage MobileMage commented Oct 3, 2026 •

Copy link
Copy Markdown
Collaborator

packages/mock-server is a private package that stands in for the NIPOST
gateway in tests. It reads the synthetic fixtures, the mock keys and the
contract scenarios from spec 0.2.0, answers the six gateway endpoints with their keys, levels,
rate-limit headers and errors, and plays each scenario by its
X-Scenario-Id header. It uses Node's own http module and has no runtime
dependency. The client tests start it in the same process, and other
SDKs run it with node or from its container image.

The core moves to spec 0.2.0. Its grammar and vectors did not change,
so only SPEC_VERSION moves. CI builds the image and calls it. A separate
workflow publishes it, and it runs only on a tag or by hand. A test
checks each body that the server sends against the OpenAPI file.

This change is larger than the 400 lines that GIT-5 suggests, because
it adds a package. Most of it is tests.

Signed-off-by: MobileMage aidelojejoshua@gmail.com

Spec 0.2.0 adds the client contract and the fixtures that the mock
server reads. Its grammar and vectors are the same as before, so the
core passes them unchanged and only its SPEC_VERSION moves. CONTEXT.md
takes the new terms of the spec's glossary.

Signed-off-by: MobileMage <aidelojejoshua@gmail.com>
The mock server answers from the spec's files, so a new observation
changes data and no code. It reads them once at start and stops with the
name of a file that has the wrong shape, so a broken spec change cannot
serve a wrong body in silence. The package runs on Node, so the lint
config lets it import Node modules, and a test pins that exception.

Signed-off-by: MobileMage <aidelojejoshua@gmail.com>
Client tests and the docs playground need answers in the gateway's
shapes, with its keys, levels, errors and rate-limit headers. Each
answer comes from a fixture, and a test checks each body that the code
builds or changes against the spec's OpenAPI file. The rules follow the
calls of 2 Oct 2026 where the docs disagree: a level above the key's
gets 403, and an empty autocomplete query gets no answer.

Signed-off-by: MobileMage <aidelojejoshua@gmail.com>
A spec file that is not JSON now fails with its path and the parser
message. A response must have exactly one kind field, and a fixture must
have a body, so the server cannot send the text "undefined". A repeated
scenario id or key fails with both places, and a scenario id must equal
its file name. Status, delay, level and rate values must be whole numbers
in range. Messages name the response or key entry. Folders are read in
sorted order, so the map order does not depend on the file system.

Signed-off-by: MobileMage <aidelojejoshua@gmail.com>
The spec now plays 70 scenarios, adds the lookup-no-data scenario and
changes the confidence of the reverse unit fixture to low. The search
test expected the old value, so it follows the fixture. The truth check
of the spec also plays each scenario as the client contract describes.

Signed-off-by: MobileMage <aidelojejoshua@gmail.com>
A client test sends X-Scenario-Id and X-Scenario-Run, and gets the next
response of that run. A run keeps its own place, so two test runs never
share a response. The server holds a connection open for a hang and
closes it for a drop, as the timeout and network scenarios need, and it
closes every open connection when a test ends. The command starts it on
Node with no build.

Signed-off-by: MobileMage <aidelojejoshua@gmail.com>
A rate-limited key now shows no requests left, as the 429 response
says. Reverse no longer returns a unit that lies outside the radius.
Numbers in a query read as decimal text by value, so a level of 2.0
works and 0x9 does not. The OpenAPI test now compares the headers and
the error code of each response with the file, and new tests pin the
order of the key, path, origin, scope, level and credit checks.

Signed-off-by: MobileMage <aidelojejoshua@gmail.com>
A delayed response kept a timer alive after the client left or the
server closed, so a process with a long delay did not exit for seconds.
The delay now ends when the client closes the connection and when the
server closes. A second close call now returns the first result, so two
signals no longer give an unhandled rejection. A failure inside the
error reply now closes the connection instead of leaving a rejection.
The URL of an IPv6 host has brackets, and the host :: gives localhost.

Signed-off-by: MobileMage <aidelojejoshua@gmail.com>
The PHP client and the docs need the mock server without a TypeScript
setup, so it ships as an image that runs the source on Node. CI builds
the image and looks up the synthetic unit on each pull request, so a
change cannot break the image unseen. A separate workflow publishes it
with a provenance attestation, and only a release tag or a person starts
it, because a pushed image is public.

Signed-off-by: MobileMage <aidelojejoshua@gmail.com>
Docker accepts the first connection on the published port before Node
listens, and then resets it. The option --retry-connrefused does not
retry a reset, so the probe failed with exit code 56. The option
--retry-all-errors retries it.

Signed-off-by: MobileMage <aidelojejoshua@gmail.com>
An empty HOST gave an empty string, and Node then bound every
interface. The command now treats an empty HOST as unset, as it does
for PORT. Two tests pin the loopback default, and the README says that
the server trusts a checked spec folder.

Signed-off-by: MobileMage <aidelojejoshua@gmail.com>
The new spec commit makes the deadline scenario less sensitive to a slow
runner, checks the postcode of each suggestion, and adds evidence marks
and notes to the contract.

Signed-off-by: MobileMage <aidelojejoshua@gmail.com>
@MobileMage
MobileMage marked this pull request as ready for review October 3, 2026 01:39
The spec branch is merged. Its squash commit on main, tagged v0.2.0,
holds the same files as the commit that the submodule named before.

Signed-off-by: MobileMage <aidelojejoshua@gmail.com>
CI scans every branch of the repo, and the client branch holds a
made-up key in a test that checks that no error message holds the
real one. The same ignore entry that the client branch carries lets
this branch pass the scan too.

Signed-off-by: MobileMage <aidelojejoshua@gmail.com>
@MobileMage
MobileMage merged commit c94adef into main Oct 3, 2026
9 checks passed
@MobileMage
MobileMage deleted the feat/mock-server branch October 3, 2026 11:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant